trie树的数据结构

A Trie data structure acts as a container for a dynamic array. In this article, we shall look at how we can implement a Trie in C/C++.

Trie数据结构充当动态数组的容器。 在本文中,我们将研究如何在C / C ++中实现Trie。

This is based on the tree data structure but does not necessarily store keys. Here, each node only has a value, which is defined based on the position.

这基于树数据结构,但不一定存储键。 在此,每个节点仅具有一个基于位置定义的值。

Trie Data Structure – Wikipedia
Trie数据结构–维基百科

So, the value of each node denotes the prefix, because it is the point from the root node after a series of matches.

因此,每个节点的值表示前缀,因为它是一系列匹配后来自根节点的点。

We call such matches as prefix matches. Therefore, we can use Tries to store words of a dictionary!

我们称这种匹配为前缀匹配 。 因此,我们可以使用Tries来存储字典中的单词!

For example, in the above figure, the root node is empty, so every string matches the root node. Node 7 matches a prefix string of to, while node 3 matches a prefix string of tea.

例如,在上图中,根节点为空,因此每个字符串都与根节点匹配。 节点7匹配到to的前缀字符串,而节点3匹配tea的前缀字符串。

Here, the keys are only stored in the leaf node positions, since prefix matching stops at any leaf node. So any non-leaf node does NOT store the whole string, but only the prefix match character.

此处,关键字仅存储在叶节点位置,因为前缀匹配在任何叶节点处停止。 因此,任何非叶子节点都不会存储整个字符串,而只会存储前缀匹配字符。

Tries are called prefix trees for all these reasons. Now let’s understand how we can implement this data structure, from a programmer’s point of view.

由于所有这些原因,尝试被称为前缀树 。 现在让我们从程序员的角度了解如何实现这种数据结构。



在C / C ++中实现Trie数据结构 (Implementing a Trie Data Structure in C/C++)

Let’s first write down the Trie structure. A Trie Node has notably two components:

让我们首先写下Trie结构。 Trie节点主要包括两个组件:

  • It’s children是孩子
  • A marker to indicate a leaf node.指示叶节点的标记。

But, since we’ll be printing the Trie too, it will be easier if we can store one more attribute in the data part.

但是,由于我们也将打印Trie,因此如果我们可以在数据部分中存储一个以上的属性,则将更加容易。

So let’s define the TrieNode structure. Here, since I will be storing only the lower case alphabets, I will implement this as a 26-ary-tree. So, each node will have pointers to 26 children.

因此,让我们定义TrieNode结构。 在这里,由于我将仅存储小写字母,因此我将其实现为26进制树。 因此,每个节点将具有指向26个子节点的指针。


// The number of children for each node
// We will construct a N-ary tree and make it
// a Trie
// Since we have 26 english letters, we need
// 26 children per node
#define N 26typedef struct TrieNode TrieNode;struct TrieNode {// The Trie Node Structure// Each node has N children, starting from the root// and a flag to check if it's a leaf nodechar data; // Storing for printing purposes onlyTrieNode* children[N];int is_leaf;
};

Now that we’ve defined our structure, let’s write functions to initialize a TrieNode in memory, and also to free it’s pointer.

现在,我们已经定义了结构,让我们编写函数以初始化内存中的TrieNode并释放其指针。


TrieNode* make_trienode(char data) {// Allocate memory for a TrieNodeTrieNode* node = (TrieNode*) calloc (1, sizeof(TrieNode));for (int i=0; i<N; i++)node->children[i] = NULL;node->is_leaf = 0;node->data = data;return node;
}void free_trienode(TrieNode* node) {// Free the trienode sequencefor(int i=0; i<N; i++) {if (node->children[i] != NULL) {free_trienode(node->children[i]);}else {continue;}}free(node);
}

在Trie上插入一个单词 (Inserting a word onto the Trie)

We’ll now write the insert_trie() function, that takes a pointer to the root node (topmost node) and inserts a word to the Trie.

现在,我们将编写insert_trie()函数,该函数需要一个指向根节点(最高节点)的指针,并向Trie中插入一个单词。

