zoukankan      html  css  js  c++  java
  • CLRS 思考题 12-2 利用字典树处理字符串排序

    Description


      给定两个串a = 'a0a1……ap'和b = 'b0b1……bq',其中每一个 ai 和每一个 bj 都属于某个有序字符集,如果下面两条规则之一成立,则说串a按字典序小于串b: 

         1)存在一个整数 j,0 <= j <= min(p,q),使得ai = bi,i = 0,1,……,j-1,且aj < bj; 

        2)p < q,且ai = bi,对所有的i = 0,1,……,p 成立 

      例如,如果a和b是位串,则根据规则1)(设j=3),有10100 < 10110;根据规则2),有10100 < 101000。这与英语字典中的排序很相似。

      下图显示的是基数树(radix tree)数据结构,其中存储了位串1011、10、011、100和0。当查找某个关键字a = a0a1……ap时,在深度为i的一个结点处,若ai = 0则向左转;若ai = 1则向右转。设S为一组不同的二进制串构成的集合,各串的长度之和为n。说明如何利用基数树,在O(n)时间内对S按字典序排序。例如,对图12-5中每个结点的关键字,排序的输出应该是序列0、011、10、100、1011

              

    思路


      大量字符串统计问题通常都是用 trie 树 or 哈希表,但是 哈希表排序的话 O(n) 有点难,所以选择 trie 树。

      从题目的 hint 中很容易知道用 trie 树 + 前序遍历即可实现字典排序。其中 insert 的时间为 O(n),print 的时间为 O(n),所以算法的时间复杂度为 O(n)

       在ASCLL码与字符的问题上 WA 了一发,C++ 没有数组边界检查导致查了很久,下次建 trie 树需要多多注意这个点。

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    //利用trie存储位串
    struct Node{
        Node *next[2]; //一个结点的next结点有两种可能
        bool flag;
        string str;
        int cnt;
        Node() {
            for (int i = 0; i <2; i++) next[i] = NULL;
            flag = false;
            str = "";
            cnt = 0;
        }
    };
    Node *root;
    
    void initTrie(){
        root = new Node();
    }
    
    void insert(const string& s){
        int len = s.size();
        Node *now = root;
    
        for (int i = 0; i < len; i++) {
            int to = s[i] - '0'; //需要依据ASCLL码做减法,否则隐式转换to将等于48/49
            if (!now->next[to]) now->next[to] = new Node();
            now = now->next[to];
        }
        if (now->flag) {
            ++now->cnt;
            return;
        }
        else {
            now->flag = true;
            now->str = s;
            now->cnt = 1;
        }
    }
    
    void preOderPrint (Node *now) {
        if (!now) return;
        if(now->flag) {
            for (int i = 0; i < now->cnt; i++)
                cout << now->str << endl;
        }
        preOderPrint(now->next[0]);
        preOderPrint(now->next[1]);
    }
    
    int main(void) {
        initTrie();
        string tmp = "";
        while(cin >> tmp) {
            insert(tmp);
        }
        preOderPrint(root);
        return 0;
    }
    View Code

      

    ————全心全意投入,拒绝画地为牢
  • 相关阅读:
    BZOJ4923 K小值查询(splay)
    BZOJ4919 大根堆(动态规划+treap+启发式合并)
    BZOJ4922 Karp-de-Chant Number(贪心+动态规划)
    BZOJ4915 简单的数字题
    BZOJ4921 互质序列
    BZOJ4898/5367 Apio2017商旅(分数规划+floyd)
    BZOJ4899 记忆的轮廓(概率期望+动态规划+决策单调性)
    Educational Codeforces Round 55 Div. 2 翻车记
    166. Fraction to Recurring Decimal
    390. Elimination Game
  • 原文地址:https://www.cnblogs.com/Bw98blogs/p/8529349.html
Copyright © 2011-2022 走看看