How to create a trie in c#

Viewed 42801

Does anyone know where I can find an example of how to construct a trie in C#? I'm trying to take a dictionary/list of words and create a trie with it.

9 Answers

To get instant suggestions from trie data structure, after loading from strings use the below. (faster retrieval)

public class Trie
    {
        public struct Letter
        {
            public const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
            public static implicit operator Letter(char c)
            {
                c = c.ToString().ToUpper().ToCharArray().First();

                return new Letter() { Index = Chars.IndexOf(c) };
            }
            public int Index;
            public char ToChar()
            {
                return Chars[Index];
            }
            public override string ToString()
            {
                return Chars[Index].ToString();
            }
        }

        public class Node
        {
            public string Word;
            public bool IsTerminal { get { return Word != null; } }
            public Dictionary<Letter, Node> Edges = new Dictionary<Letter, Node>();


        }

        public Node Root = new Node();

        public Trie(string[] words)
        {
            for (int w = 0; w < words.Length; w++)
            {
                var word = words[w];
                var node = Root;
                for (int len = 1; len <= word.Length; len++)
                {
                    var letter = word[len - 1];
                    Node next;
                    if (!node.Edges.TryGetValue(letter, out next))
                    {
                        next = new Node();
                        if (len == word.Length)
                        {
                            next.Word = word;
                        }
                        node.Edges.Add(letter, next);
                    }
                    node = next;
                }
            }
        }


        public List<string> GetSuggestions(string word, int max)
        {
            List<string> outPut = new List<string>();

            var node = Root;
            int i = 0;
            foreach (var l in word)
            {
                Node cNode;
                if (node.Edges.TryGetValue(l, out cNode))
                {
                    node = cNode;
                }
                else
                {
                    if (i == word.Length - 1)
                        return outPut;
                }
                i++;
            }

            GetChildWords(node, ref outPut, max);

            return outPut;
        }


        public void GetChildWords(Node n, ref List<string> outWords, int Max)
        {
            if (n.IsTerminal && outWords.Count < Max)
                outWords.Add(n.Word);

            foreach (var item in n.Edges)
            {
                GetChildWords(item.Value, ref outWords, Max);
            }
        }

    }

Simple and beautiful:

class Trie
    {
        private readonly string _key;
        private string _value;
        private List<Trie> _path;
        private List<Trie> _children;
        public Trie(string key = "root", string value = "root_val")
        {
            this._key = key;
            this._value = value;
            this._path = this._children = new List<Trie>();
        }
        public void Initialize(Dictionary<string, string> nodes, int keyLength = 1)
        {
            foreach (var node in nodes)
            {
                this.Add(node, keyLength);
            }
        }
        public void Add(KeyValuePair<string, string> node, int keyLength = 1)
        {
            if (this._children.Count == 0 || !this._children.Any(ch => (node.Key.StartsWith(ch._key)) || (ch._key == node.Key)))
            {
                //For any item that could be a child of newly added item
                Predicate<Trie> possibleChildren = (Trie ch) => { return ch._key.StartsWith(node.Key); };

                var newChild = new Trie(node.Key, node.Value);
                newChild._children.AddRange(this._children.FindAll(possibleChildren));

                this._children.RemoveAll(possibleChildren);
                this._children.Add(newChild);
            }
            else
            {
                this._children.First(ch => (ch._key == node.Key) || (node.Key.Substring(0, keyLength) == ch._key)).Add(node, keyLength + 1);
            }
        }
        public void Delete(string key, bool recursively = true)
        {
            var newChildren = new List<Trie>(this._children);
            foreach (var child in this._children)
            {
                if (child._key == key)
                {
                    if (!recursively)
                    {
                        newChildren.AddRange(child._children);
                    }
                    newChildren.Remove(child);
                }
                else
                {
                    child.Delete(key, recursively);
                }
            }

            this._children = newChildren;
        }
        public List<Trie> Find(string key, int keyLength = 1)
        {
            this._path = new List<Trie>();

            if (key.Length >= keyLength - 1 && this._key == key.Substring(0, keyLength - 1))
            {
                this._path.Add(this);
            }
            foreach (var child in this._children)
            {
                var childPath = child.Find(key, keyLength + 1);
                this._path.AddRange(childPath);
            }

            return this._path;
        }
    }

var items = new Dictionary<string, string>
{
    { "a", "First level item" },
    { "b", "First level item"},
    { "ad", "Second level item"},
    { "bv", "Second level item"},
    { "adf", "Third level item"},
    { "adg", "Third level item"},
    { "bvc", "Third level item"},
    { "bvr", "Third level item"}
};

var myTree = new Trie();
myTree.Initialize(items);
Related