美文网首页
跳表的简单实现

跳表的简单实现

作者: ColeWang | 来源:发表于2017-09-26 10:52 被阅读0次

    跳表(SkipList)是一种检索效率非常高的数据结构,其检索效率经证明与红黑树相当。但是,轮到实现复杂度比较的时候,跳表可就把红黑树、AVL树等结构足足甩出了八条街,以至于LevelDB、Redis等著名的工程项目当中,都采取了跳表的实现方案。
    另外,在并发环境下,SkipList相对于经典树形结构还有一点优势。红黑树在插入和删除的时候可能会有涉及到树中多节点的rebalance操作,而SkipList的变化操作则会更加局部性一些,需要被加锁的节点更少,因此在并发环境下理论上性能会更好一些。
    本质上,跳表是一种添加了多级“索引”的链表,采用了空间换时间的方式,通过随机的方式决定节点的层级数,在节点的层级上均维护该节点的连接节点,即,将连接指针变成了一个数组。

    跳表的简易实现代码如下:

      
    // 跳表实现
      
    #include <stdio.h>  
    #include <assert.h>  
    #include <stdlib.h>  
    #include <time.h>  
      
    /* 跳表节点数据结构 
     * 
     */  
    template <typename TData>  
    struct SkipListNode  
    {  
        TData value; // 节点值  
        SkipListNode<TData>** forward;  // 节点前向指针数组  
    };  
      
    /* 跳表操作的返回码 
     */  
    enum  
    {  
        SKIP_LIST_TMPL_INSERT_NODE_SUCCESS = 0,                        // 插入节点成功  
        SKIP_LIST_TMPL_GET_FREE_SKIP_LIST_NODE_FAILED = 1,     // 获取空闲节点失败  
        SKIP_LIST_TMPL_NODE_EXIST = 2,                         // 节点已经存在  
        SKIP_LIST_TMPL_NODE_NOT_EXIST = 3,                     // 节点不存在于跳表中  
        SKIP_LIST_TMPL_DELETE_NODE_SUCCESS = 4,                   // 删除节点成功  
    };  
      
    /* 跳表 
     * 
     */  
    template <typename TData>  
    class SkipListTmpl  
    {  
    public:  
        /* 初始化跳表 
         */  
        bool InitSkipListTmpl();  
      
        /* 获取一个空闲的跳表节点 
         * @param level  跳表节点的层数 
         * @return 返回NULL表示创建失败,否则返回创建的跳表节点指针 
         */  
        SkipListNode<TData>* GetFreeSkipListNode(int level);  
      
        /* 增加一个跳表节点 
         * @param value 节点值 
         * @return 返回操作码,详情看上面跳表操作返回码的意义 
         */  
        int InsertSkipListNode(const TData &value);  
      
        /* 删除一个跳表节点 
         * @param value 节点值 
         * @return 返回操作码,详情看上面跳表操作返回码的意义 
         */  
        int DeleteSkipListNode(const TData &value);  
      
        /* 查找跳表节点 
         * @param value 节点值 
         * @return 返回NULL表示查找失败,否则返回找到了跳表节点指针 
         */  
        SkipListNode<TData>* SearchSkipListNode(const TData &value);  
      
        /* 遍历处理跳表中所有节点 
         * @param proc 回调的处理函数 
         * @return 返回处理的节点数目 
         */  
        int ProcessEverySkipListNode(void (*proc)(const TData &value));  
      
    private:  
        int level; // 当前跳表的最大层数  
        SkipListNode<TData>* header;  // 跳表头节点  
      
    private:  
        const static int MAX_SKIP_LIST_TMPL_LEVEL = 32;  // 跳表的最大层数  
        const static double SKIP_LIST_TMPL_LEVEL_PROBABILITY;  // i-1层节点属于i层的概率  
      
    private:  
        /* 获取一个节点的层数,层数范围 
         * @return 节点的层数 
         */  
        int GetRandomSkipListNodeLevel();  
    };  
      
    // i-1层节点属于i层的概率  
    template <typename TData>  
    const double SkipListTmpl<TData>::SKIP_LIST_TMPL_LEVEL_PROBABILITY = 0.5;  
      
    /* 创建一个空的跳表节点 
     * @param level  跳表节点的层数 
     * @return 返回NULL表示创建失败,否则返回创建的跳表节点指针 
     */  
    template <typename TData>  
    SkipListNode<TData>* SkipListTmpl<TData>::GetFreeSkipListNode(int level)  
    {  
        // 节点层数范围0  
        assert(level >= 0 && level < MAX_SKIP_LIST_TMPL_LEVEL);  
      
        SkipListNode<TData>* newNode = (SkipListNode<TData>*)malloc(sizeof(SkipListNode<TData>));  
        if (NULL == newNode)  
        {  
            return NULL;  
        }  
          
        // 前向节点初始化为NULL  
        newNode->forward = (SkipListNode<TData> **)malloc(sizeof(SkipListNode<TData>*) * (level+1));  
        if (NULL == newNode->forward)  
        {  
      
            // 申请内存失败那么就归还之前申请的内存  
            free(newNode);  
            return NULL;  
        }  
          
        for (int i = 0; i <= level; ++i)  
        {  
            newNode->forward[i] = NULL;  
        }  
      
        // 创建好的跳表节点  
        return newNode;  
    }  
      
    /* 初始化跳表 
     */  
    template <typename TData>  
    bool SkipListTmpl<TData>::InitSkipListTmpl()  
    {  
        level = 0; // 当前最大层初始为0  
          
        // 头结点的层数为跳表最大层数,这个节点是个冗余节点,增加它是为了方便链表操作  
        header = GetFreeSkipListNode(MAX_SKIP_LIST_TMPL_LEVEL-1);  
      
        // 初始化成功  
        if (header)  
        {  
            return true;  
        }  
      
        // 初始化失败  
        return false;  
    }  
      
    /* 增加一个跳表节点 
     * @param value 节点值 
     * @return 返回操作码,详情看上面跳表操作返回码的意义 
     */  
    template <typename TData>  
    int SkipListTmpl<TData>::InsertSkipListNode(const TData &value)  
    {  
        // 保证跳表已经初始化  
        assert(NULL != header);  
      
        // 首先查找节点的插入位置  
        SkipListNode<TData>* update[MAX_SKIP_LIST_TMPL_LEVEL];  // 插入节点的前驱节点数组  
      
        SkipListNode<TData>* p = header;  
        SkipListNode<TData>* q = NULL;  
      
        // 找到跳表中插入节点的前驱节点  
        for (int k = level; k >= 0; --k)  
        {  
            q = p->forward[k];  
            while(q && q->value < value)  
            {  
                p = q;  
                q = q->forward[k];  
            }  
            update[k] = p;  
        }  
      
        // 说明节点已经存在  
        if (q && value == q->value)  
        {  
            return SKIP_LIST_TMPL_NODE_EXIST;  
        }  
      
        // 随机获取到插入节点的层数  
        int nodelevel = GetRandomSkipListNodeLevel();  
      
        // 如果插入节点层数大于当前跳表的最大层数,需要更新插入节点的前驱节点数组  
        while(nodelevel > level)  
        {  
            ++level;  
            update[level] = header;  
        }  
      
        // 获取一个空闲的跳表节点  
        SkipListNode<TData>* freeNode = GetFreeSkipListNode(nodelevel);  
        if (NULL == freeNode)  
        {  
            // 获取空闲节点失败  
            return SKIP_LIST_TMPL_GET_FREE_SKIP_LIST_NODE_FAILED;  
        }  
      
        // 初始化该节点  
        freeNode->value = value;  
      
        // 将节点插入到跳表中,update数组中保存了节点的不同层的前驱节点数组  
        for (int k = 0; k <= nodelevel; ++k)  
        {  
            freeNode->forward[k] = update[k]->forward[k];  
            update[k]->forward[k] = freeNode;  
        }  
      
        return SKIP_LIST_TMPL_INSERT_NODE_SUCCESS;  
    }  
      
    /* 删除一个跳表节点 
     * @param value 节点值 
     * @return 返回操作码,详情看上面跳表操作返回码的意义 
     */  
    template <typename TData>  
    int SkipListTmpl<TData>::DeleteSkipListNode(const TData &value)  
    {  
        // 保证跳表已经初始化  
        assert(NULL != header);  
          
        // 首先查找节点的前驱节点数组  
        SkipListNode<TData>* update[MAX_SKIP_LIST_TMPL_LEVEL];  // 删除节点的前驱节点数组  
          
        SkipListNode<TData>* p = header;  
        SkipListNode<TData>* q = NULL;  
      
        // 找到跳表中删除节点的前驱节点  
        for (int k = level; k >= 0; --k)  
        {  
            q = p->forward[k];  
            while(q && q->value < value)  
            {  
                p = q;  
                q = q->forward[k];  
            }  
            update[k] = p;  
        }  
      
        // 说明删除节点存在  
        if (q && q->value == value)  
        {  
            for (int k = 0; k <= level && update[k]->forward[k] == q; ++k)  
            {  
                update[k]->forward[k] = q->forward[k];  
            }  
            free(q->forward);  
            free(q);  
      
            // 如果q节点刚好是跳表中的最大层节点,需要更新当前跳表的最大层  
            while(NULL == header->forward[level] && level > 0)  
            {  
                --level;  
            }  
      
            // 删除节点成功  
            return SKIP_LIST_TMPL_INSERT_NODE_SUCCESS;  
        }  
        else  
        {  
            // 说明删除节点不存在  
            return SKIP_LIST_TMPL_NODE_NOT_EXIST;  
        }  
    }  
      
    /* 查找跳表节点 
     * @param value 节点值 
     * @return 返回NULL表示查找失败,否则返回找到了跳表节点指针 
     */  
    template <typename TData>  
    SkipListNode<TData>* SkipListTmpl<TData>::SearchSkipListNode(const TData &value)  
    {  
        // 确保跳表已经初始化  
        assert(NULL != header);  
      
        SkipListNode<TData>* p = header;  
        SkipListNode<TData>* q = NULL;  
          
        for (int k = level; k >= 0; --k)  
        {  
            q = p->forward[k];  
            while(q && q->value < value)  
            {  
                p = q;  
                q = q->forward[k];  
            }  
        }  
      
        // 说明找到节点了  
        if (q && q->value == value)  
        {  
            return q;  
        }  
        else  
        {  
            // 说明没有找到节点  
            return NULL;  
        }  
    }  
      
    /* 遍历处理跳表中所有节点 
     * @param proc 回调的处理函数 
     * @return 返回处理的节点数目 
     */  
    template <typename TData>  
    int SkipListTmpl<TData>::ProcessEverySkipListNode(void (*proc)(const TData &value))  
    {  
        // 确保跳表已经初始化  
        assert(NULL != header);  
          
        int cnt = 0;  
        SkipListNode<TData>* p = header->forward[0];  
        while(p)  
        {  
            proc(p->value);  
            cnt++;  
            p = p->forward[0];  
        }  
        return cnt;  
    }  
      
      
    /* 随机获取一个节点的层数,层数范围0 - (MAX_SKIP_LIST_TMPL_LEVEL-1) 
     * @return 节点的层数 
     */  
    template <typename TData>  
    int SkipListTmpl<TData>::GetRandomSkipListNodeLevel()  
    {  
        // 选择一个种子值  
        static bool seedInit = false;  
        if (!seedInit)  
        {  
            srand(time(NULL));  
            seedInit = true;  
        }  
          
        // 根据概率计算出节点的层数  
        int newLevel = 0;  
        while(1)  
        {  
            double curP = (double)(rand() % 100) / 100.0;  
            if (curP < SKIP_LIST_TMPL_LEVEL_PROBABILITY)  
            {  
                newLevel++;  
            }  
            else  
            {  
                break;  
            }  
      
            // 最大层数是MAX_SKIP_LIST_TMPL_LEVEL-1  
            if ( (MAX_SKIP_LIST_TMPL_LEVEL-1) <= newLevel)  
            {  
                break;  
            }  
        }  
          
        // 最大层数是MAX_SKIP_LIST_TMPL_LEVEL-1  
        if (newLevel >= MAX_SKIP_LIST_TMPL_LEVEL)  
        {  
            newLevel = MAX_SKIP_LIST_TMPL_LEVEL - 1;  
        }  
      
        return newLevel;  
    }  
    
    

    相关文章

      网友评论

          本文标题:跳表的简单实现

          本文链接:https://www.haomeiwen.com/subject/mtcsextx.html