【模板】字典树Trie

Trie T r i e 是解决一类字符串查找问题的利器,当然有些题目需要Trie支持的操作有很多,这里我只给出能够支持以下操作的 Trie T r i e :
1.向Trie插入一个字符串
2.在Trie中查找一个字符串是否存在
普通的 Trie T r i e 有两种写法,一种是所有字符开一个儿子结点,另一种是使用左孩子右兄弟法。当然还有压缩Trie树,但目前不在我们讨论的范围之内。

对于每个结点,给每个字符都开一个儿子的存储方式

先来说说优点,应该很明显吧,就是查找迅速,只要 O(len) O ( l e n ) 就可以完成两个操作,但是当字符集特别大,字符串总数又比较少的时候,就会被轻易地卡掉空间。。。

Getkey

int key(char ch) {
        return ch - 'a';//有多种形式,具体情况具体分析
    }

插入操作

void insert(char *word) {
        Trie *node = this;
        char *p = word;//一个指针代替word
        while (*p) {
            int id = key(*p++); //找到*p对应的字符
            if (node->son[id] == NULL) //没有后继就新开
                node->son[id] = new Trie();
            node = node->son[id];
        }
        node->finished = true; //finished标记
    }

查询操作

bool search(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            node = node->son[key(*p++)];
            if (node == NULL) return false;
        }
        return node->finished;
    }

完整代码

struct Trie {
    static const int MAXSIZE = 26;
    Trie *son[MAXSIZE];
    bool finished;
    Trie() { 
        finished = false;
        memset(son, 0, sizeof son);
    }
    int key(char ch) {
        return ch - 'a';
    }
    void insert(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            int id = key(*p++);
            if (node->son[id] == NULL) 
                node->son[id] = new Trie();
            node = node->son[id];
        }
        node->finished = true;
    }
    bool search(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            node = node->son[key(*p++)];
            if (node == NULL) return false;
        }
        return node->finished;
    }
};

左孩子右兄弟表示法

优点是当字符集较大,字符串总数较少时可以减少空间开销,但是当每个结点的后继都是满的时候速度回比较慢。

插入操作

void insert(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            if (node->son == NULL) { //没有儿子直接新开
                node->son = new Trie(*p);
                node = node->son;
            }
            else { //有儿子需要遍历所有儿子列表
                Trie *next = node->son;
                while (next->letter != *p && next->brother) //遍历结点兄弟
                    next = next->brother;
                if (next->letter != *p) { //没有结点就新开
                    next = new Trie(*p);
                    node->son->brother = next;
                }
                node = next;
            }
            *p++;
        }
        node->finished = true; //尾部标记
    }

查找操作

bool search(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            if (node->son == NULL) return false;
            Trie *next = node->son;
            while (next->letter != *p && next->brother)
                next = next->brother;
            if (next->letter != *p) 
                return false;
            node = next;
            if (node == NULL) return false;
        }
        return node->finished;
    }

完整代码

struct Trie {
    static const int MAXSIZE = 26;
    char letter;
    Trie *son, *brother;
    bool finished;
    Trie() { 
        letter = '\0';
        finished = false;
        son = brother = NULL;
    }
    Trie(char letter) : letter(letter) {
        finished = false;
        son = brother = NULL;
    }
    void insert(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            if (node->son == NULL) {
                node->son = new Trie(*p);
                node = node->son;
            }
            else {
                Trie *next = node->son;
                while (next->letter != *p && next->brother)
                    next = next->brother;
                if (next->letter != *p) {
                    next = new Trie(*p);
                    node->son->brother = next;
                }
                node = next;
            }
            *p++;
        }
        node->finished = true;
    }
    bool search(char *word) {
        Trie *node = this;
        char *p = word;
        while (*p) {
            if (node->son == NULL) return false;
            Trie *next = node->son;
            while (next->letter != *p && next->brother)
                next = next->brother;
            if (next->letter != *p) 
                return false;
            node = next;
            if (node == NULL) return false;
        }
        return node->finished;
    }
};

总之两种方法各有优劣,具体情况还是要看题目。

你可能感兴趣的:(Struct,Trie)