0
点赞
收藏
分享

微信扫一扫

【算法模板】前缀树(原理+数组&哈希实现)


前缀树

前缀是原理


前缀树是N叉树的一种特殊形式,通常来用来存储字符串

前缀树每一个节点代表一个字符串(前缀),每个节点会有多个子节点,通往不同子节点的路径上有着不同的字符。

子节点代表的字符串是由节点本身的原始字符串,以及通往该子节点路径上所有的字符组成的。

【算法模板】前缀树(原理+数组&哈希实现)_字符串

根节点表示空字符串。

重要特性:节点所有的后代都与该节点相关的字符串有着共同的前缀。

前缀树的特别之处在于字符和子节点之间的对应关系。

可用于用于自动补全、拼写检查


前缀树表示方法


用数组存储子节点


#define N 26  // 26个英文字母

struct TrieNode {
TrieNode* children[N];
// you might need some extra values according to different cases
};
// 访问快捷,容易导致空间浪费


用哈希表来存储子节点


struct TrieNode {
unordered_map<char, TrieNode*> children;

// you might need some extra values according to different cases
};
// 根据键值访问节点,比数组稍慢,但是节省空间

前缀树操作


①插入

②查询


实现前缀树

数组实现前缀树

class Trie
{
private:
bool isEnd=false;
Trie *children[26]={nullptr};
public:
Trie(){}

void insert(const string word)//插入单词
{
Trie *root=this;
for(auto ch:word){
ch -= 'a';
if(root->children[ch]==nullptr){
root->children[ch]=new Trie();
}
root=root->children[ch];
}
root->isEnd=true;
}

bool search(const string word)//查找单词
{
Trie* root=this;
for(auto ch:word){
ch -= 'a';
if(root->children[ch]==nullptr)return false;
root=root->children[ch];
}
return root->isEnd;
}

bool startsWith(string prefix)//查找前缀
{
Trie* root=this;
for(auto ch:prefix){
ch -= 'a';
if(root->children[ch]==nullptr)return false;
root=root->children[ch];
}
return true;
}
};
class Trie {
private:
// 使用数组构造
vector<Trie*>children;
bool isEnd; // 标志位,是否到字符串末尾
// 查询前缀
Trie* searchPrefix(string prefix) {
Trie* node = this;
// 遍历前缀,进行比对
for(char ch : prefix){
ch -= 'a';
if(node->children[ch] == nullptr){ // 遍历到空,说明没有此前缀,返回
return nullptr;
}
node = node->children[ch];
}
return node; // 前缀都遍历了一遍,说明树中有这个前缀
}
public:
// 构造,初始化
Trie() : children(26), isEnd(false) {}
// 插入
void insert(string word) {
Trie* node = this;
// 遍历字符串
for(char ch : word) {
ch -= 'a'; // 当前字符在数组中的位置
// 判断前缀树中是否存在这个字符
if(node->children[ch] == nullptr){
// 不存在,就新建
node->children[ch] = new Trie();
}
// 更新节点
node = node->children[ch];
}
// 遍历结束,标志位赋值true
node->isEnd = true;
}
// 查询
bool search(string word) {
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd; // 验证是不是到单词末尾
}
bool startWith(string prefix) {
return this->searchPrefix(prefix) != nullptr;
}
};

哈希表实现前缀树

class Trie {
private:
unordered_map<char, Trie*> umap;
bool isEnd;

Trie* searchPrefix(string prefix){
Trie* node = this;
for(char ch : prefix){
if(umap.find(ch) == umap.end()){
return nullptr;
}
node = umap[ch];
}
return node;
}
public:
Trie() : umap(26), isEnd(false) {}

void insert(string word){
Trie* node = this;
for(char ch : word){
if(umap.find(ch) == umap.end()){
umap[ch] = new Trie();
}
node = umap[ch];
}
node->isEnd = true;
}
bool search(string word){
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd;
}
bool startsWith(string prefix){
return this->searchPrefix(prefix) != nullptr;
}
};