The insertion procedure is simple. It iterates through the word character by character and evaluates the relative position.

插入过程很简单。 它逐个字符地遍历单词并评估相对位置。

For example, a character of b will have a position of 1, so will be the second child.

例如,字符b的位置为1,因此第二个孩子也是。


for (int i=0; word[i] != '\0'; i++) {// Get the relative position in the alphabet listint idx = (int) word[i] - 'a';if (temp->children[idx] == NULL) {// If the corresponding child doesn't exist,// simply create that child!temp->children[idx] = make_trienode(word[i]);}else {// Do nothing. The node already exists}

We will match the prefix character by character, and simply initialize a node if it doesn’t exist.

我们将逐字符匹配前缀,并简单地初始化节点(如果不存在)。

Otherwise, we simply keep moving down the chain, until we have matched all the characters.

否则,我们只是继续沿着链条向下移动,直到匹配所有字符为止。


temp = temp->children[idx];

Finally, we will have inserted all unmatched characters, and we will return back the updated Trie.

最后,我们将插入所有不匹配的字符,然后返回更新的Trie。


TrieNode* insert_trie(TrieNode* root, char* word) {// Inserts the word onto the Trie// ASSUMPTION: The word only has lower case charactersTrieNode* temp = root;for (int i=0; word[i] != '\0'; i++) {// Get the relative position in the alphabet listint idx = (int) word[i] - 'a';if (temp->children[idx] == NULL) {// If the corresponding child doesn't exist,// simply create that child!temp->children[idx] = make_trienode(word[i]);}else {// Do nothing. The node already exists}// Go down a level, to the child referenced by idx// since we have a prefix matchtemp = temp->children[idx];}// At the end of the word, mark this node as the leaf nodetemp->is_leaf = 1;return root;
}

在Trie中搜索单词 (Search for a word in the Trie)

Now that we’ve implemented insertion onto a Trie, let’s look at searching for a given pattern.

现在,我们已经在Trie中实现了插入,让我们看一下搜索给定的模式。

We’ll try to match the string character by character, using the same prefix matching strategy as above.

我们将尝试使用与上述相同的前缀匹配策略来逐字符匹配字符串。

If we have reached the end of the chain and haven’t yet found a match, that means that the string does not exist, as a complete prefix match is not done.

如果我们已到达链的末尾但尚未找到匹配项,则表示该字符串不存在,因为尚未完成完整的前缀匹配。

For this to return correctly, our pattern must exactly match, and after we finish matching, we must reach a leaf node.

为了使此方法正确返回,我们的模式必须完全匹配,并且在完成匹配之后,我们必须到达叶节点。


int search_trie(TrieNode* root, char* word)
{// Searches for word in the TrieTrieNode* temp = root;for(int i=0; word[i]!='\0'; i++){int position = word[i] - 'a';if (temp->children[position] == NULL)return 0;temp = temp->children[position];}if (temp != NULL && temp->is_leaf == 1)return 1;return 0;
}

Okay, so we’ve completed the insert and search procedures.

好的,我们已经完成了insertsearch过程。

To test it, we’ll first write a print_tree() function, that prints the data of every node.

为了测试它,我们将首先编写一个print_tree()函数,该函数将打印每个节点的数据。


void print_trie(TrieNode* root) {// Prints the nodes of the trieif (!root)return;TrieNode* temp = root;printf("%c -> ", temp->data);for (int i=0; i<N; i++) {print_trie(temp->children[i]); }
}

Now that we have done that, let’s just run the complete program until now, to check that it’s working correctly.

现在我们已经完成了,现在让我们运行完整的程序,以检查其是否正常运行。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>// The number of children for each node
// We will construct a N-ary tree and make it
// a Trie
// Since we have 26 english letters, we need
// 26 children per node
#define N 26typedef struct TrieNode TrieNode;struct TrieNode {// The Trie Node Structure// Each node has N children, starting from the root// and a flag to check if it's a leaf nodechar data; // Storing for printing purposes onlyTrieNode* children[N];int is_leaf;
};TrieNode* make_trienode(char data) {// Allocate memory for a TrieNodeTrieNode* node = (TrieNode*) calloc (1, sizeof(TrieNode));for (int i=0; i<N; i++)node->children[i] = NULL;node->is_leaf = 0;node->data = data;return node;
}void free_trienode(TrieNode* node) {// Free the trienode sequencefor(int i=0; i<N; i++) {if (node->children[i] != NULL) {free_trienode(node->children[i]);}else {continue;}}free(node);
}TrieNode* insert_trie(TrieNode* root, char* word) {// Inserts the word onto the Trie// ASSUMPTION: The word only has lower case charactersTrieNode* temp = root;for (int i=0; word[i] != '\0'; i++) {// Get the relative position in the alphabet listint idx = (int) word[i] - 'a';if (temp->children[idx] == NULL) {// If the corresponding child doesn't exist,// simply create that child!temp->children[idx] = make_trienode(word[i]);}else {// Do nothing. The node already exists}// Go down a level, to the child referenced by idx// since we have a prefix matchtemp = temp->children[idx];}// At the end of the word, mark this node as the leaf nodetemp->is_leaf = 1;return root;
}int search_trie(TrieNode* root, char* word)
{// Searches for word in the TrieTrieNode* temp = root;for(int i=0; word[i]!='\0'; i++){int position = word[i] - 'a';if (temp->children[position] == NULL)return 0;temp = temp->children[position];}if (temp != NULL && temp->is_leaf == 1)return 1;return 0;
}void print_trie(TrieNode* root) {// Prints the nodes of the trieif (!root)return;TrieNode* temp = root;printf("%c -> ", temp->data);for (int i=0; i<N; i++) {print_trie(temp->children[i]); }
}void print_search(TrieNode* root, char* word) {printf("Searching for %s: ", word);if (search_trie(root, word) == 0)printf("Not Found\n");elseprintf("Found!\n");
}int main() {// Driver program for the Trie Data Structure OperationsTrieNode* root = make_trienode('\0');root = insert_trie(root, "hello");root = insert_trie(root, "hi");root = insert_trie(root, "teabag");root = insert_trie(root, "teacan");print_search(root, "tea");print_search(root, "teabag");print_search(root, "teacan");print_search(root, "hi");print_search(root, "hey");print_search(root, "hello");print_trie(root);free_trienode(root);return 0;
}

