每日一题9:字典树(一)

百科上对于字典树的定义是:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。其结构如下:
这里写图片描述
今天,就来实现一个简单的字典树,本次实现只包含创建字典树(未考虑排序问题,如果输入的单词资料是排序的,那么创建起来的字典树也是排序的),遍历字典树(仅是将其显示在控制台上),判断一个单词是否存在于字典树三个基本功能。

#include "stdafx.h"
#include <string>
#include <iostream>
#include <fstream>
using namespace std;

定义字典树需要的节点结构。dict_tree节点包含了该字典树包含的单词个数和指向作为单词开头的字母的链表,letter_node节点表示一个字母的节点。每个字母节点b中包含其表示的字母,指示b是否是一个单词最后一个字母的bool值,sib指针指向一个链表,这个链表连同b存储了当前节点的前一个节点a表示的字母后出现所有字母(b,b1,b2,b3…),next指针指向了存储该节点后出现的所有字母的链表的表头c。

struct letter_node
{
    bool IsTerminate;
    char c;
    letter_node* sib;
    letter_node* next;
};

struct dict_tree
{
    int word_count;
    letter_node* head;
};

检查输入单词是否合法。该字典树只接受由大小写字母构成的单词,暂不考虑带有其他符号的合法单词,以后只要修改该函数就可以扩充了。

bool IsLegalWord(const char* word)
{
    int length = strlen(word);
    const char* p = word;
    for (int i = 0; i < length; ++i)
    {
        char c = *p++;
        if(!(c <= 'z' && c >= 'a' || c <= 'Z' && c >= 'A')) return false;
    }
    return true;
}

创建一个新的字母节点。

letter_node* create_letter(const char c)
{
    letter_node *node = new letter_node;
    node->c = c;
    node->IsTerminate = false;
    node->sib = NULL;
    node->next = NULL;
    return node;
}

把一个字母节点添加到合适的位置,如果该字母已经存在,那么简单返回找到的节点就可以了,如果没有找到,新建一个节点,并将它添加到sib链表的末尾。

letter_node* add_letter(letter_node** head,char c)
{
    letter_node *p = *head;
    if(p == NULL)
    {
        p = create_letter(c);
        *head = p;
        return p;
    }
    letter_node *res = p;
    while(res->sib)
    {
        if(res->c == c) return res;
        res = res->sib;
    }
    res->sib = create_letter(c);
    return res->sib;
}

将一个合法的单词加入到字典树中。

bool insert_word(dict_tree **dict,const char * word)
{
    if(!IsLegalWord(word)) return false;
    const char* c = word;
    letter_node* letter = add_letter(&((*dict)->head),*c);
    while(*(++c))
    {
        letter = add_letter(&(letter->next),*c);
    }
    letter->IsTerminate = true;
    ++((*dict)->word_count);
    return true;
}

从文件中读取单词并创建字典树。

dict_tree* create_dict_tree(const char* filename)
{
    dict_tree* root = new dict_tree;
    root->head = NULL;
    root->word_count = 0;
    ifstream input;
    input.open(filename);
    string word;
    while(input>>word)
    {
        insert_word(&root,word.c_str());
    }
    return root;
}

遍历字典树内部调用的函数,prefix表示由到达当前节点之前经过的路径组成的字符串。

void _treverse(letter_node* letter,string &prefix)
{
    if(letter == NULL) return;
    string l = prefix + letter->c; 
    if(letter->IsTerminate) cout<<l<<endl;
    if(letter->next)
    {
        _treverse(letter->next,l);
    }
    if(letter->sib) _treverse(letter->sib,prefix);
}

遍历字典树,开始时没有经过任何几点,所以s = “”。

void treverse(dict_tree* dict)
{
    string s = "";
    _treverse(dict->head,s);
}

在一个sib链表中查找表示指定字母的节点,没有找到则返回空指针。

const letter_node* find_letter(const letter_node* head,char c)
{
    const letter_node *res = head;
    while(res)
    {
        if(res->c == c) return res;
        res = res->sib;
    }
    return NULL;
}

判断一个单词是否在字典树中。

bool IsWordContained(const dict_tree* dict,const char* word)
{
    const char* p = word;
    const letter_node *head = dict->head;
    const letter_node * node;
    while(*p)
    {
        node = find_letter(head,*p);
        if(!node) return false;
        head = node->next;
        ++p;
    }
    if(node->IsTerminate)
        return true;
    return false;
}

测试函数。以圣经中的50个单词作为输入,建立起一个小型的字典树,然后遍历输出字典树中包含的单词,然后在判断两个单词是否存在于字典树之中。

int _tmain(int argc, _TCHAR* argv[])
{
    const char* filename = " test.txt";
    dict_tree* dict = create_dict_tree(filename);
    treverse(dict);
    cout<<dict->word_count<<endl;
    cout<<IsWordContained(dict,"tumors")<<endl;
    cout<<IsWordContained(dict,"tumor")<<endl;
    return 0;
}

输入文件内容如下:

cloudburst
declares
Ahiludin
shame
Dimon
southeast
instinct
orchard
weighs
convened
weight
Jerichoand
drain
Rehob
Rephaiah
tumors
fond
unusual
doorway
entertained
surpassingly
Antioch
convenes
felled
Shoot
bottles
Hegai
provide
commanderinchief
ceremonies
Weigh
sailing
Jaminite
incensethe
Zalmon
Ehud
Tishbite
food
snatch
Between
fool
sternfaced
foot
A
exclaim
intentionally
C
defiled
juice
I

程序运行截图如下:
这里写图片描述
这里写图片描述
输入中只有tumors而没有tumor,运行结果与实际一致。
第一步实现了,以后就可以在此基础上实现统计词频啊、猜测用户输入、检查输入啥的了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值