trie树

文章内容来自
Trie树:应用于统计和排序
Trie树

  • trie树又称:字典树、单词查找树、前缀树等,总之是一种树状结构

  • 实现形式,一幅图就能够说明,如下图所示


    QQ截图20140907005657.jpg

    对于英文字符串,其每个节点包括26个next指针,每个指针对应一个字母,即每一条边为一个字母,同时每个节点包括一个标识,表征从根节点到该节点的边是否组成了一个单词。其节点结构体如下

const int NUM = 26;
struct trieNode
{
    bool isStr;
    trieNode *next[NUM];
};
  • 基本操作:查找、插入、删除
class trie
{
private: trieNode * root;
         int strNum;
public:  bool insert(char *str);
         bool query(char *str);     
         void del(trieNode *root);              //删除整棵树
         int getCount(){return strNum;}
         trie():root(new trieNode()),strNum(0){}
         ~trie(){ del(root); }
};

假设存在字符串str,Trie树的根结点为root。i=0,p=root。
1.插入
1)取str[i],判断p->next[str[i]-'a']是否为空,若为空,则建立结点temp,并将p->next[str[i]-‘a’]指向temp,然后p指向temp;
若不为空,则p=p->next[str[i]-'a'];
2)i++,继续取str[i],循环1)中的操作,直到遇到结束符'\0',此时将当前结点p中的isStr置为true。

bool trie::insert(char *str)
{
    if (str == NULL)
        return false;
    trieNode * p = root;
    while(*str != '\0')
    {
        if (p->next[(*str)-'a'] == NULL)
        {
            p->next[(*str)-'a'] = new trieNode();
            p = p->next[(*str)-'a'];
        }
        else
            p = p->next[(*str)-'a'];
        str++;
    }
    if (p->isStr)
        return false;       //已存在这个单词
    else
    {
        p->isStr = true;
        strNum++;
        return true;
    }
}

2.查找
1)取str[i],判断判断p->next[str[i]-‘a’]是否为空,若为空,则返回false;若不为空,则p=p->next[str[i]-'a'],继续取字符。
2)重复1)中的操作直到遇到结束符'\0',若当前结点p不为空并且isStr为true,则返回true,否则返回false。

bool trie::query(char *str)
{
    if (str == NULL)
        return false;
    trieNode * p = root;
    while (*str != '\0')
    {
        if (p->next[(*str)-'a'] == NULL)
            return false;
        else
            p = p->next[(*str)-'a'];
        str++;
    }
    return p->isStr;    
}

3.删除
删除可以以递归的形式进行删除。

void trie::del(trieNode *root)
{
    if (root == NULL)
        return;
    for (int i = 0; i < NUM; i++)
    {
        if (root->next[i]!=NULL)
            del(root->next[i]);
    }
    if (root!=trie::root)
        delete root;    
}

简单的验证程序如下

#include <iostream>
#include <string>
#include "trie.h"
using namespace std;
int main()
{
    trie wordtree;
    string str;
    cout<<"输入一个句子:";
    do 
    {
        cin>>str;
        wordtree.insert(const_cast<char *>(str.c_str()));
    } while (str!="exit");
    do 
    {
        cout<<"输入要查找的单词";
        cin>>str;
        if(wordtree.query(const_cast<char *>(str.c_str())))
            cout<<str<<" is exsit"<<endl;
        else
            cout<<str<<" is not exsit"<<endl;
    } while (str!="exit");
    system("pause");    
}
  • 用处:统计和排序大量的字符串、文本词频统计等
    字符串检索,词频统计,搜索引擎的热门查询,事先将已知的一些字符串(字典)的有关信息保存到trie树里,查找另外一些未知字符串是否出现过或者出现频率
    举例:
    1)有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16字节,内存限制大小是1M。返回频数最高的100个词。
    2)给出N 个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。
    3)给出一个词典,其中的单词为不良单词。单词均为小写字母。再给出一段文本,文本的每一行也由小写字母构成。判断文本中是否含有任何不良单词。例如,若rob是不良单词,那么文本problem含有不良单词。
    4)1000万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串
    5)寻找热门查询:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节。假设目前有一千万个记录,这些查询串的重复读比较高,虽然总数是1千万,但是如果去除重复和,不超过3百万个。一个查询串的重复度越高,说明查询它的用户越多,也就越热门。请你统计最热门的10个查询串,要求使用的内存不能超过1G。

字符串最长公共前缀,Trie树利用多个字符串的公共前缀来节省存储空间,反之,当我们把大量字符串存储到一棵trie树上时,我们可以快速得到某些字符串的公共前缀
举例:

  1. 给出N 个小写英文字母串,以及Q 个询问,即询问某两个串的最长公共前缀的长度是多少. 解决方案:
    首先对所有的串建立其对应的字母树。此时发现,对于两个串的最长公共前缀的长度即它们所在结点的公共祖先个数,于是,问题就转化为了离线 (Offline)的最近公共祖先(Least Common Ancestor,简称LCA)问题。
    而最近公共祖先问题同样是一个经典问题,可以用下面几种方法:1. 利用并查集(Disjoint Set),可以采用采用经典的Tarjan 算法; 2. 求出字母树的欧拉序列(Euler Sequence )后,就可以转为经典的最小值查询(Range Minimum Query,简称RMQ)问题了;

排序,Trie树是一棵多叉树,只要先序遍历整棵树,输出相应的字符串便是按字典序排序的结果
举例:
给你N 个互不相同的仅由一个单词构成的英文名,让你将它们按字典序从小到大排序输出。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容