After compiling with your gcc compiler, you’ll get the following output.

使用gcc编译器进行编译后,您将获得以下输出。


Searching for tea: Not Found
Searching for teabag: Found!
Searching for teacan: Found!
Searching for hi: Found!
Searching for hey: Not Found
Searching for hello: Found!-> h -> e -> l -> l -> o -> i -> t -> e -> a -> b -> a -> g -> c -> a -> n ->

While it may be obvious how it’s being printed, the clue is to look at the print_tree() method. Since that prints the current node, and then all of its children, the order does indicate that.

虽然很明显是如何打印的,但线索是看一下print_tree()方法。 由于该命令将打印当前节点,然后打印其所有子节点,因此该顺序的确表明了这一点。

So, now let’s implement the delete method!

因此,现在让我们实现delete方法!

从Trie删除单词 (Delete a word from a Trie)

This one is actually a bit more tricky than the other two methods.

这个方法实际上比其他两种方法更棘手。

There doesn’t exist any format algorithm of sorts since there is no explicit way in which we store the keys and values.

由于没有明确的方式存储键和值,因此不存在任何种类的格式算法。

But, for the purpose of this article, I’ll handle deletions only if the word to be deleted is a leaf node. That is, it must be prefix matched all the way, until a leaf node.

但是,出于本文的目的,仅当要删除的单词是叶节点时,我才会处理删除。 也就是说,必须一直对其进行前缀匹配,直到叶子节点为止。

So let’s start. Our signature for the delete function will be:

因此,让我们开始吧。 我们对delete函数的签名为:


TrieNode* delete_trie(TrieNode* root, char* word);

As mentioned earlier, this will delete only if the prefix match is done until a leaf node. So let’s write another function is_leaf_node(), that does this for us.

如前所述,仅当前缀匹配完成直到叶节点时,此操作才会删除。 因此,让我们编写另一个函数is_leaf_node() ,为我们做到这一点。


int is_leaf_node(TrieNode* root, char* word) {// Checks if the prefix match of word and root// is a leaf nodeTrieNode* temp = root;for (int i=0; word[i]; i++) {int position = (int) word[i] - 'a';if (temp->children[position]) {temp = temp->children[position];}}return temp->is_leaf;
}

Okay, so with that completed, let’s look at the draft of our delete_trie() method.

好的,完成后,让我们看一下delete_trie()方法的草稿。


TrieNode* delete_trie(TrieNode* root, char* word) {// Will try to delete the word sequence from the Trie only it // ends up in a leaf nodeif (!root)return NULL;if (!word || word[0] == '\0')return root;// If the node corresponding to the match is not a leaf node,// we stopif (!is_leaf_node(root, word)) {return root;}// TODO
}

After this check is done, we now know that our word will end in a leaf node.

完成此检查后,我们现在知道单词将以叶节点结尾。

But there is another situation to handle. What if there exists another word that has a partial prefix match of the current string?

但是还有另一种情况要处理。 如果存在另一个单词,该单词的当前前缀部分匹配,该怎么办?

For example, in the below Trie, the words tea and ted have a partial common match until te.

例如,在下面的Trie中,单词teated具有部分共同的匹配项,直到te为止。

Trie – Partial Prefix Match
特里–部分前缀比赛

So, if this happens, we cannot simply delete the whole sequence from t to a, as then, both the chains will be deleted, as they are linked!

因此,如果发生这种情况,我们不能简单地从t到a删除整个序列,因为那样,两个链都将被删除,因为它们被链接了!

Therefore, we need to find the deepest point until which such matches occur. Only after that, can we delete the remaining chain.

因此,我们需要找到最深的匹配点。 只有在那之后,我们才能删除剩余的链。

This involves finding the longest prefix string, so let’s write another function.

这涉及查找最长的前缀字符串,因此让我们编写另一个函数。


char* longest_prefix(TrieNode* root, char* word);

This will return the longest match in the Trie, which is not the current word (word). The below code explains every intermediate step in the comments.

这将返回Trie中最长的匹配项,而不是当前单词( word )。 下面的代码解释了注释中的每个中间步骤。


char* find_longest_prefix(TrieNode* root, char* word) {// Finds the longest common prefix substring of word// in the Trieif (!word || word[0] == '\0')return NULL;// Length of the longest prefixint len = strlen(word);// We initially set the longest prefix as the word itself,// and try to back-track from the deepest position to// a point of divergence, if it existschar* longest_prefix = (char*) calloc (len + 1, sizeof(char));for (int i=0; word[i] != '\0'; i++)longest_prefix[i] = word[i];longest_prefix[len] = '\0';// If there is no branching from the root, this// means that we're matching the original string!// This is not what we want!int branch_idx  = check_divergence(root, longest_prefix) - 1;if (branch_idx >= 0) {// There is branching, We must update the position// to the longest match and update the longest prefix// by the branch index lengthlongest_prefix[branch_idx] = '\0';longest_prefix = (char*) realloc (longest_prefix, (branch_idx + 1) * sizeof(char));}return longest_prefix;
}

There is another twist here! Since we try to find the longest match, the algorithm will actually greedily match the original string itself! This is not what we want.

这里还有另外一个转折! 由于我们尝试找到最长的匹配项,因此该算法实际上会贪婪地匹配原始字符串本身! 这不是我们想要的。

We want the longest match that is NOT the input string. So, we must have a check with another method check_divergence().

我们希望最长的匹配不是输入字符串。 因此,我们必须使用另一种方法check_divergence()进行检查。

This will check if there is any branching from the root to the current position, and return the length of the best match which is NOT the input.

这将检查从根到当前位置是否有任何分支,并返回不是输入的最佳匹配的长度。

If we are in the bad chain, that corresponds to the original string, then there will be no branching from the point! So this is a good way for us to avoid that nasty point, using check_divergence().

如果我们处于与原始字符串相对应的坏链中,那么从该点开始就不会出现分支! 因此,这是使用check_divergence()避免该讨厌点的好方法。


int check_divergence(TrieNode* root, char* word) {// Checks if there is branching at the last character of word//and returns the largest position in the word where branching occursTrieNode* temp = root;int len = strlen(word);if (len == 0)return 0;// We will return the largest index where branching occursint last_index = 0;for (int i=0; i < len; i++) {int position = word[i] - 'a';if (temp->children[position]) {// If a child exists at that position// we will check if there exists any other child// so that branching occursfor (int j=0; j<N; j++) {if (j != position && temp->children[j]) {// We've found another child! This is a branch.// Update the branch positionlast_index = i + 1;break;}}// Go to the next child in the sequencetemp = temp->children[position];}}return last_index;
}

Finally, we’ve ensured that we don’t just delete the whole chain blindly. So now let’s move on with our delete method.

最后,我们确保我们不只是盲目地删除整个链。 现在,让我们继续delete方法。


TrieNode* delete_trie(TrieNode* root, char* word) {// Will try to delete the word sequence from the Trie only it // ends up in a leaf nodeif (!root)return NULL;if (!word || word[0] == '\0')return root;// If the node corresponding to the match is not a leaf node,// we stopif (!is_leaf_node(root, word)) {return root;}TrieNode* temp = root;// Find the longest prefix string that is not the current wordchar* longest_prefix = find_longest_prefix(root, word);//printf("Longest Prefix = %s\n", longest_prefix);if (longest_prefix[0] == '\0') {free(longest_prefix);return root;}// Keep track of position in the Trieint i;for (i=0; longest_prefix[i] != '\0'; i++) {int position = (int) longest_prefix[i] - 'a';if (temp->children[position] != NULL) {// Keep moving to the deepest node in the common prefixtemp = temp->children[position];}else {// There is no such node. Simply return.free(longest_prefix);return root;}}// Now, we have reached the deepest common node between// the two strings. We need to delete the sequence// corresponding to wordint len = strlen(word);for (; i < len; i++) {int position = (int) word[i] - 'a';if (temp->children[position]) {// Delete the remaining sequenceTrieNode* rm_node = temp->children[position];temp->children[position] = NULL;free_trienode(rm_node);}}free(longest_prefix);return root;
}

The above code simply finds the deepest node for the prefix match and deletes the remaining sequence matching word from the Trie, since that is independent of any other match.

上面的代码只是找到前缀匹配的最深节点,并从Trie中删除其余的序列匹配词,因为它与任何其他匹配均无关。

上述程序的时间复杂度 (Time Complexity for the above Procedures)

The Time Complexity of the procedures are mentioned below.

该过程的时间复杂度在下面提到。

Procedure Time Complexity of Implementation
search_trie() O(n) -> n is the length of the input string
insert_trie() O(n) -> n is the length of the input string
delete_trie() O(C*n) -> C is the number of alphabets,
n is the length of the input word
程序 实施的时间复杂度
search_trie() O(n) -> n是输入字符串的长度
insert_trie() O(n) -> n是输入字符串的长度
delete_trie() O(C * n) -> C是字母的数目,
n是输入单词的长度

For almost all cases, the number of alphabets is a constant, so the complexity of delete_trie() is also reduced to O(n).

在几乎所有情况下,字母的数量都是一个常数,因此delete_trie()的复杂度也降低为O(n)



Trie数据结构的完整C / C ++程序 (The Complete C/C++ program for the Trie Data Structure)

At long last, we’ve (hopefully), completed our delete_trie() function. Let’s check if what we’ve written was correct, using our driver program.

最后,我们(希望)完成了delete_trie()函数。 让我们使用驱动程序检查我们编写的内容是否正确。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>// The number of children for each node
// We will construct a N-ary tree and make it
// a Trie
// Since we have 26 english letters, we need
// 26 children per node
#define N 26typedef struct TrieNode TrieNode;struct TrieNode {// The Trie Node Structure// Each node has N children, starting from the root// and a flag to check if it's a leaf nodechar data; // Storing for printing purposes onlyTrieNode* children[N];int is_leaf;
};TrieNode* make_trienode(char data) {// Allocate memory for a TrieNodeTrieNode* node = (TrieNode*) calloc (1, sizeof(TrieNode));for (int i=0; i<N; i++)node->children[i] = NULL;node->is_leaf = 0;node->data = data;return node;
}void free_trienode(TrieNode* node) {// Free the trienode sequencefor(int i=0; i<N; i++) {if (node->children[i] != NULL) {free_trienode(node->children[i]);}else {continue;}}free(node);
}TrieNode* insert_trie(TrieNode* root, char* word) {// Inserts the word onto the Trie// ASSUMPTION: The word only has lower case charactersTrieNode* temp = root;for (int i=0; word[i] != '\0'; i++) {// Get the relative position in the alphabet listint idx = (int) word[i] - 'a';if (temp->children[idx] == NULL) {// If the corresponding child doesn't exist,// simply create that child!temp->children[idx] = make_trienode(word[i]);}else {// Do nothing. The node already exists}// Go down a level, to the child referenced by idx// since we have a prefix matchtemp = temp->children[idx];}// At the end of the word, mark this node as the leaf nodetemp->is_leaf = 1;return root;
}int search_trie(TrieNode* root, char* word)
{// Searches for word in the TrieTrieNode* temp = root;for(int i=0; word[i]!='\0'; i++){int position = word[i] - 'a';if (temp->children[position] == NULL)return 0;temp = temp->children[position];}if (temp != NULL && temp->is_leaf == 1)return 1;return 0;
}int check_divergence(TrieNode* root, char* word) {// Checks if there is branching at the last character of word// and returns the largest position in the word where branching occursTrieNode* temp = root;int len = strlen(word);if (len == 0)return 0;// We will return the largest index where branching occursint last_index = 0;for (int i=0; i < len; i++) {int position = word[i] - 'a';if (temp->children[position]) {// If a child exists at that position// we will check if there exists any other child// so that branching occursfor (int j=0; j<N; j++) {if (j != position && temp->children[j]) {// We've found another child! This is a branch.// Update the branch positionlast_index = i + 1;break;}}// Go to the next child in the sequencetemp = temp->children[position];}}return last_index;
}char* find_longest_prefix(TrieNode* root, char* word) {// Finds the longest common prefix substring of word// in the Trieif (!word || word[0] == '\0')return NULL;// Length of the longest prefixint len = strlen(word);// We initially set the longest prefix as the word itself,// and try to back-tracking from the deepst position to// a point of divergence, if it existschar* longest_prefix = (char*) calloc (len + 1, sizeof(char));for (int i=0; word[i] != '\0'; i++)longest_prefix[i] = word[i];longest_prefix[len] = '\0';// If there is no branching from the root, this// means that we're matching the original string!// This is not what we want!int branch_idx  = check_divergence(root, longest_prefix) - 1;if (branch_idx >= 0) {// There is branching, We must update the position// to the longest match and update the longest prefix// by the branch index lengthlongest_prefix[branch_idx] = '\0';longest_prefix = (char*) realloc (longest_prefix, (branch_idx + 1) * sizeof(char));}return longest_prefix;
}int is_leaf_node(TrieNode* root, char* word) {// Checks if the prefix match of word and root// is a leaf nodeTrieNode* temp = root;for (int i=0; word[i]; i++) {int position = (int) word[i] - 'a';if (temp->children[position]) {temp = temp->children[position];}}return temp->is_leaf;
}TrieNode* delete_trie(TrieNode* root, char* word) {// Will try to delete the word sequence from the Trie only it // ends up in a leaf nodeif (!root)return NULL;if (!word || word[0] == '\0')return root;// If the node corresponding to the match is not a leaf node,// we stopif (!is_leaf_node(root, word)) {return root;}TrieNode* temp = root;// Find the longest prefix string that is not the current wordchar* longest_prefix = find_longest_prefix(root, word);//printf("Longest Prefix = %s\n", longest_prefix);if (longest_prefix[0] == '\0') {free(longest_prefix);return root;}// Keep track of position in the Trieint i;for (i=0; longest_prefix[i] != '\0'; i++) {int position = (int) longest_prefix[i] - 'a';if (temp->children[position] != NULL) {// Keep moving to the deepest node in the common prefixtemp = temp->children[position];}else {// There is no such node. Simply return.free(longest_prefix);return root;}}// Now, we have reached the deepest common node between// the two strings. We need to delete the sequence// corresponding to wordint len = strlen(word);for (; i < len; i++) {int position = (int) word[i] - 'a';if (temp->children[position]) {// Delete the remaining sequenceTrieNode* rm_node = temp->children[position];temp->children[position] = NULL;free_trienode(rm_node);}}free(longest_prefix);return root;
}void print_trie(TrieNode* root) {// Prints the nodes of the trieif (!root)return;TrieNode* temp = root;printf("%c -> ", temp->data);for (int i=0; i<N; i++) {print_trie(temp->children[i]); }
}void print_search(TrieNode* root, char* word) {printf("Searching for %s: ", word);if (search_trie(root, word) == 0)printf("Not Found\n");elseprintf("Found!\n");
}int main() {// Driver program for the Trie Data Structure OperationsTrieNode* root = make_trienode('\0');root = insert_trie(root, "hello");root = insert_trie(root, "hi");root = insert_trie(root, "teabag");root = insert_trie(root, "teacan");print_search(root, "tea");print_search(root, "teabag");print_search(root, "teacan");print_search(root, "hi");print_search(root, "hey");print_search(root, "hello");print_trie(root);printf("\n");root = delete_trie(root, "hello");printf("After deleting 'hello'...\n");print_trie(root);printf("\n");root = delete_trie(root, "teacan");printf("After deleting 'teacan'...\n");print_trie(root);printf("\n");free_trienode(root);return 0;
}

Output

输出量


Searching for tea: Not Found
Searching for teabag: Found!
Searching for teacan: Found!
Searching for hi: Found!
Searching for hey: Not Found
Searching for hello: Found!-> h -> e -> l -> l -> o -> i -> t -> e -> a -> b -> a -> g -> c -> a -> n ->
After deleting 'hello'...-> h -> i -> t -> e -> a -> b -> a -> g -> c -> a -> n ->
After deleting 'teacan'...-> h -> i -> t -> e -> a -> b -> a -> g ->

With that, we’ve come to the end of our Trie Data Structure implementation in C/C++. I know that this is a long read, but hopefully you’ve understood how you can apply these methods correctly!

这样,我们就结束了C / C ++中Trie数据结构实现的过程。 我知道这是一本长篇小说,但希望您已经了解如何正确应用这些方法!



下载代码 (Download the Code)

You can find the complete code in a Github Gist that I’ve uploaded. It may not be the most efficient code, but I’ve tried my best to ensure that it’s working correctly.

您可以在我上传的Github Gist中找到完整的代码。 它可能不是最有效的代码,但我已尽力确保它正常工作。

If you have any questions or suggestions, do raise them in the comment section below!

如果您有任何疑问或建议,请在下面的评论部分提出!



参考资料 (References)

  • Wikipedia Article on Tries维基百科有关尝试的文章


推荐读物: (Recommended Reads:)

If you’re interested in similar topics, you can refer to the Data Structures and Algorithms section, which includes topics like Hash Tables and Graph Theory.

如果您对类似的主题感兴趣,可以参考“ 数据结构和算法”部分,其中包括诸如哈希表和图论之类的主题。



翻译自: https://www.journaldev.com/36507/trie-data-structure-in-c-plus-plus

trie树的数据结构

