利用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树,即字典树,又称单词查找树或键树,是一种树形结构.典型应用是用于统计和排序大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计.它的优 ...
随机推荐
- C# 控制台窗口的显示与隐藏
1. 定义一个Consolse帮助类,如下: /// <summary> /// 控制台帮助类 /// </summary> public static class Conso ...
- 一、C# 概述
1.托管执行环境 2.程序集 3.关键字:C#保留字 4.除了C#定义的关键字之外,开发者可以提供他们自己的名称,编程语言将这些名称称为标识符 5.如果关键字包含一个"@"前缀,那 ...
- jQuery无刷新上传学习心得
记得刚离开大学,进入目前这家公司不到一个月时,有一位前辈给我们当时的新人讲了下JS无刷新上传的相关知识. 在此之前,一直都是在使用C#提供的服务器上传控件FileUpload,但是每次使用时,都会刷新 ...
- 关于Java中的选择排序法和冒泡排序法
一,这种方法是直接传入一个数组进行排序(选择排序法) public static void selectSort(int arr[]){ for (int i = 0; i < arr.leng ...
- 谷歌的C++智能指针实现
//智能指针基类所有智能指针对象都继承该类class RefCountedBase { public: ; ; protected: virtual ~RefCountedBase(){} }; 智能 ...
- Windowsphone 之xml序列化和反序列化的应用(WebService解析返回的数据DataSet )
关于Xml的序列化和反序列化: 可以看这篇文章,http://www.cnblogs.com/Windows-phone/p/3243575.html WebService解析返回的数据DataSet ...
- WPF DataGrid 行头小三角
<DataTemplate x:Key="RowHeaderTemplate"> <StackPanel Orientation="Horizontal ...
- 2、Python djang 框架下的word Excel TXT Image 等文件的下载
2.python实现文件下载 (1)方法一.直接用a标签的href+数据库中文件地址,即可下载.缺点:word excel是直接弹框下载,对于image txt 等文件的下载方式是直接在新页面打开. ...
- SecurityCRT输出日志重定向
使用CRT进行抓取log,因为工具本省缓冲区有限,导致,刷屏特别快,可能会错过一些log,可以对CRT的log进行增加输出源,或者说将输出到控制台的log再输出到本地文件中: 文件->点击(勾选 ...
- 关于PowerDesigner
1. PowerDesigner将所有的小写改为大写:Tools->Model Option->左侧菜单中“Naming conversion”->Column->Code – ...