您的位置:首页 > 其它

POJ-3630-Phone List-Trie树(键树、数字查找树、基数树)

2011-02-06 15:49 357 查看
先看下键树的有关基础知识。

键树中的每个结点不是包含一个关键字,而是只包含组成关键字的符号。例如,若关键字是数值,则结点中只包含一个数位;若关键字是单词,则结点中只包含一个字母字符。这种树会给某种类型关键字的表的查找带来方便。

通常用树的多重链表表示键树。下图是一个例子。



在这个例子中,每个关键字均由a-z这26个小写字母组成。为了表示这些关键字,每上结点均有一个大小为26的指针数组。上图中,一共表示了"abc","d","da","dda"这四个字符串。

键树具有以下性质:

1)关键字的符号的种数决定了指针数组branch的大小,如上例的大小为26;

2)branch数组的下标index代表该符号相对'a'对位置;

3)在结点中采用一个bool变量,确定是否已构成了一个关键字;

4)插入、查找的复杂度均为O(len),len为关键字符串的长度。

然后解答POJ3630题。

题意:给出一组电话号码,判断其中一个号码是否另一个号码的前缀。

分析:具体看代码注释。

代码:

#include <stdio.h>
#include <string.h>

#define MAX_NODE_SIZE 100000 //最大结点容量,题意最多有10000个号,每个号最多有10位
#define MAX_NUM_SIZE 10 //每个号码串最大长度
#define MAX_DIGIT 10 //每个号码串由0~9的数字组成

struct node {
    bool isEnd; //表示是否到达了一个串的结束处
    struct node* branch[MAX_DIGIT]; //branch指针数组,表示该位置的符号
};

struct node nodesPool[MAX_NODE_SIZE]; //由于用new会超时,故在程序一开始便申请了静态数组
struct node *root; //trie树的根
int nodeNum; //使用nodesPool数组时用到

/*每次运行一个测试用例前均应初始化*/
void init() {
    for(int i = 0; i < MAX_NODE_SIZE; i++) {
        nodesPool[i].isEnd = false;
        for(int j = 0; j < MAX_DIGIT; j++) {
            nodesPool[i].branch[j] = NULL;
        }
    }

    root = &nodesPool[0];
    nodeNum = 1;
}

/*插入一个电话号码。
 *在插入过程中,并判断:
 *1)在trie树中是否已有一个串为新插入串的前缀;
 *2)该新插入的串是否为trie树中某个串的前缀。
 *若满足以上两种情况,返回false,表示不插入;否则正确插入,返回true
 *O(len)
 */
bool insert(char *phoneStr) {
    int len = strlen(phoneStr);

    struct node *location = root;
    for(int i = 0; i < len; i++) {
        int index = phoneStr[i] - '0'; //下标

        /*判断情况2),在i指向串最后一个字符时进行判断*/
        if(i == len - 1 && location->branch[index] != NULL) {
            return false;
        }

        if(location->branch[index] == NULL) {
            location->branch[index] = &nodesPool[nodeNum];
            nodeNum++;
        } else {
            /*判断情况1)*/
            if(location->branch[index]->isEnd)
                return false;
        }

        /*不断向前*/
        location = location->branch[index];
    }
    location->isEnd = true; //到达该结点,结束。注意:对于每个串,若串长度为n,则需n+1个结点表示

    return true;
}

int main() {
    int nCases;
    scanf("%d", &nCases);
    while(nCases--) {
        init();

        int n;
        scanf("%d", &n);
        bool isConsistent = true;
        while(n--) {
            char phoneStr[MAX_NUM_SIZE + 2];
            scanf("%s", phoneStr);

            /*即使已能判断出不能正确插入,还得继续循环,因为还有数输入要读取*/
            if(!insert(phoneStr)) {
                isConsistent = false;
            }
        }

        if(isConsistent)
            printf("YES/n");
        else
            printf("NO/n");
    }

    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: