字典树Trie
简介:
字典树Trie又称前缀树、查找树,是哈希树的一个变种。存储字典、字符串快速检索、求最长公共前缀、快速统计和字符串快速排序等有较多的应用。可以减少无效字符的比较,相对于哈希来说,查找效率更高,更节约空间。
基本性质:
- 根结点没有字符,除了根结点外,每个结点只有一个字符
- 从根结点到某一结点,路径上经过的字符连起来,为该结点对应的字符串
- 每个结点的所有子结点包含的字符都不相同
很明显,查询的时间是线性的,存储的空间也是线性的。问题的复杂度在于该线性的常数的取值。一般来说,采用孩子兄弟结点的存储结构来存储。
举例说明:
上图所示的Trie中,从左到有的单词分别是:Add、At、try、transh、In、It。
代码实现:
#include <bits/stdc++.h>
using namespace std;
struct Node {
char data;
struct Node *ch, *bro;
Node() {
ch = bro = nullptr;
}
} *root;
void Create(int N) { // 建立Trie算法
for(int k = 0; k < N; ++k) {
string num;
cin >> num;
Node *r = root;
int len = num.length();
for(int i = 0; i < len; ++i) {
Node* ch = r->ch;
if(ch == nullptr) { // 没有孩子结点,直接添加孩子结点
ch = new Node;
ch->data = num[i];
r->ch = ch;
r = ch;
} else { // 已经有孩子结点的情况
Node* p = ch;
while(p != nullptr && p->bro != nullptr && p->data != num[i]) {
p = p->bro;
}
if(p->data == num[i]) { // 能匹配上之前的前缀
r = p;
ch = r->ch;
} else { // 开辟新的前缀
p->bro = new Node;
r = p->bro;
r->data = num[i];
ch = r->ch;
}
}
}
}
}
bool Find(const string& num) { // 查询算法
Node* r = root;
int len = num.length();
for(int i = 0; i < len; ++i) {
Node* ch = r->ch;
if(ch != nullptr && ch->data == num[i]) { // 可以匹配
r = ch;
ch = r->ch;
if(i == len - 1) {
return true; // 找到了
}
} else if(ch == nullptr && i < len - 1) { // 待查询字符串过长的情况
return false;
} else {
while(ch != nullptr && ch->data != num[i]) { // 查询兄弟结点
ch = ch->bro;
}
if(ch == nullptr) {
return false;
} else { // 可以匹配当前字符,继续向下查找孩子
r = ch;
ch = r->ch;
}
}
}
return false;
}
int main() {
root = new Node;
int N;
cout << "input number of phone numbers:" << endl;
cin >> N;
cout << "input phone numbers:" << endl;
Create(N);
cout << "input to check:" << endl;
string num;
cin >> num;
if(Find(num)) {
cout << "yes" << endl;
} else {
cout << "No" << endl;
}
return 0;
}