Trie树,即字典树,又称单词查找树或键树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较。
前缀树的3个基本性质:
1.根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2.从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3.每个节点的所有子节点包含的字符都不相同。
Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。
结构:
要点:
1.类型转换:string ——> char[] ,用c_str()函数后返回值为const char *,用mencpy进行内存拷贝初始化char[]后方便使用范围for遍历
2.删除节点时要释放掉堆区数据,避免出现内存泄漏。
参考左神代码编写:
#include
#include
#include
#include
#define MAX_BRANCH 26 //仅考虑26个字母组成的前缀树
using namespace std;
//节点
class TrieNode
{
public:
int pass; //经过次数
int end; //结束标记
vector<TrieNode *> nexts; //节点有 MAX_BRANCH 个指针指向其他节点
TrieNode() : pass(0), end(0), nexts(MAX_BRANCH, nullptr) {}
};
//前缀树
class TrieTree
{
private:
TrieNode *root;
public:
TrieTree(); //构造函数
~TrieTree(); //构造函数
void insert(string word); //插入函数
int search(string word); //查询字符出现次数
int prefix_number(string pre); //查询含前缀字符的字符串个数
void destory(TrieNode *node); //销毁子节点函数
void delete_data(string word); //删除元素函数
};
//构造函数
TrieTree::TrieTree()
{
root = new TrieNode;
}
//构造函数
TrieTree::~TrieTree()
{
destory(root);
}
//销毁子节点函数
void TrieTree::destory(TrieNode *node)
{
if (node == nullptr)
{
return;
}
for (int i = 0; i < MAX_BRANCH; i++)
{
destory(node->nexts[i]);
}
delete node;
node = nullptr;
}
//插入函数
void TrieTree::insert(string word)
{
if (word.empty())
{
return;
}
const char *cha = word.c_str(); // c_str() 返回类型为 const char * 类型
char data[word.size()]; //用于接收转化为char类型之后的字符串
memcpy(data, cha, strlen(cha)); // 内存拷贝初始化data
TrieNode *node = root;
node->pass++;
int index = 0;
for (char data_i : data)
{
index = data_i - 'a';
if (node->nexts[index] == nullptr)
{
node->nexts[index] = new TrieNode;
}
node = node->nexts[index];
node->pass++;
}
node->end++;
}
//查询字符出现次数
int TrieTree::search(string word)
{
if (word.empty())
{
return 0;
}
TrieNode *node = root;
const char *cha = word.c_str();
char data[word.size()];
memcpy(data, cha, strlen(cha));
int index = 0;
for (char data_i : data)
{
index = data_i - 'a';
if (node->nexts[index] == nullptr)
{
return 0;
}
node = node->nexts[index];
}
return node->end;
}
//查询含前缀字符的字符串个数
int TrieTree::prefix_number(string pre)
{
if (pre.empty())
{
return 0;
}
TrieNode *node = root;
const char *cha = pre.c_str();
char data[pre.size()];
memcpy(data, cha, strlen(cha));
int index = 0;
for (char data_i : data)
{
index = data_i - 'a';
if (node->nexts[index] == nullptr)
{
return 0;
}
node = node->nexts[index];
}
return node->pass;
}
//删除元素函数
void TrieTree::delete_data(string word)
{
if (search(word) != 0)
{
TrieNode *node = root;
--node->pass;
const char *chu = word.c_str();
char data[word.size()];
memcpy(data, chu, strlen(chu));
int index = 0;
for (char data_i : data)
{
index = data_i - 'a';
if (--node->nexts[index]->pass == 0) //进入分支,且是单一要删除的链路
{
destory(node->nexts[index]); //进入分支释放内存
node->nexts[index] = nullptr;
return;
}
node = node->nexts[index];
}
node->end--;
}
}
int main()
{
TrieTree tree1;
tree1.insert("abcde");
tree1.insert("abbbb");
tree1.insert("abccc");
cout << "abcde 出现的次数 :" << tree1.search("abcde") << endl
<< "以 abc 开头的字符串出现的次数 :" << tree1.prefix_number("abc") << endl;
tree1.delete_data("abcde");
cout << "删除 abcde 后" << endl
<< "abcde 出现的次数 :" << tree1.search("abcde") << endl
<< "以 abc 开头的字符串出现的次数 :" << tree1.prefix_number("abc");
return 0;
}
结果:
引用:
链接: 李滚滚 – 前缀树及C++实现.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)