码迷,mamicode.com
首页 > 其他好文 > 详细

POJ3630-Phone List-(字典树)

时间:2019-11-16 12:51:30      阅读:70      评论:0      收藏:0      [点我收藏+]

标签:优点   color   范围   系统   ack   def   list   大量   time   

一直没有学字典树,听起来很唬人,闲来无事找一道入门题做做。

字典树:又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

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

搜索字典项目的方法为:
(1) 从根结点开始一次搜索;
(2) 取得要查找关键词的第一个字母,并根据该字母选择对应的子树并转到该子树继续进行检索
(3) 在相应的子树上,取得要查找关键词的第二个字母,并进一步选择对应的子树进行检索。
(4) 迭代过程……
(5) 在某个结点处,关键词的所有字母已被取出,则读取附在该结点上的信息,即完成查找。

用一张图表示会比较直观,至于实现过程就是编码能力的问题了。

技术图片

http://poj.org/problem?id=3630

题意:给出好多不超过10位的电话号码,如果存在某一个电话号码(如911)是其他电话号码(91110086)的前缀就会导致后者无法拨通,问是否全部电话号码都能拨通。

思路:开一个tree[maxx][10]数组模拟树的节点搜寻,也就是用数组解决指针指向问题,第二维度的下标是0-9这10个数字,存储的内容是下一次跳向的行数rt。对于当前数字x,通过tree[rt][x]判断是否存在或者重新标记。并使用一个num数组来标记一个电话号码的终点,判断是不是其他电话号码的前缀。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define inf 0x3f3f3f3f
const double pi=3.1415926;
using namespace std;

int t,n;
int tree[100086][20];
int num[100086];
int cnt;
bool flag=true;

void my_insert(string s)
{
    int rt=0;///当前节点,最后变成字典树的叶子节点
    int len=s.size();
    for(int i=0;i<len;i++)
    {
        int x=s[i]-0;///用数字表示就不用一直写引号
        if(tree[rt][x]==0)
            tree[rt][x]=cnt++;///cnt是全局累计变量,下一行又作为rt,所以tree数组的行至少要开到n*10
        rt=tree[rt][x];
        if(num[rt])///判断到当前位时,是否存在前缀的电话号码,因为每到一个叶子节点就会用num数组标记
            flag=false;
    }
    num[rt]=1;
    for(int i=0;i<10;i++)///判断当前字符串是不是别人的前缀
    {
        if(tree[rt][i])
        {
            flag=false;
            break;
        }
    }
}

int main()///poj3630
{
    cin>>t;
    while(t--)
    {
        memset(tree,0,sizeof(tree));
        memset(num,0,sizeof(num));
        cnt=1;
        flag=true;
        cin>>n;
        string s;
        for(int i=1;i<=n;i++)
        {
            cin>>s;///对于每个电话号码插入到字典树之中
            if(flag) ///如果还没有判断出公共前缀才插入,减少时间
                my_insert(s);
        }
        if(flag)
            cout<<"YES"<<endl;
        else
            cout<<"NO"<<endl;
    }
    return 0;
}

例如插入第一个911654的电话号码,tree数组变动情况如下,横竖下标范围都是0-9

技术图片

再插入一个911,整个tree数组不变,通过查找历史前缀可以找到

再插入一个110,数组变成

技术图片

 

参考:https://blog.csdn.net/qq_41879343/article/details/102501946

POJ3630-Phone List-(字典树)

标签:优点   color   范围   系统   ack   def   list   大量   time   

原文地址:https://www.cnblogs.com/shoulinniao/p/11871036.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!