利用Trie树对字符串集合进行排序并计算特征值
该算法用于将一组乱序的字符串反序列化到一个Trie树中,这个过程即可视为对字符串进行了一次排序。
还可以通过调用 GetFeatureString 将该 Trie 树重新序列化。
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #ifndef bool
# define bool char
#endif #ifndef true
# define true
#endif #ifndef false
# define false
#endif #define NEXTSIZE 256 struct TrieTreeNode
{
struct TrieTreeNode *Next[NEXTSIZE];
bool Accepted;
}; struct TrieTreeRoot
{
int NodeCount;
struct TrieTreeNode *Tree;
}; struct TrieTreeRoot *BuildTrieTree();
void InsertItem(struct TrieTreeRoot *TrieTreeRoot, char *Item);
unsigned char *GetFeatureString(struct TrieTreeRoot *TrieTreeRoot, int *StringLength); /*
* 构建 Trie 树并初始化
* 返回一个新的 Trie 根节点
*/
struct TrieTreeRoot *BuildTrieTree()
{
struct TrieTreeRoot *Root = (struct TrieTreeRoot *)malloc(sizeof(struct TrieTreeRoot));
Root->NodeCount = ;
Root->Tree = (struct TrieTreeNode *)malloc(sizeof(struct TrieTreeNode));
memset(Root->Tree, '\0', sizeof(struct TrieTreeNode));
return Root;
} /*
* 插入新的字符串
* Root : struct TrieTreeRoot* 要操作的 Trie 树根节点
* Item : char* 要插入的字符串
*/
void InsertItem(struct TrieTreeRoot *Root, char *Item)
{
struct TrieTreeNode *Ptr = Root->Tree;
int index = ;
unsigned char Charactor; while ((Charactor = Item[index]) != '\0')
{
if (Ptr->Next[Charactor] == NULL)
{
Ptr->Next[Charactor] = (struct TrieTreeNode *)malloc(sizeof(struct TrieTreeNode));
memset(Ptr->Next[Charactor], '\0', sizeof(struct TrieTreeNode));
Root->NodeCount++;
}
Ptr = Ptr->Next[Charactor];
index++;
} Ptr->Accepted = true;
} /*
* 递归序列化 Trie 树
* Node : struct TrieTreeNode* 当前操作的 Trie 节点
* WritePtr : unsigned char* 特征串写入指针
*/
unsigned char *DoFeature(struct TrieTreeNode *Node, unsigned char *WritePtr)
{
int i, count = ;
unsigned char *ErgodicPtr; *WritePtr = (unsigned char)Node->Accepted; // 写入节点是否接受
WritePtr++; ErgodicPtr = WritePtr; // 记录集合起始地址 for (i = ; i < NEXTSIZE; i++) // 将该组记录写入特征串
{
if (Node->Next[i] != NULL)
{
*WritePtr = (char)i;
WritePtr++;
count++;
}
} *WritePtr = '\0'; // 写入组分隔符
WritePtr++; for (i = ; i < count; i++) // 递归调用处理所有边
{
WritePtr = DoFeature(Node->Next[ErgodicPtr[i]], WritePtr);
} return WritePtr;
} /*
* 取得 Trie 的特征串,即序列化 Trie 树
* Root : struct TrieTreeRoot* 要操作的 Trie 树根节点
* StringLength : int* 长度指针(为了返回二进制串而设置)
*/
unsigned char *GetFeatureString(struct TrieTreeRoot *Root, int *StringLength)
{
struct TrieTreeNode *Ptr = Root->Tree;
// 假设最坏情况下,每个节点只有一条边,那么存储该节点就需要三个单元(Accepted、边、分隔符)
// 但实际上真正用到的只有 3N-1 个字节
unsigned char *FeatureString = (unsigned char *)malloc(Root->NodeCount * );
unsigned char *WritePtr = FeatureString; WritePtr = DoFeature(Ptr, WritePtr); *StringLength = WritePtr - FeatureString;
return FeatureString;
} void Test_1()
{
struct TrieTreeRoot *t = BuildTrieTree();
InsertItem(t, "P(\376P)\377");
InsertItem(t, "P(\376)\377");
InsertItem(t, "P(\376P)(");
InsertItem(t, "P(\376)(");
InsertItem(t, "P\376(P))");
InsertItem(t, "P\376())");
int l = , i;
unsigned char *s = GetFeatureString(t, &l);
printf("Feature: Size=%d, NodeCount=%d\n", l, t->NodeCount);
for (i = ; i < l; i++)
{
printf("%X ", s[i]);
}
printf("\n");
} void Test_2()
{
struct TrieTreeRoot *t = BuildTrieTree();
InsertItem(t, "P(\376)(");
InsertItem(t, "P(\376P)\377");
InsertItem(t, "P(\376P)(");
InsertItem(t, "P(\376(\377");
InsertItem(t, "P(\376P)\377");
InsertItem(t, "P\376())");
InsertItem(t, "P(\376)\377");
InsertItem(t, "P\376(P))");
int l = , i;
unsigned char *s = GetFeatureString(t, &l);
printf("Feature: Size=%d, NodeCount=%d\n", l, t->NodeCount);
for (i = ; i < l; i++)
{
printf("%X ", s[i]);
}
printf("\n");
} int main(int argc, char **argv)
{
Test_1();
Test_2();
return ;
}
仍有两个地方可以进行优化:
1、将 next 数组改为指针,有效减少叶子节点占用的空间;
2、如果插入的字符串是固定的,那么可以通过第一遍扫描该组字符串,构建一个大小为256的字典,通过代码 next[dic[charactor]] 进行访问,可有效减少边的数量。
利用Trie树对字符串集合进行排序并计算特征值的更多相关文章
- Trie树:应用于统计和排序
Trie树:应用于统计和排序 1. 什么是trie树 1.Trie树 (特例结构树) Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构 ...
- poj 2945 trie树统计字符串出现次数
用记录附加信息的val数组记录次数即可. trie的原理:每个可能出现的字目给一个编号c,那么整个树就是一个c叉树 ch[u][c]表示 节点u走c边过去之后的节点 PS:trie树还有种动态写法,使 ...
- 利用trie树实现前缀输入提示及trie的python实现
代码来自https://github.com/wklken/suggestion/blob/master/easymap/suggest.py 还实现了缓存功能,搜索某个前缀超过一定次数时,进行缓存, ...
- Trie树检索字符串
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct TrieNode ...
- 大规模字符串检索-压缩trie树
本文使用压缩trie树实现字符串检索的功能.首先将字符串通过编码转化为二进制串,随后将二进制串插入到trie树中,在插入过程中同时实现压缩的功能. 字符编码采用Huffman,但最终测试发现不采用Hu ...
- Trie树(c++实现)
转:http://www.cnblogs.com/kaituorensheng/p/3602155.html http://blog.csdn.net/insistgogo/article/detai ...
- Trie树
一.什么是trie树 1.Trie树 (特例结构树) Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构.典型应用是用于统计和排序大量的字符串( ...
- trie树信息抽取之中文数字抽取
这一章讲一下利用trie树对中文数字抽取的算法.trie树是一个非常有用的数据结构,可以应用于大部分文本信息抽取/转换之中,后续会开一个系列,对我在实践中摸索出来的各种抽取算法讲开来.比如中文时间抽取 ...
- Trie树(字典树) 最热门的前N个搜索关键词
方法介绍 1.1.什么是Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...
随机推荐
- 带参数的查询防止SQL注入攻击
把单引号替换成两个单引号,虽然能起到一定的防止SQL注入攻击的作用,但是更为有效的办法是把要拼接的内容做成“参数” SQLCommand支持带参数的查询,也就是说,可以在查询语句中指定参数: 参数的设 ...
- 百练_2409 Let it Bead(Polya定理)
描述 "Let it Bead" company is located upstairs at 700 Cannery Row in Monterey, CA. As you ca ...
- php 单引号与双引号区别
一.单引号与双引号区别 1." "双引号里面的字段会经过编译器解释,然后再当作HTML代码输出. 2.' '单引号里面的不进行解释,直接输出. 从字面意思上就可以看出,单引号比双引 ...
- 24种设计模式--装饰模式【Decorator Pattern】
装饰模式在中国使用的那实在是多,中国的文化是中庸文化,说话或做事情都不能太直接,需要有技巧的,比如说话吧,你要批评一个人,你不能一上来就说你这个做的不对,那个做的不对,你要先肯定他的成绩,表扬一下优点 ...
- 将requirejs进行到底(一)
随着网站功能逐渐丰富,网页中的js也变得越来越复杂和臃肿,原有通过script标签来导入一个个的js文件这种方式已经不能满足现在互联网开发模式,我们需要团队协作.模块复用.单元测试等等一系列复杂的需求 ...
- 解决WEB(apache)服务器time_wait过高的性能优化过程
目录 1.网站的硬件环境 2.修改Httpd.conf 3.修改sysctl.conf文件 一.网站环境LAMP硬件环境 [root@www conf]# dmidecode -s processor ...
- Installing MySQL Server
Installing MySQL Server Here we will learn how to Compile and Install the MySQL Server from source c ...
- android 代码混淆及问题大集锦
最近在需要对所开发的项目进行了代码混淆,在android studio中开启代码混淆其实还是挺方便的,不过因为代码混淆产生的问题非常多,特别是对于一些涉及到反射的第三方库经常因为名称的变化导致无法使用 ...
- C# mvc 验证码3
//// <summary> /// 生成验证码 /// </summary> /// <param name="length">指定验证码的长 ...
- 手写js面向对象选项卡插件
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8&qu ...