利用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树,即字典树,又称单词查找树或键树,是一种树形结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...
随机推荐
- ubuntu出现有线已连接却无法上网
或者直接追加到/etc/sysctl.conf 如果遇到“设备未托管”,一般是台式机默认移动ip后禁用网络. 那么修改/etc/NetworkManager/NetworkManager.conf,设 ...
- winform中的chat
百度一下 源代码下载:百度一下
- (转)JS页面间传值
一:JavaScript静态页面值传递之URL篇 能过URL进行传值.把要传递的信息接在URL上. 例子: 参数传出页面Post.htm—> <input type="text& ...
- [Lua]cocos framework
package_support function cc.register(name, package) function cc.load(...) function cc.bind(target, . ...
- Angularjs中编写指令模版
angular.module('moduleName', []).directive( 'namespaceDirectiveName', [ function() { return { restri ...
- sublime 正则搜索日语字符
sublime 正则搜索日语字符 [\x{3041}-\x{3096}\x{30A0}-\x{30FF}\x{3400}-\x{4DB5}\x{4E00}-\x{9FCB}\x{F900}-\x{FA ...
- Eclipse Git和sourceTree用法
Eclipse Git和sourceTree用法 Eclipse Git: 提交代码到git: 1.team->Repository->pull 若没有冲突: 2.team->com ...
- CSS3—CSS3和现代Web设计
1.1 现代Web设计理念 1.1.1 可访问性第一 同样一段内容, 可以用成千上万的方法为其设计样式, 但全世界的用户应该依然可以访问它们, 不管他们用什么方式去访问Web——无论手机.键盘控制器还 ...
- hibernate面试笔记
Hibernate使用Java 反射机制 而不是字节码增强程序来实现透明性 如果JDBC代码写的完美,优化做好,那么JDBC效率是最高的.但是,实际开发中非常不现实,对程序员要求太高.一般情况下,hi ...
- php函数应用场景
截取文件后缀: $slen = strlen($suffix); substr($this->uri_string, -$slen) === $suffix 原理:截取倒数多少长度字符 判断多维 ...