该算法用于将一组乱序的字符串反序列化到一个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树对字符串集合进行排序并计算特征值的更多相关文章

  1. Trie树:应用于统计和排序

    Trie树:应用于统计和排序 1. 什么是trie树 1.Trie树 (特例结构树)       Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构 ...

  2. poj 2945 trie树统计字符串出现次数

    用记录附加信息的val数组记录次数即可. trie的原理:每个可能出现的字目给一个编号c,那么整个树就是一个c叉树 ch[u][c]表示 节点u走c边过去之后的节点 PS:trie树还有种动态写法,使 ...

  3. 利用trie树实现前缀输入提示及trie的python实现

    代码来自https://github.com/wklken/suggestion/blob/master/easymap/suggest.py 还实现了缓存功能,搜索某个前缀超过一定次数时,进行缓存, ...

  4. Trie树检索字符串

    #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct TrieNode ...

  5. 大规模字符串检索-压缩trie树

    本文使用压缩trie树实现字符串检索的功能.首先将字符串通过编码转化为二进制串,随后将二进制串插入到trie树中,在插入过程中同时实现压缩的功能. 字符编码采用Huffman,但最终测试发现不采用Hu ...

  6. Trie树(c++实现)

    转:http://www.cnblogs.com/kaituorensheng/p/3602155.html http://blog.csdn.net/insistgogo/article/detai ...

  7. Trie树

    一.什么是trie树 1.Trie树 (特例结构树)   Trie树,又称单词查找树.字典树,是一种树形结构,是一种哈希树的变种,是一种用于快速检索的多叉树结构.典型应用是用于统计和排序大量的字符串( ...

  8. trie树信息抽取之中文数字抽取

    这一章讲一下利用trie树对中文数字抽取的算法.trie树是一个非常有用的数据结构,可以应用于大部分文本信息抽取/转换之中,后续会开一个系列,对我在实践中摸索出来的各种抽取算法讲开来.比如中文时间抽取 ...

  9. Trie树(字典树) 最热门的前N个搜索关键词

    方法介绍 1.1.什么是Trie树 Trie树,即字典树,又称单词查找树或键树,是一种树形结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...

随机推荐

  1. Android简单例子——AlertDialog

    最近学习了一段时间的Android,在网上找了些小的Demo,自己模拟这做了下,首先谢谢那些提供例子的朋友 今天主要学习的是简单的Dialog的使用(实现退出对话框)和自定义对话框 1.实现退出对话框 ...

  2. iOS程序员的自我修养之道

    新技术的了解渠道 WWDC开发者大会视频 官方文档 General -> Guides -> iOS x.x API Diffs 程序员的学习 iOS技术的学习 官当文档 Sample C ...

  3. CSS3—CSS3和现代Web设计

    1.1 现代Web设计理念 1.1.1 可访问性第一 同样一段内容, 可以用成千上万的方法为其设计样式, 但全世界的用户应该依然可以访问它们, 不管他们用什么方式去访问Web——无论手机.键盘控制器还 ...

  4. 【elasticsearch】(4)centos7 超简单安装elasticsearch 的 jdbc

    前言 elasticsearch(下面简称ES)使用jdbc连接mysql比go-mysql-elasticsearch的elasticsearch-river-jdbc能够很好的支持增量数据更新的问 ...

  5. struts2 package元素

    <package../>元素         name         必选    包名         extends     可选    继承         namespace    ...

  6. 或许有一两点你不知的C语言特性

    关键字篇 volatile关键字 鲜为人知的关键字之一volatile,表示变量是'易变的',之所以会有这个关键字,主要是消除编译优化带来的一些问题,看下面的代码 ; int b = a; int c ...

  7. PHP创建桌面快捷方式实例

    要利用php创建桌面快捷方式我们需要借助于header,InternetShortcut及一些我看不懂的代码. 方法:新建一个php文件,然后把下面的代码扔进去,保存为比如shortcut.php,放 ...

  8. Windows下面对环境变量的操作

    如何在cmd命令行中查看.修改.删除与添加环境变量:首先明确一点:所有的在cmd命令行下对环境变量的修改只对当前窗口有效,不是永久性的修改.也就是说当关闭此cmd命令行窗口后,将不再起作用.永久性修改 ...

  9. Unity3D C#脚本开发学习

    1. Inherit from MonoBehaviour,All behaviour scripts must inherit from MonoBehaviour (directly or ind ...

  10. 我们说的oc是动态运行时语言是什么意思?

    1.KVC和KVO区别,分别在什么情况下使用?  答:KVC(Key-Value-Coding) KVO(Key-Value-Observing)理解KVC与KVO(键-值-编码与键-值-监看) 当通 ...