字典树的C++实现以及应用

基本概念

Trie,字典树,又称单词查找树、前缀树,是一种哈希树的变种。应用于字符串的统计与排序,经常被搜索引擎系统用于文本词频统计。
(后续再补充)
参见:http://www.cnblogs.com/dlutxm/archive/2011/10/26/2225660.html
http://blog.csdn.net/pyang1989/article/details/22834653

1. 统计一组字符串中某前缀出现的次数。

#include
using namespace std;
#define MAX 26
typedef struct node
{
    struct node *next[MAX];
    int num;//该结点出现的次数
}Node;

Node *CreateNew()//创建结点!
{
    Node *p = new node;
    for (int i = 0; inext[i] = NULL;
    }
    p->num = 0;
    return p;
}
void insert_str(char str[], Node *head)
{
    int len = strlen(str);
    Node *t, *p = head;
    for (int i = 0; iint c = str[i] - 'a';
        if (p->next[c] == NULL)
        {
            t = CreateNew();
            p->next[c] = t;
            p->next[c]->num++;
            p = p->next[c];
        }
        else
        {
            p = p->next[c];
            p->num++;
        }
    }
}

int search_str(char str[], Node *head)
{
    Node *p = head;
    int len = strlen(str);
    int count = 0;
    for (int i = 0; iint c = str[i] - 'a';
        if (p->next[c] == NULL)
        {
            cout << "不存在字符串" << endl;
            count = 0;
            return 0;
        }
        else
        {
            p = p->next[c];
            count = p->num;
        }
    }
    return count;
}
int main()
{
    cout << "Hello" << endl;
    Node *head = CreateNew();
    char s[10];

    while (cin >> s, strcmp(s, "quit"))
    {
        insert_str(s, head);
    }
    int c = search_str("ab", head);
    cout << c << endl;
    system("pause");
    return 0;
}

注意对上述代码的理解:
根节点是一个没有实际意义的节点,根节点的子节点才是单词开始的节点。

对节点的描述:一个节点包含经历该节点的单词个数以及它的孩子节点。

typedef struct node
{
    struct node *next[MAX];
    int num;//该节点出现的次数
}Node;

创建一个节点时,把该节点的孩子节点都指向NULL,另外,经历该节点的次数初始化为0。

Node *CreateNew()
{
    Node *p = new node;
    for (int i = 0; inext[i] = NULL;
    }
    p->num = 0;
    return p;
}

插入一个节点,其实就是插入一个单词,一个一个字母插入,访问根节点是用该字母在字母表中的位置来访问的。

void insert_str(char str[], Node *head)
{
    int len = strlen(str);
    Node *t, *p = head;//从根节点开始做插入单词操作
    for (int i = 0; i//遍历单词
    {
        int c = str[i] - 'a';//取字母的位置(在字母表中)
        if (p->next[c] == NULL)//如果父节点没有该孩子节点,就创建!
        {
            t = CreateNew();
            p->next[c] = t;
            p->next[c]->num++;//经历该孩子的个数开始+1。其实就是置1
            p = p->next[c];//父节点换成指向孩子节点
        }
        else//如果有相应的节点,就对节点的遍历次数++。
        {
            p = p->next[c];//
            p->num++;
        }
    }
}

如果输入:abcd abc abcc dac ab
那么和ab匹配的字符串有4个。输出结果是4。

2. 判断一组字符串中是否有一个字符串是另一个字符串的前缀

需要对节点添加一个变量EndFlag。
如果EndFlag=0,表明该节点不是单词的结尾,如果EndFlag=1,表明该节点是单词的结尾。
插入单词程序也需要修改:
针对:
已经有abcd插入abc时,我们只需要在插入abc时,当要插入到最后一个字符时,判断字典树中是否已经有最后一个字符,如果有,就说明存在前缀。

        if (i == len - 1&&p->next[c]!=NULL)//插入最后一个字符串,且它是前面某个单词的后缀(已经有abcd,在插入abc时出现)
        {
            IsPrefix = true;
        }

已经有abc插入abcd时,我们在插入c的过程中,判断该节点是否是字典树中某个单词节点的结尾,如果是,就表明存在前缀。

整体代码如下 :

#include
using namespace std;
#define MAX 26
typedef struct node
{
    struct node *next[MAX];
    int num;//该结点出现的次数
    bool EndFlag;//如果EndFlag=0,表明该节点不是单词的结尾,如果EndFlag=1,表明该节点是单词的结尾
}Node;

Node *CreateNew()
{
    Node *p = new node;
    for (int i = 0; inext[i] = NULL;
    }
    p->num = 0;
    p->EndFlag = 0;
    return p;
}
void insert_str(char str[], Node *head,bool &IsPrefix)//插入功能,并在插入的时候判断当前要插入的单词
//是否是已经插入的单词的前缀或者已经插入的单词是否是该单词的前缀
{
    IsPrefix = false;//初始化不存在
    int len = strlen(str);
    Node *t, *p = head;
    for (int i = 0; iint c = str[i] - 'a';

        if (i == len - 1&&p->next[c]!=NULL)//插入最后一个字符串,且它是前面某个单词的后缀(已经有abcd,在插入abc时出现)
        {
            IsPrefix = true;
        }

        if (p->next[c] == NULL)
        {
            t = CreateNew();
            p->next[c] = t;
            p->next[c]->num++;
            p = p->next[c];
        }
        else
        {
            p = p->next[c];
            p->num++;
            if (p->EndFlag == 1)//某个已经插入的单词的结束标识符(已经有abc,插入abcd时出现)
                IsPrefix = true;
        }
    }
    p->EndFlag = 1;//单词插入完以后,就把当前的节点作为终结节点,EndFlag=1。
}
int main()
{
    cout << "Hello" << endl;
    Node *head = CreateNew();
    char s[10];
    bool IsPrefix = false;
    while (cin >> s, strcmp(s, "quit"))
    {
        insert_str(s, head, IsPrefix);
        if(IsPrefix)
            cout << "存在某个单词是另一个单词的前缀" << endl;
    }
    /*int c = search_str("ab", head);
    cout << c << endl;*/
    system("pause");
    return 0;
}

你可能感兴趣的:(数据结构)