字典树简介

来源:互联网 发布:什么软件买火车票便宜 编辑:程序博客网 时间:2024/06/15 18:08

Trie,

又称字典树、单词查找树,是一种树形结构,用于保存大量的字符串。它的优点是:利用字符串的公共前缀来节约存储空间。
相对来说,Trie树是一种比较简单的数据结构.理解起来比较简单,正所谓简单的东西也得付出代价.故Trie树也有它的缺点,Trie树的内存消耗非常大.当然,或许用左儿子右兄弟的方法建树的话,可能会好点.

核心思想就是空间换时间。

 

基本性质·····

搜索字典项目的方法····

查找效率分析····

相关练习······

字典树的应用····

实现方法······


 

一、基本性质

1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
3. 每个节点的所有子节点包含的字符都不相同。

其基本操作有:查找插入和删除,当然删除操作比较少见.我在这里只是实现了对整个树的删除操作,至于单个word的删除操作也很简单.

 

二、搜索字典项目的方法为

(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索;

(3)在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。

(4)迭代过程……

(5)在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。
    其他操作类似处理.

 

三、查找效率分析

 

在trie树中查找一个关键字的时间和树中包含的结点数无关,而取决于组成关键字的字符数。(对比:二叉查找树的查找时间和树中的结点数有关O(log2n)。)
如果要查找的关键字可以分解成字符序列且不是很长,利用trie树查找速度优于二叉查找树。
若关键字长度最大是5,则利用trie树,利用5次比较可以从265=11881376个可能的关键字中检索出指定的关键字。而利用二叉查找树至少要进行log2265=23.5次比较。

  

  

四、相关练习

 

HDOJ-1075     What Are You Talking About
HDOJ-1251     统计难题
HDOJ-1298     T9
HDOJ-1800    Flying to the Mars
ZOJ-1109      Language of FatMouse

 

五、字典树的应用 

 

1.字典树在串的快速检索中的应用。

 

给出N个单词组成的熟词表,以及一篇全用小写英文书写的文章,请你按最早出现的顺序写出所有不在熟词表中的生词。 

在这道题中,我们可以用数组枚举,用哈希,用字典树,先把熟词建一棵树,然后读入文章进行比较,这种方法效率是比较高的。

 

2. 字典树在“串”排序方面的应用

 

给定N个互不相同的仅由一个单词构成的英文名,让你将他们按字典序从小到大输出

用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序。对这棵树进行先序遍历即可

 

3. 字典树在最长公共前缀问题的应用

 

对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,于是,问题就转化为最近公共祖先问题。

 

 

>>>>>>>>

六、实现方法

 

实现一般分为两种,一种是结点类型包含存放字符值的char类型和26个指向结点孩子的结构体指针类型,另一种则是用整型值n代表该字符出现的次数而非用char存放元素的值。

 

第一种:

 

#include"stdio.h"
#include "stdlib.h"
#include"string.h"

#define BRANCH_COUNT26                                                                                            

typedef struct Trie_Node
{
    char*data;
    structTrie_Node *branch[BRANCH_COUNT];

}*Node;


int Insert(Noderoot,char *string,char *data) 
{
   int branch;
   int result;

   Node location=root;
   while(*string!='\0'&&location!=NULL)
    {
       if(*string>='a'||*string<='z')branch=*string-'a';
       elseif(*string>='A'||*string<='Z')branch=*string='A';
       else
           return-1;      

       if(location->branch[branch]==NULL)
       {
           location->branch[branch]=(Node)malloc(sizeof(structTrie_Node));
       }
       location=location->branch[branch];

       string++;
    }

   if(location->data!=NULL)result=0;
    else
    {
      location->data=(char *)malloc(sizeof(char));
      strcpy(location->data,data);
    }

   return result;
}

int Search(Node root,char*string,char *search_result)
{
    intbranch;


   Node location=root;
   while(location!=NULL&&*string!='\0')
    {
       if(*string>='a'||*string<='z')
           branch=*string-'a';
       elseif(*string>='A'||*string<='Z')
           branch=*string-'A';
       else
           return -1; 

       location=location->branch[branch];
       string++;
    }

   if(location!=NULL&&location->data!=NULL)
    {
      strcpy(search_result,location->data);
      return 1;
    }
    else
       return0;    

 

第二种:这一种是用数组来分配空间的,话说malloc太慢了。。

 

#define MAX    26//字符集大小

typedef struct TrieNode
{
    int nCount;//记录该字符出现次数
    structTrieNode *next[MAX];
}TrieNode;

 

TrieNode Memory[1000000];
int allocp = 0;

 


void InitTrieRoot(TrieNode**pRoot)
{
    *pRoot =NULL;
}

 


TrieNode *CreateTrieNode()
{
    int i;
    TrieNode*p;

    p =&Memory[allocp++];
   p->nCount = 1;
    for(i = 0 ;i < MAX ; i++)
    {
       p->next[i] = NULL;
    }

    returnp;
}

 


void InsertTrie(TrieNode **pRoot ,char *s)
{
    int i ,k;
    TrieNode*p;

    if(!(p =*pRoot))
    {
       p = *pRoot = CreateTrieNode();
    }
    i = 0;
   while(s[i])
    {
       k = s[i++] - 'a'; //确定branch
       if(p->next[k])
           p->next[k]->nCount++;
       else
           p->next[k] = CreateTrieNode();
       p = p->next[k];
    }
}

 

//查找
int SearchTrie(TrieNode **pRoot , char *s)
{
    TrieNode*p;
    int i ,k;

    if(!(p =*pRoot))
    {
       return 0;
    }
    i = 0;
   while(s[i])
    {
       k = s[i++] - 'a';
       if(p->next[k] ==NULL)    return0;
       p = p->next[k];
    }
    returnp->nCount;
}

 

 

原创粉丝点击