hdu1251(字典Trie树)

来源:互联网 发布:sql 多个结果合并 编辑:程序博客网 时间:2024/06/04 23:53

在空行之前给出多个单词,之后输入一个空行,之后给出多个前缀,问可以是是几个单词的前缀

一共有三种方法

给出n个固定的单词后

给出一行行的字符,判断这些字符是否为n个单词的前缀,输出是几个单词的前缀

使用字典树的方法

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



第一种是链表的方法,然而内存超限,还没有找到解决的办法

用链表做比较好理解,从根节点开始有26个孩子,插入的时候:

void trieInsert(char* str,trie root)

{

    trie node=root;

    char *p=str;

    int id;

    while(*p)

    {

        id=*p-'a';

        if(node->next[id]==NULL)

            node->next[id]=creatTrie();

        node=node->next[id];

        node->count++;

        ++p;

    }

    //node->exist=true;

}

一个字母一个字母的开始遍历

假设第一个字母为b,如果孩子中跟node->next[b-'a']如果不存在,那么creeatTrie()创建孩子结构体,之后node=node->next[b-'a'],并且node-.>count++,count用来记录该孩子节点出现的次数。

然后查找

之后输出

//

//  main.cpp

//  3.A

//

//  Created by Mr.Xue on 17/7/12.

//  Copyright © 2017 Mr.Xue. All rights reserved.

//


#include <iostream>

#include <string.h>

#include <iostream>

usingnamespacestd;

typedefstruct node

{

    int count;

    structnode *next[26];

    //bool exist;

}TrieNode,*trie;


TrieNode* creatTrie()

{

    TrieNode* node=(TrieNode*)malloc(sizeof(TrieNode));

    node->count=0;

    memset(node->next,0,sizeof(node->next));

    //node->exist=false;

    return node;

}

void trieInsert(char* str,trie root)

{

    trie node=root;

    char *p=str;

    int id;

    while(*p)

    {

        id=*p-'a';

        if(node->next[id]==NULL)

            node->next[id]=creatTrie();

        node=node->next[id];

        node->count++;

        ++p;

    }

    //node->exist=true;

}

int find(char* str,trie root)

{

    trie node=root;

    char *p=str;

    int id;

    while(*p)

    {

        id=*p-'a';

        node=node->next[id];

        ++p;

        if(node==NULL)

            return0;

    }

    return node->count;

}

int main()

{

    trie root=creatTrie();

    char str[10];

    while(gets(str))

    {

        if(strlen(str)==0)

            break;

        trieInsert(str,root);

    }

    while(~scanf("%s",str))

    {

        if(strlen(str)>10)

            printf("0\n");

        else

        {

            int m=find(str,root);

            printf("%d\n",m);

        }

        

    }

    return0;

}

/*

banana

band

bee

absolute

acm


ba

b

band

abc

*/

/***********************************************************************************************************************/

另一种方法是用数组ch[i][j]来保存,这个ac了


i为节点的编号,根结点为0,比如输入的第一个字符串为avx,那么a的编号为2,v为3,以此来记录,这个编号sz为全局变量,j就是每一个字母-'a'后的数字了

void insert(char *s)
{
    int u=0,n=strlen(s);
    for(int i=0;i<n;i++)
    {
        int c=idx(s[i]);
        if(!ch[u][c])
        {
            memset(ch[sz],0,sizeof(ch[sz]));//
            val[sz]=0;
            ch[u][c]=sz++;//
        }
        u=ch[u][c];
        val[u]++;
    }
}

ch[u][c]的值为下一个结点的编号

val记录的是当前编号的结点所代表的字符串出现的字数

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;

int ch[500000][26];
int val[500000];
int sz=1;


int idx(char c)
{
    return c-'a';
}


void insert(char *s)
{
    int u=0,n=strlen(s);
    for(int i=0;i<n;i++)
    {
        int c=idx(s[i]);
        if(!ch[u][c])
        {
            memset(ch[sz],0,sizeof(ch[sz]));//
            val[sz]=0;//中间节点的附加信息为0
            ch[u][c]=sz++;//构建新的节点
        }
        u=ch[u][c];
        val[u]++;
    }
}
int find(char* s)
{
    int u=0,n=strlen(s);
    for(int i=0;i<n;i++)
    {
        int c=idx(s[i]);
        if(ch[u][c]==0)
            return 0;
        u=ch[u][c];
    }
    return val[u];
}
int main()
{
    char str[10];
    memset(ch[0],0,sizeof(ch[0]));
    memset(val,0,sizeof(val));
    while(gets(str))
    {
        if(strlen(str)==0)
            break;
        insert(str);
    }
    while(~scanf("%s",str))
    {
        if(strlen(str)>10)
            printf("0\n");
        else
        {
            int m=find(str);
            printf("%d\n",m);
        }


    }
    return 0;
}
/*
banana
band
bee
absolute
acm


ba
b
band

abc

*/

/*******************************************************************************************/

第三种方法是学长演示的很简单。。。

利用map<string,int>直接计数前缀就可以了

#include<iostream>

#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<cmath>

#include<algorithm>

#include<map>

using namespacestd;

map<string,int>mp;

char ch[12];

int main()

{

    while(gets(ch))

    {

        int n=strlen(ch);

        if(n==0)

            break;

        for(int i=n;i>=0;i--)

        {

            ch[i]='\0';

            mp[ch]++;

        }

    }

    while(~scanf("%s",ch))

    {

        printf("%d\n",mp[ch]);

    }

    return0;

}





原创粉丝点击