Skip to content

Instantly share code, notes, and snippets.

@Krasipeace
Last active January 4, 2024 17:28
Show Gist options
  • Save Krasipeace/ac8efd9eebfc8456a20dad45821e7cee to your computer and use it in GitHub Desktop.
Save Krasipeace/ac8efd9eebfc8456a20dad45821e7cee to your computer and use it in GitHub Desktop.
Implementation of Trie - Prefix Tree
using System.Text;
public class Trie
{
private TrieNode root;
public Trie()
{
this.root = new TrieNode();
}
/// <summary>
/// Insert a word into the trie.
/// </summary>
/// <param name="word"></param>
public void Insert(string word)
{
var node = root;
foreach (var @char in word)
{
if (GetChildNode(node, @char) == null)
{
node.Children[@char - 'a'] = new TrieNode();
}
node = GetChildNode(node, @char);
}
node.IsEnd = true;
}
/// <summary>
/// Prefix search
/// </summary>
/// <param name="word"></param>
/// return true if the word is in the trie.
public bool Search(string word)
{
var node = root;
foreach (var @char in word)
{
if (GetChildNode(node, @char) == null)
{
return false;
}
node = GetChildNode(node, @char);
}
return node.IsEnd;
}
/// <summary>
/// Prefix search `startsWith`
/// </summary>
/// <param name="prefix"></param>
/// return true if there is any word in the trie that starts with the given prefix.
public bool StartsWith(string prefix)
{
var node = root;
foreach (var @char in prefix)
{
if (GetChildNode(node, @char) == null)
{
return false;
}
node = GetChildNode(node, @char);
}
return true;
}
/// <summary>
/// Delete a word from the trie.
/// </summary>
/// <param name="word"></param>
public void Delete(string word)
{
Delete(root, word, 0);
}
private bool Delete(TrieNode node, string word, int index)
{
if (index == word.Length)
{
if (!node.IsEnd)
{
return false;
}
node.IsEnd = false;
return node.Children.All(c => c == null);
}
char ch = word[index];
TrieNode nextNode = GetChildNode(node, ch);
if (nextNode == null)
{
return false;
}
bool canDeleteCurrentNode = Delete(nextNode, word, index + 1);
if (canDeleteCurrentNode)
{
node.Children[ch - 'a'] = null!;
return node.Children.All(c => c == null);
}
return false;
}
/// <summary>
/// Finds the longest common prefix among an array of strings.
/// </summary>
/// <param name="words"></param>
/// <returns></returns>
public string LongestCommonPrefix(string[] words)
{
TrieNode node = root;
StringBuilder sb = new ();
foreach (var word in words)
{
Insert(word);
}
while (node.Count == 1)
{
var child = node.Children.First(c => c != null);
sb.Append(child);
node = child;
}
return sb.ToString();
}
private class TrieNode
{
public TrieNode()
{
Children = new TrieNode[26];
}
public TrieNode[] Children { get; set; }
public bool IsEnd { get; set; }
public bool IsStart { get; set; }
/// <summary>
/// Count of children
/// </summary>
public int Count => Children.Count(c => c != null);
/// <summary>
/// Clear all children
/// </summary>
public void ClearChildren()
{
Children = new TrieNode[26];
}
/// <summary>
/// To string
/// </summary>
/// <returns></returns>
public override string ToString()
=> $"IsEnd: {IsEnd}, Count: {Count}";
/// <summary>
/// Get all children of the node To List
/// </summary>
/// <returns></returns>
public ICollection<TrieNode> GetChildren()
=> Children.Where(c => c != null).ToList();
/// <summary>
/// Get all children of the node To Array
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="func"></param>
/// <returns></returns>
public T[] ToArray<T>(Func<TrieNode, T> func)
=> Children.Where(c => c != null).Select(func).ToArray();
}
/// <summary>
/// Get child node of the node
/// </summary>
/// <param name="node"></param>
/// <param name="c"></param>
/// <returns></returns>
private static TrieNode GetChildNode(TrieNode node, char c)
=> node.Children[c - 'a'];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment