赞
踩
Trie数据结构是一种高级数据结构,用于有效地存储和搜索字符串。Trie 源自单词 re TRIE val,意思是找到或取回某些东西。字典可以使用 Trie 数据结构有效地实现,Tries 也用于我们在搜索引擎中看到的自动完成功能。Trie 数据结构在存储和检索数据方面比二叉搜索树和哈希表更快。Trie 数据结构也称为前缀树或数字树。在 Trie 的帮助下,我们可以轻松地进行基于前缀的搜索。
Trie 数据结构是一种基于树的数据结构,用于存储字符串集合。trie 一词源自 re TRIE val 一词,意思是找到或拿回某些东西。如果两个字符串具有共同的前缀,那么它们在 trie 中将具有相同的祖先。在 trie 数据结构中,我们可以存储大量字符串,并可以有效地对其进行搜索操作。trie 可用于按字母顺序对字符串集合进行排序,以及搜索 trie 中是否存在具有给定前缀的字符串。字典可以在 trie 数据结构的帮助下有效地实现。现在让我们讨论何时以及如何实现 Trie 数据结构。
trie 数据结构用于存储和检索数据。我们可以想到的用于执行相同操作的另一种数据结构是哈希表。然而,trie 数据结构可以比哈希表更有效地处理这些操作。此外,trie数据结构可以用于基于前缀的搜索,而我们不能使用哈希表来进行基于前缀的搜索。基于前缀的搜索的一个示例是搜索字符串集合中存在的有多少字符串包含给定前缀。trie 数据结构给我们带来了优于哈希表的优势,主要体现在以下几个方面:
trie 的结构类似于树的结构。每个 trie 由一个根节点组成。根节点分支成具有多个边的各种子节点。每个TrieNode由一个指针数组组成,其中数组的每个索引代表一个字符。trie 的每个节点代表一个字符串,每条边代表一个字符。根节点是一个空字符串。除根节点外的每个节点都是一个字符串,其中包含从根到该节点的路径上的字符。让我们通过一个例子来了解 Trie 数据结构的结构。
上图显示了一个 trie 数据结构,其中输入字符串为ball、bat、eAr、eAt、tea和ten。我们可以看到每个节点代表给定字符串的一部分或前缀。根节点代表一个空字符串。每条边都由一个字符表示。
Trie数据结构的每一层代表一个给定长度的前缀。如果我们认为根节点处于级别0。那么根节点代表一个长度为0的前缀或者一个空字符串。Trie 的级别 1表示长度为1的前缀,依此类推。
如果tea和ten具有相同的祖先,即te和t ,则两个子节点具有相同的祖先。这是因为它们共享相同的te前缀。
请注意,我们可以在 Trie 数据结构中包含任意数量的字符,包括字母、数字和特殊字符。在本文中,我们将讨论带有字符az 的字符串。因此,对于 Trie 中的每个节点,我们都需要一个大小为26的指针数组。其中第 0 个索引表示a,第25 个索引表示z。
另一个需要注意的重要事项是 Trie 数据结构中的每个字符串都是按字典顺序从左到右排序的。我们将在讨论 Trie 中的插入操作时学习如何实现它。
现在让我们讨论如何在 Trie 数据结构中实现插入、搜索和删除操作。
在本节中,我们将讨论 Trie 数据结构中插入、搜索和删除操作背后的逻辑。我们将一一理解每一个操作的代码,然后在文章的后半部分实现Trie数据结构的整个代码。
借助插入操作,我们可以将新字符串插入到Trie数据结构中。首先我们来了解一下Trie节点的结构。当我们考虑带有字符a - z的字符串时。每个 Trie 节点都会有一个大小为26的字符指针数组。。我们将创建TrieNode的结构如下 -
- struct TrieNode {
- //pointer array for child nodes of each node
- TrieNode *childNode[26];
- int wordEndCnt;
-
- //constructor
- TrieNode()
- {
- //initialize the wordEndCnt variable with 0
- //initialize every index of childNode array with NULL
- wordEndCnt = 0;
- for (int i = 0; i < 26; i++)
- {
- childNode[i] = NULL;
- }
- }
- };

在将任何字符串插入 Trie 之前,我们为 Trie 创建一个根节点。根节点的结构如下。
根由一个空字符串和26 个指针组成,每个指针都用 NULL 初始化。图中的N表示每个索引处的 NULL 值。现在让我们尝试将字符串tea插入到 Trie 中。
上图显示了在 Trie 中插入Tea字符串的步骤。在每一步中,完成操作的节点都用绿色标记。我们将该节点称为当前节点。
现在让我们尝试将字符串10插入同一个 trie 中。插入步骤如下图所示。
让我们定义一个函数insert_key (TrieNode *root,string &key) ,它将带有两个参数。第一个参数是 Trie 的根。第二个参数是我们要插入到 Trie 数据结构中的字符串。我们创建一个currentNode指针并用根节点初始化它。然后我们循环遍历字符串键的整个长度并遵循上面讨论的算法。最后从insert_key()函数返回更新后的根节点。
- TrieNode* insert_key(TrieNode *root, string &key)
- {
- //initialize the currentNode pointer with the root node
- TrieNode *currentNode = root;
-
- //Store the length of the key string
- int length = key.size();
-
- //iterate across the length of the string
- for (int i = 0; i < length; i++)
- {
-
- //Check X-'a' th index is NULL or not
- if (currentNode->childNode[key[i] - 'a'] == NULL)
- {
- //If null make a new node
- TrieNode * newNode = new TrieNode();
-
- //Point the X-'a' th index of current node to the new node
- currentNode->childNode[key[i] - 'a'] = newNode;
- }
-
- //Move the current node pointer to the newly created node.
- currentNode = currentNode->childNode[key[i] - 'a'];
- }
-
- //Increment the wordEndCnt for the last currentNode pointer as it will point
- //the string that is the end of the string key.
- currentNode->wordEndCnt++;
-
- //return the updated root node
- return root;
- }

借助搜索操作,我们可以搜索某个字符串是否存在于 Trie 数据结构中。搜索操作可以修改为以不同的方式使用。在本文中,我们将讨论搜索操作,以检查查询函数中给出的整个字符串是否存在于 Trie 数据结构中。如果查询字符串存在,我们将返回布尔值 true,否则我们将返回布尔值 false。
Trie 数据结构中的搜索操作与插入操作类似。Search 操作中唯一的区别是,每当我们发现一个节点的X -当前节点的childNode指针数组的第一个索引为 NULL 时,我们都会返回 false,而不是创建一个新节点。这里X可以是查询字符串的任何字符。仅当我们处理整个查询字符串而没有遇到空指针并且最后一个节点的wordEndCnt大于0时,我们才返回 True 。
我们将使用上面讨论的第二次插入操作后获得的相同 Trie。让我们尝试在给定的 Trie 中搜索字符串tea 。
上图显示了 在 Trie 中搜索字符串tea所涉及的步骤。
最初,当前节点是根节点。查询字符串的第一个字符是t。我们检查当前节点的childNode指针数组的第t - a索引是否为NULL。由于它不为空,我们将当前节点指针移动到t -当前节点的第一个索引(即步骤 1 中的根节点)所指向的节点。
现在我们检查查询字符串的第二个字符,即e。由于当前节点的第e个索引也不为NULL。我们将当前节点指针移动到e -当前节点的第一个索引所指向的节点。
然后,我们处理查询字符串的最后一个字符,即a。由于当前节点的a - a索引不等于 null,我们将当前节点指针移动到当前节点的childNode指针数组的a - a th 索引所指向的节点。
最后,我们检查当前节点的wordEndCnt是否大于 0。如果wordEndCnt大于 0(查询字符串tea就是这种情况) ,我们将返回 true。否则,我们返回 false。
现在让我们讨论一下 Trie 中不存在查询字符串的情况。让我们尝试在 Trie 中搜索字符串。
让我们定义一个函数search_key (TrieNode *root,string &queryString) ,它将采用两个参数。第一个参数是 Trie 的根。第二个参数是我们要在 Trie 中搜索的字符串。我们创建一个currentNode指针并用根节点初始化它。然后我们循环遍历字符串queryString的整个长度。如果我们 在 Trie 中找到了queryString,则返回 true,否则返回 false。
- bool search_key(TrieNode *root, string &queryString)
- {
- //Initialize the currentNode pointer with the root node
- TrieNode *currentNode = root;
-
- //Store the length of the query string
- int length = queryString.size();
-
- for (int i = 0; i < length; i++)
- {
- //Check if the X-'a' th index is NULL or not
- if (currentNode->childNode[queryString[i] - 'a'] == NULL)
- {
- //If null then the query string is not present in the Trie
- //return false
- return false;
- }
- //If not NULL
- //Move the currentNode pointer to the node pointed by X-'a' th index of the
- //current node
- currentNode = currentNode->childNode[queryString[i] - 'a'];
- }
-
- //If currentNode pointer is not NULL
- //and wordEndCnt for the currentNode pointer
- //is greater than 0 then return true else
- //return false
- return currentNode != NULL && currentNode->wordEndCnt > 0;
- }

借助删除操作,我们可以删除 Trie 数据结构中先前出现的字符串。如果 Trie 数据结构中不存在某个字符串,我们就无法删除该字符串。如果使用删除操作成功删除字符串,我们将返回布尔值 True。如果该字符串不存在于 Trie 中,则返回布尔值 false。
为了在 Trie 数据结构中实现删除操作,我们首先搜索查询字符串是否存在于 Trie 中。为了搜索字符串,我们应用上一节中讨论的相同逻辑。如果该字符串不存在于 Trie 数据结构中,我们将返回 false。如果字符串存在于 Trie 数据结构中,我们将最后一个当前节点指针的节点 pointe 的wordEndCnt减少1。
让我们尝试从上面获得的Trie数据结构中删除字符串tea 。
上图显示了从给定 Trie 中删除字符串tea所涉及的步骤。
请注意,如果我们在上述操作之后再次尝试从 Trie 中删除字符串tea 。我们将无法删除该字符串,因为Trie中只有一个茶字符串,并且我们已经删除了该字符串。如果我们尝试删除字符串,那么对于最后一个当前节点,我们将得到值为0的wordEndCnt。所以我们返回一个布尔假值。
让我们定义一个函数delete_key (TrieNode *root,string &queryString),它将带有两个参数。第一个参数是 Trie 的根。第二个参数是我们要在 Trie 中删除的字符串。我们创建一个currentNode指针并用根节点初始化它。然后我们循环遍历字符串queryString的整个长度。如果 Trie 中不存在这样的字符串,我们返回 false。否则,我们递减Trie 中queryString的wordEndCnt并返回 true。
- bool delete_key(TrieNode *root, string &queryString)
- {
-
- //Initialize the currentNode pointer with the root node
- TrieNode *currentNode = root;
-
- //Store the length of the queryString
- int length = queryString.size();
-
- for (int i = 0; i < length; i++)
- {
- //Check if the X-'a' th index is NULL or not
- if (currentNode->childNode[queryString[i] - 'a'] == NULL)
- {
- //If null the query string is not present in the Trie
- //return false
- return false;
- }
- //Move the currentNode pointer to the next node
- currentNode = currentNode->childNode[queryString[i] - 'a'];
- }
-
- //If currentNode pointer is not NULL and
- //wordEndCnt for the currentNode is greater than 0
-
- if (currentNode != NULL && currentNode->wordEndCnt > 0)
- {
- //then decrement the wordEndCnt for the
- //currentNode
- currentNode->wordEndCnt--;
-
- //return true
- return true;
- }
-
- //If the wordEndCnt for the currentNode is equal to 0
- //then the queryString is not present in Trie
- //return false
-
- return false;
- }

- #include<bits/stdc++.h>
- using namespace std;
-
- struct TrieNode {
-
- //pointer array for child nodes of each node
- TrieNode *childNode[26];
- int wordEndCnt;
-
- TrieNode()
- {
- // constructor
- //initialize the wordCnt variable with 0
- //initialize every index of childNode array with NULL
- wordEndCnt = 0;
- for (int i = 0; i < 26; i++)
- {
- childNode[i] = NULL;
- }
- }
- };
-
- TrieNode * insert_key(TrieNode *root, string &key)
- {
- //initialize the currentNode pointer with the root node
- TrieNode *currentNode = root;
-
- //Store the length of the key string
- int length = key.size();
-
- //iterate across the length of the string
- for (int i = 0; i < length; i++)
- {
-
- //Check X-'a' th index is NULL or not
- if (currentNode->childNode[key[i] - 'a'] == NULL)
- {
- //If null make a new node
- TrieNode * newNode = new TrieNode();
-
- //Point the X-'a' th index of current node to the new node
- currentNode->childNode[key[i] - 'a'] = newNode;
- }
-
- //Move the current node pointer to the newly created node.
-
- currentNode = currentNode->childNode[key[i] - 'a'];
- }
-
- //Increment the wordEndCnt for the last currentNode pointer as it will point
- //the string that is the end of the string key.
- currentNode->wordEndCnt++;
-
- //return the updated root node
- return root;
- }
-
- bool search_key(TrieNode *root, string &queryString)
- {
- //Initialize the currentNode pointer with the root node
- TrieNode *currentNode = root;
-
- //Store the length of the query string
- int length = queryString.size();
-
- for (int i = 0; i < length; i++)
- {
- //Check if the X-'a' th index is NULL or not
- if (currentNode->childNode[queryString[i] - 'a'] == NULL)
- {
- //If null then the query string is not present in the Trie
- //return false
- return false;
- }
- //If not NULL
- //Move the currentNode pointer to the node pointed by X-'a' th index of the
- //current node
- currentNode = currentNode->childNode[queryString[i] - 'a'];
- }
-
- //If currentNode pointer is not NULL
- //and wordEndCnt for the currentNode pointer
- //is greater than 0 then return true else
- //return false
-
- return currentNode != NULL && currentNode->wordEndCnt > 0;
-
- }
-
- bool delete_key(TrieNode *root, string &queryString)
- {
-
- //Initialize the currentNode pointer with the root node
- TrieNode *currentNode = root;
-
- //Store the length of the queryString
- int length = queryString.size();
-
- for (int i = 0; i < length; i++)
- {
- //Check if the X-'a' th index is NULL or not
- if (currentNode->childNode[queryString[i] - 'a'] == NULL)
- {
- //If null the query string is not present in the Trie
- //return false
- return false;
- }
- //Move the currentNode pointer to the next node
- currentNode = currentNode->childNode[queryString[i] - 'a'];
- }
-
- //If currentNode pointer is not NULL and
- //wordEndCnt for the currentNode is greater than 0
-
- if (currentNode != NULL && currentNode->wordEndCnt > 0)
- {
- //then decrement the wordEndCnt for the
- //currentNode
- currentNode->wordEndCnt--;
-
- //return true
- return true;
- }
-
- //If the wordEndCnt for the currentNode is equal to 0
- //Then that string is not present in Trie
- //return false
-
- return false;
- }
-
- int main()
- {
- //make a root node for the Trie
- TrieNode *root = new TrieNode();
-
- //stores the strings that we want to insert in the
- //Trie
- vector<string> inputStrings = {"tea", "ten", "eat", "ear", "bat", "ball"};
-
- //number of insert operations in the Trie
- int n = inputStrings.size();
-
- for (int i = 0; i < n; i++)
- {
- root = insert_key(root, inputStrings[i]);
- }
-
- //stores the strings that we want to search in the Trie
- vector<string>searchQueryStrings = {"tea", "to", "bal"};
-
- //number of search operations in the Trie
- int searchQueries = searchQueryStrings.size();
-
- for (int i = 0; i < searchQueries; i++)
- {
- cout << "Query String : " << searchQueryStrings[i] << "\n";
- if (search_key(root, searchQueryStrings[i]))
- {
- //the queryString is present in the Trie
- cout << "The query string is present in the Trie\n";
- }
- else
- {
- //the queryString is not present in the Trie
- cout << "The query string is not present in the Trie\n";
- }
- }
-
- //stores the strings that we want to delete from the Trie
- vector<string>deleteQueryStrings = {"tea", "tea"};
-
- //number of delete operations from the Trie
- int deleteQueries = deleteQueryStrings.size();
-
- for (int i = 0; i < deleteQueries; i++)
- {
- cout << "Query String : " << deleteQueryStrings[i] << "\n";
- if (delete_key(root, deleteQueryStrings[i]))
- {
- //The queryString is successfully deleted from
- //the Trie
- cout << "The query string is successfully deleted\n";
- }
- else
- {
- //The query string is not present in the Trie
- cout << "The query string is not present in the Trie\n";
- }
- }
-
-
- return 0;
- }

- #include<stdio.h>
- #include<stdlib.h>
- #include<stdbool.h>
-
- struct TrieNode {
-
- //pointer array for child nodes of each node
- struct TrieNode *childNode[26];
- int wordEndCnt;
- };
-
- struct TrieNode* new_object()
- {
- struct TrieNode *new_node = (struct TrieNode*) malloc(sizeof(struct TrieNode));
-
- new_node->wordEndCnt = 0;
-
- for (int i = 0; i < 26; i++)
- {
- new_node->childNode[i] = NULL;
- }
-
- return new_node;
- }
-
- struct TrieNode * insert_key(struct TrieNode *root, const char *key)
- {
- //initialize the currentNode pointer with the root node
- struct TrieNode *currentNode = root;
-
- int i = 0;
-
- while (key[i] != '\0')
- {
- if (currentNode->childNode[key[i] - 'a'] == NULL)
- {
- //If null make a new node
- struct TrieNode * newNode = new_object();
-
- //Point the X-'a' th index of current node to the new node
- currentNode->childNode[key[i] - 'a'] = newNode;
- }
-
- //Move the current node pointer to the newly created node.
- currentNode = currentNode->childNode[key[i] - 'a'];
-
- i++;
- }
-
- //Increment the wordEndCnt for the last currentNode pointer as it will point
- //the string that is the end of the string key.
- currentNode->wordEndCnt++;
-
- //return the updated root node
- return root;
- }
-
- bool search_key(struct TrieNode *root, const char *queryString)
- {
- //Initialize the currentNode pointer with the root node
- struct TrieNode *currentNode = root;
-
- int i = 0;
-
- while (queryString[i] != '\0')
- {
-
- if (currentNode->childNode[queryString[i] - 'a'] == NULL)
- {
- //If null then the query string is not present in the Trie
- //return false
- return false;
- }
- //If not NULL
- //Move the currentNode pointer to the node pointed by X-'a' th index of the
- //current node
- currentNode = currentNode->childNode[queryString[i] - 'a'];
- i++;
- }
-
- //If currentNode pointer is not NULL
- //and wordEndCnt for the currentNode pointer
- //is greater than 0 then return true else
- //return false
-
- return currentNode != NULL && currentNode->wordEndCnt > 0;
-
- }
-
- bool delete_key(struct TrieNode *root, const char *queryString)
- {
-
- //Initialize the currentNode pointer with the root node
- struct TrieNode *currentNode = root;
-
- int i = 0;
-
- while (queryString[i] != '\0')
- {
- //Check if the X-'a' th index is NULL or not
- if (currentNode->childNode[queryString[i] - 'a'] == NULL)
- {
- //If null the query string is not present in the Trie
- //return false
- return false;
- }
- //Move the currentNode pointer to the next node
- currentNode = currentNode->childNode[queryString[i] - 'a'];
- i++;
- }
-
- //If currentNode pointer is not NULL and
- //wordEndCnt for the currentNode is greater than 0
- if (currentNode != NULL && currentNode->wordEndCnt > 0)
- {
- //then decrement the wordEndCnt for the
- //currentNode
- currentNode->wordEndCnt--;
-
- //return true
- return true;
- }
-
- //If the wordEndCnt for the currentNode is equal to 0
- //Then that string is not present in Trie
- //return false
- return false;
- }
-
- int main()
- {
- //make a root node for the Trie
- struct TrieNode *root = new_object();
-
- //stores the strings that we want to insert in the
- //Trie
- const char *inputStrings[] = {"tea\0", "ten\0", "eat\0", "ear\0", "bat\0", "ball\0"};
-
-
- //number of insert operations in the Trie
- int n = sizeof(inputStrings) / sizeof(const char *);
-
- for (int i = 0; i < n; i++)
- {
- root = insert_key(root, inputStrings[i]);
- }
-
- // stores the strings that we want to search in the Trie
- const char *searchQueryStrings[] = {"tea\0", "to\0", "bal\0"};
-
- // number of search operations in the Trie
- int searchQueries = sizeof(searchQueryStrings) / sizeof(const char *);
-
- for (int i = 0; i < searchQueries; i++)
- {
- printf("Query String : %s\n", searchQueryStrings[i]);
-
- if (search_key(root, searchQueryStrings[i]))
- {
- //the queryString is present in the Trie
- printf("The query string is present in the Trie\n");
- }
- else
- {
- //the queryString is not present in the Trie
- printf("The query string is not present in the Trie\n");
- }
-
- }
-
- // stores the strings that we want to delete from the Trie
- const char *deleteQueryStrings[] = {"tea\0", "tea\0"};
-
- // number of delete operations from the Trie
- int deleteQueries = sizeof(deleteQueryStrings) / sizeof(const char *);
-
- for (int i = 0; i < deleteQueries; i++)
- {
- printf("Query String : %s\n", deleteQueryStrings[i]);
-
- if (delete_key(root, deleteQueryStrings[i]))
- {
- //The queryString is successfully deleted from
- //the Trie
- printf("The query string is successfully deleted\n");
- }
- else
- {
- //The query string is not present in the Trie
- printf("The query string is not present in the Trie\n");
- }
- }
-
-
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。