跳表的简单实现

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

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

  
// 跳表实现
  
#include   
#include   
#include   
#include   
  
/* 跳表节点数据结构 
 * 
 */  
template   
struct SkipListNode  
{  
    TData value; // 节点值  
    SkipListNode** 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   
class SkipListTmpl  
{  
public:  
    /* 初始化跳表 
     */  
    bool InitSkipListTmpl();  
  
    /* 获取一个空闲的跳表节点 
     * @param level  跳表节点的层数 
     * @return 返回NULL表示创建失败,否则返回创建的跳表节点指针 
     */  
    SkipListNode* GetFreeSkipListNode(int level);  
  
    /* 增加一个跳表节点 
     * @param value 节点值 
     * @return 返回操作码,详情看上面跳表操作返回码的意义 
     */  
    int InsertSkipListNode(const TData &value);  
  
    /* 删除一个跳表节点 
     * @param value 节点值 
     * @return 返回操作码,详情看上面跳表操作返回码的意义 
     */  
    int DeleteSkipListNode(const TData &value);  
  
    /* 查找跳表节点 
     * @param value 节点值 
     * @return 返回NULL表示查找失败,否则返回找到了跳表节点指针 
     */  
    SkipListNode* SearchSkipListNode(const TData &value);  
  
    /* 遍历处理跳表中所有节点 
     * @param proc 回调的处理函数 
     * @return 返回处理的节点数目 
     */  
    int ProcessEverySkipListNode(void (*proc)(const TData &value));  
  
private:  
    int level; // 当前跳表的最大层数  
    SkipListNode* 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   
const double SkipListTmpl::SKIP_LIST_TMPL_LEVEL_PROBABILITY = 0.5;  
  
/* 创建一个空的跳表节点 
 * @param level  跳表节点的层数 
 * @return 返回NULL表示创建失败,否则返回创建的跳表节点指针 
 */  
template   
SkipListNode* SkipListTmpl::GetFreeSkipListNode(int level)  
{  
    // 节点层数范围0  
    assert(level >= 0 && level < MAX_SKIP_LIST_TMPL_LEVEL);  
  
    SkipListNode* newNode = (SkipListNode*)malloc(sizeof(SkipListNode));  
    if (NULL == newNode)  
    {  
        return NULL;  
    }  
      
    // 前向节点初始化为NULL  
    newNode->forward = (SkipListNode **)malloc(sizeof(SkipListNode*) * (level+1));  
    if (NULL == newNode->forward)  
    {  
  
        // 申请内存失败那么就归还之前申请的内存  
        free(newNode);  
        return NULL;  
    }  
      
    for (int i = 0; i <= level; ++i)  
    {  
        newNode->forward[i] = NULL;  
    }  
  
    // 创建好的跳表节点  
    return newNode;  
}  
  
/* 初始化跳表 
 */  
template   
bool SkipListTmpl::InitSkipListTmpl()  
{  
    level = 0; // 当前最大层初始为0  
      
    // 头结点的层数为跳表最大层数,这个节点是个冗余节点,增加它是为了方便链表操作  
    header = GetFreeSkipListNode(MAX_SKIP_LIST_TMPL_LEVEL-1);  
  
    // 初始化成功  
    if (header)  
    {  
        return true;  
    }  
  
    // 初始化失败  
    return false;  
}  
  
/* 增加一个跳表节点 
 * @param value 节点值 
 * @return 返回操作码,详情看上面跳表操作返回码的意义 
 */  
template   
int SkipListTmpl::InsertSkipListNode(const TData &value)  
{  
    // 保证跳表已经初始化  
    assert(NULL != header);  
  
    // 首先查找节点的插入位置  
    SkipListNode* update[MAX_SKIP_LIST_TMPL_LEVEL];  // 插入节点的前驱节点数组  
  
    SkipListNode* p = header;  
    SkipListNode* 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* 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   
int SkipListTmpl::DeleteSkipListNode(const TData &value)  
{  
    // 保证跳表已经初始化  
    assert(NULL != header);  
      
    // 首先查找节点的前驱节点数组  
    SkipListNode* update[MAX_SKIP_LIST_TMPL_LEVEL];  // 删除节点的前驱节点数组  
      
    SkipListNode* p = header;  
    SkipListNode* 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   
SkipListNode* SkipListTmpl::SearchSkipListNode(const TData &value)  
{  
    // 确保跳表已经初始化  
    assert(NULL != header);  
  
    SkipListNode* p = header;  
    SkipListNode* 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   
int SkipListTmpl::ProcessEverySkipListNode(void (*proc)(const TData &value))  
{  
    // 确保跳表已经初始化  
    assert(NULL != header);  
      
    int cnt = 0;  
    SkipListNode* 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   
int SkipListTmpl::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;  
}  

你可能感兴趣的:(跳表的简单实现)