zoukankan      html  css  js  c++  java
  • 基数树

    原理参考《算法导论》

    注:代码设定,支持索引的位数最大是32位,当然可以修改让其支持64和32位的索引

    首先定义一些常量(修改此处的常量,让其支持64位的索引)

    #define MAX_BITS 0x80000000 
    #define INT_BITS 32  //32位下的int

    然后定义一个基数树类

    template <typename T, int bits, int height>//bits代表索引的位数,height代表高度, 暂时支持32位
    class radix_tree {
    public:
        struct _Nodetype;
        typedef union _Autotype {
            _Nodetype *DeepNodes;//下一层
            T *slots;
        }Autotype;
        typedef struct _Nodetype {
            _Nodetype() { autov.DeepNodes = NULL; }
            _Nodetype(_Nodetype *node) { autov.DeepNodes = node; }
            _Nodetype(T *s) { autov.slots = s; }
            Autotype autov;
        }Nodetype, *pNodetype;
        radix_tree() {
            root = new Nodetype((pNodetype)NULL);
        }
        ~radix_tree() {
            
        }
        void radix_insert(int index, T key);//T类型应用时是指针,指向对象
        T radix_search(int index);
        void radix_delete(int index);//惰性删除
        void radix_empty();//未实现,建议采用双线程池,这样方便这个函数回收内存
    private:
        int radix_mask(int h);
        int radix_index(const int index, int h);
        pNodetype root;
    };

    关于类成员实现

    radix_mask成员负责根据所在树的层数,动态生成掩码。比如本例中使用18位的索引值,然后定义树高为3,那么在第一层的掩码是0x3F000,第二层的掩码是0xFC0,第三层的掩码是0x3F

    template <typename T, int bits, int height>
    int radix_tree<T, bits, height>::radix_mask(int h) {//1到height层
        int slotbits = bits / height, skipbits = INT_BITS - bits + (h - 1)*slotbits, tMask = 0;
        if (h<1 || h>height) return -1;
        while (skipbits < INT_BITS - bits + slotbits*h) {
            tMask |= (MAX_BITS >> skipbits);
            skipbits++;
        }
        return tMask;
    }

    radix_index成员负责提取索引中的偏移值。比如18位索引,第一层的时候,掩码为0x3F000,那么通过此掩码提取出来的6位偏移值,用于查找第一层的查找。其余层数以此类推。

    template <typename T, int bits, int height>
    int radix_tree<T, bits, height>::radix_index(const int index, int h) {
        int slotbits = bits / height, lowerMask = radix_mask(height), mask;
        if (h<1 || h>height) return -1;
        mask = radix_mask(h);//更新mask
        return (index & mask) >> (bits / height*(height - h)) & lowerMask;
    }

    radix_insert成员通过提供的索引值,插入到指定位置

    template <typename T, int bits, int height>
    void radix_tree<T, bits, height>::radix_insert(int index, T key) {
        pNodetype node = root;
        for (int tree_h = 1; tree_h < height; tree_h++) {//目录,没有数据
            if (node->autov.DeepNodes == NULL)
                node->autov.DeepNodes = new Nodetype[pow(2, bits / height)];
            node = &node->autov.DeepNodes[radix_index(index, tree_h)];
        }
        //录入数据
        if (node->autov.slots==NULL)
            node->autov.slots = new T[pow(2, bits / height)];
        node->autov.slots[radix_index(index, height)] = key;
    }

    radix_search成员,原理和radix_insert成员一样,但是不负责分配,只负责查找

    template <typename T, int bits, int height>
    T radix_tree<T, bits, height>::radix_search(int index) {
        pNodetype node = root;
        for (int tree_h = 1; tree_h < height; tree_h++) {
            if (node->autov.DeepNodes == NULL)
                return -1;
            node = &node->autov.DeepNodes[radix_index(index, tree_h)];
        }
        //查询数据
        if (node == root || node->autov.slots == NULL)
            return -1;
        return node->autov.slots[radix_index(index, height)];
    }

    radix_delete成员,采用惰性删除,仅将找到的节点数据变为-1,不删除节点,因为实际应用中,每个数据都是指针,指向对应对象,所以不存在负数

    template <typename T, int bits, int height>
    void radix_tree<T, bits, height>::radix_delete(int index) {
        if (radix_search(index))
            radix_insert(index, -1);
    }

    radix_empty成员,删除所有节点以及数据

    template <typename T, int bits, int height>
    void radix_tree<T, bits, height>::radix_empty() {
        //建议用线程池分配所有,这样方便释放
    //这里未实现,思路是利用线程池,用来分配节点。这样释放时,整体释放线程池;否则比如18位的索引,必须得搜索0x0-0xffff范围的所有索引,然后逐一删除,这样很浪费时间。
    }

    分离定义模版类一定要提前实例化

    template class radix_tree<int, 18, 3>;//index是18位的整数,3是树高

    所有代码均经测试,结果正确。

  • 相关阅读:
    pat甲级 1155 Heap Paths (30 分)
    pat甲级 1152 Google Recruitment (20 分)
    蓝桥杯 基础练习 特殊回文数
    蓝桥杯 基础练习 十进制转十六进制
    蓝桥杯 基础练习 十六进制转十进制
    蓝桥杯 基础练习 十六进制转八进制
    51nod 1347 旋转字符串
    蓝桥杯 入门训练 圆的面积
    蓝桥杯 入门训练 Fibonacci数列
    链表相关
  • 原文地址:https://www.cnblogs.com/dalgleish/p/8983552.html
Copyright © 2011-2022 走看看