示例

/*
* @Descripttion:
* @version:
* @Author: KJ
* @Date: 2022-04-11 16:34:33
* @LastEditors: KJ
* @LastEditTime: 2022-04-17 19:04:28
*/
#include <iostream>
#include <vector>
#include <unordered_map>

using namespace std;


// class Trie
// {
// private:
// bool isEnd=false;
// Trie *children[26]={nullptr};
// public:
// Trie(){}

// void insert(const string word)//插入单词
// {
// Trie *root=this;
// for(auto ch:word){
// ch -= 'a';
// if(root->children[ch]==nullptr){
// root->children[ch]=new Trie();
// }
// root=root->children[ch];
// }
// root->isEnd=true;
// }

// bool search(const string word)//查找单词
// {
// Trie* root=this;
// for(auto ch:word){
// ch -= 'a';
// if(root->children[ch]==nullptr)return false;
// root=root->children[ch];
// }
// return root->isEnd;
// }

// bool startsWith(string prefix)//查找前缀
// {
// Trie* root=this;
// for(auto ch:prefix){
// ch -= 'a';
// if(root->children[ch]==nullptr)return false;
// root=root->children[ch];
// }
// return true;
// }
// };

// class Trie {
// private:
// // 使用数组构造
// vector<Trie*>children;
// bool isEnd; // 标志位,是否到字符串末尾
// // 查询前缀
// Trie* searchPrefix(string prefix) {
// Trie* node = this;
// // 遍历前缀,进行比对
// for(char ch : prefix){
// ch -= 'a';
// if(node->children[ch] == nullptr){ // 遍历到空,说明没有此前缀,返回
// return nullptr;
// }
// node = node->children[ch];
// }
// return node; // 前缀都遍历了一遍,说明树中有这个前缀
// }
// public:
// // 构造,初始化
// Trie() : children(26), isEnd(false) {}
// // 插入
// void insert(string word) {
// Trie* node = this;
// // 遍历字符串
// for(char ch : word) {
// ch -= 'a'; // 当前字符在数组中的位置
// // 判断前缀树中是否存在这个字符
// if(node->children[ch] == nullptr){
// // 不存在,就新建
// node->children[ch] = new Trie();
// }
// // 更新节点
// node = node->children[ch];
// }
// // 遍历结束,标志位赋值true
// node->isEnd = true;
// }
// // 查询
// bool search(string word) {
// Trie* node = this->searchPrefix(word);
// return node != nullptr && node->isEnd; // 验证是不是到单词末尾
// }
// bool startsWith(string prefix) {
// return this->searchPrefix(prefix) != nullptr;
// }
// };

class Trie {
private:
unordered_map<char, Trie*> umap;
bool isEnd;

Trie* searchPrefix(string prefix){
Trie* node = this;
for(char ch : prefix){
if(umap.find(ch) == umap.end()){
return nullptr;
}
node = umap[ch];
}
return node;
}
public:
Trie() : umap(26), isEnd(false) {}

void insert(string word){
Trie* node = this;
for(char ch : word){
if(umap.find(ch) == umap.end()){
umap[ch] = new Trie();
}
node = umap[ch];
}
node->isEnd = true;
}
bool search(string word){
Trie* node = this->searchPrefix(word);
return node != nullptr && node->isEnd;
}
bool startsWith(string prefix){
return this->searchPrefix(prefix) != nullptr;
}
};

int main() {
Trie demo;
demo.insert("abc");
demo.insert("defr");
demo.insert("asdrtf");
cout << demo.search("a") << endl;
cout << demo.search("abc") << endl;

cout << demo.startsWith("def") << endl;
cout << demo.search("ap") << endl;

return 0;
}

【算法模板】前缀树(原理+数组&哈希实现)_c++_02



举报

相关推荐

0 条评论