trie树的数据结构_C / C ++中的Trie数据结构相关推荐

  1. 数据结构专题—计算机中常用的数据结构

    前言: 在学习 java 相关技术或者学习mysql 存储引擎 InnoDB 的时候,会发现其底层运用了大量的数据结构.之所以不从java这门语言来展开讲数据结构是因为:数据结构是不分语言不分平台的. ...

  2. 字符串匹配数据结构 --Trie树 高效实现搜索词提示 / IDE自动补全

    文章目录 1. 算法背景 2. Trie 树实现原理 2.1 Trie 树的构建 2.2 Trie树的查找 2.3 Trie树的遍历 2.4 Trie树的时间/空间复杂度 2.5 Trie 树 Vs ...

  3. 数据结构-----基于双数组的Trie树

    Trie树简介 Trie树也称字典树,在字符串的查找中优势比较明显,适用于在海量数据中查找某个数据.因为Trie树的查找时间和数据总量没有关系,只和要查找的数据长度有关.比如搜索引擎中热度词语的统计. ...

  4. 数据结构八-Trie树

    文章出处:极客时间<数据结构和算法之美>-作者:王争.该系列文章是本人的学习笔记. 1 Trie树的使用场景 搜索引擎中的搜索词建议.当你在搜索引擎中输入词,搜索引擎提示给你一个词的列表, ...

  5. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  6. java单词匹配算法_前端学数据结构与算法(八): 单词前缀匹配神器-Trie树的实现及其应用...

    前言 继二叉树.堆之后,接下来介绍另外一种树型的数据结构-Trie树,也可以叫它前缀树.字典树.例如我们再搜索引擎里输入几个关键字之后,后续的内容会自动续上.此时我们输入的关键词也就是前缀,而后面的就 ...

  7. 字符串匹配算法 -- AC自动机 基于Trie树的高效的敏感词过滤算法

    文章目录 1. 算法背景 2. AC自动机实现原理 2.1 构建失败指针 2.2 依赖失败指针过滤敏感词 3. 复杂度及完整代码 1. 算法背景 之前介绍过单模式串匹配的高效算法:BM和KMP 以及 ...

  8. 算法 | 动画+解析,轻松理解「Trie树」

    Trie这个名字取自"retrieval",检索,因为Trie可以只用一个前缀便可以在一部字典中找到想要的单词. 虽然发音与「Tree」一致,但为了将这种 字典树 与 普通二叉树 ...

  9. Trie 树——搜索关键词提示

    当你在搜索引擎中输入想要搜索的一部分内容时,搜索引擎就会自动弹出下拉框,里面是各种关键词提示,这个功能是怎么实现的呢?其实底层最基本的就是 Trie 树这种数据结构. 1. 什么是 "Tri ...

最新文章

  1. Caffe源码中各种依赖库的作用及简单使用
  2. 机器学习在高德搜索建议中的应用优化实践
  3. android如何让自定义控件居中,Android自定义控件之自定义TextView,实现drawableLeft可以和文字一起居中...
  4. 中国第二代身份证验证js代码
  5. 成人教育计算机统考分数查询江苏省,江苏省教育考试院查询
  6. c++ h264RTP接收和发送程序
  7. iOS开发UI篇—核心动画(UIView封装动画)
  8. EasyExecl导出模板,实现动态下拉列
  9. 我的世界基岩版好还是java版好_我的世界:Java版本好玩还是基岩版好玩?老玩家看完后沉默了...
  10. html涟漪动画效果,CSS 在按钮上做个涟漪效果(Ripple Animation)
  11. C# 多窗口切换的实现
  12. word文件和扩展名不匹配的解决办法,亲测有效
  13. 2Opinion Word Expansion and Target Extraction through Double Propagation(2020-10-18)
  14. 可控硅温控器的组成和可控硅的选择
  15. int const, const int *,int *const,int const *const 区别
  16. win10 telnet不是内部或外部命令(已解决)
  17. 学习笔记(117):R语言入门基础-前10名的行业和地区展示
  18. 转录组表达量计RPKM、FPKM、TPM说明
  19. DECIMAL Data Type Characteristics
  20. java web工程web.xml配置详解

热门文章

  1. 禁止按钮在一定时间内连续点击
  2. WebPack 简明学习教程
  3. oracle 锁表查询及解决、表字段查询
  4. 搜狗云输入法对外提供调用体验
  5. [转载] windows下python包的导入方法
  6. [转载] numpy.minimum
  7. [转载] python的短逻辑
  8. PHP 利用curl 模拟get post 请求
  9. 牛客Wannafly挑战赛10 A.小H和迷宫
  10. App 更换应用图标