跳表 SkipList

跳跃表实现简单,空间复杂度和时间复杂度也较好,Redis中使用跳表而不是红黑树。



实现参考了:



插入时的核心逻辑:

  1. 找到插入的位置
  2. 随机得到新插入节点的level
  3. 处理为了插入当前节点穿过的指针和未穿过的指针的指向和跨度

删除时的核心逻辑:

  1. 找到删除的位置
  2. 处理要删除的节点穿过的指针和未穿过的指针的指向和跨度
  3. 如果可以,减小跳跃表的level


下面两个题可以使用平衡树,这里为了练习使用跳跃表,注意根据每个题的题意特殊处理。
SPOJ ORDERSET

#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

const int MAX_LEVEL = 32;
const int MAX_N = 200000;

struct ListNode {
    struct Forward {
        int span;
        ListNode *forward;
    };
    int val;
    vector<Forward> levels;
};

namespace memory {
    ListNode nodes[MAX_N + 1 + 16];
    int cnt;

    void init() {
        cnt = 0;
    }

    ListNode *new_node(int level, int val) {
        nodes[cnt].levels.resize(level);
        for (int i = 0; i < level; i++) {
            nodes[cnt].levels[i].forward = nullptr;
            nodes[cnt].levels[i].span = 0;
        }
        nodes[cnt].val = val;
        return &nodes[cnt++];
    }
}

struct SkipList {
    ListNode *header;
    int level;
    int length;

    void init() {
        memory::init();
        srand(time(0));

        level = 1;
        length = 0;
        header = memory::new_node(MAX_LEVEL, 0);
    }

    int get_level() {
        int level = 1;
        while (rand() % 2 && level + 1 < MAX_LEVEL)
            level++;
        return level;
    }

    void insert(int x) {
        ListNode *update[MAX_LEVEL];
        int rank[MAX_LEVEL];

        ListNode *p = header;
        for (int i = level - 1; i >= 0; i--) {
            rank[i] = i == (level - 1) ? 0 : rank[i + 1];
            while (p->levels[i].forward && p->levels[i].forward->val <= x) {
                rank[i] += p->levels[i].span;
                p = p->levels[i].forward;
            }
            update[i] = p;
        }
        if (p != header && p->val == x)
            return;

        int level_of_node = get_level();
        if (level_of_node > level) {
            for (int i = level; i < level_of_node; i++) {
                header->levels[i].span = length;
                update[i] = header;
                rank[i] = 0;
            }
            level = level_of_node;
        }
        ListNode *node = memory::new_node(level_of_node, x);
        for (int i = 0; i < level_of_node; i++) {
            node->levels[i].forward = update[i]->levels[i].forward;
            node->levels[i].span = update[i]->levels[i].span - (rank[0] - rank[i]);

            update[i]->levels[i].forward = node;
            update[i]->levels[i].span = rank[0] - rank[i] + 1;
        }

        for (int i = level_of_node; i < level; i++) {
            update[i]->levels[i].span++;
        }

        length++;
    }

    void remove(int x) {
        ListNode *update[MAX_LEVEL];

        ListNode *p = header;
        for (int i = level - 1; i >= 0; i--) {
            while (p->levels[i].forward && p->levels[i].forward->val < x) {
                p = p->levels[i].forward;
            }
            update[i] = p;
        }

        p = p->levels[0].forward;
        if (!p || p->val != x)
            return;

        for (int i = level - 1; i >= 0; i--) {
            if (update[i]->levels[i].forward == p) {
                update[i]->levels[i].forward = p->levels[i].forward;
                update[i]->levels[i].span += p->levels[i].span - 1;
            } else {
                update[i]->levels[i].span--;
            }
        }

        while (level > 1 && !header->levels[level - 1].forward)
            level--;
        length--;
    }

    int kth(int k) {
        int span = 0;
        ListNode *p = header;
        for (int i = level - 1; i >= 0; i--) {
            while (p->levels[i].forward && span + p->levels[i].span <= k) {
                span += p->levels[i].span;
                p = p->levels[i].forward;
            }
        }
        return p->val;
    }

    int rank(int x) {
        int ans = 0;
        ListNode *p = header;
        for (int i = level - 1; i >= 0; i--) {
            while (p->levels[i].forward && p->levels[i].forward->val < x) {
                ans += p->levels[i].span;
                p = p->levels[i].forward;
            }
        }
        return ans;
    }

} skip_list;

int main(int argc, char **argv) {
    int n;
    while (scanf("%d", &n) != EOF) {
        skip_list.init();
        for (int i = 0; i < n; i++) {
            char op[2];
            int x;
            scanf("%s%d", op, &x);
            if (op[0] == 'I') {
                skip_list.insert(x);
            } else if (op[0] == 'D') {
                skip_list.remove(x);
            } else if (op[0] == 'K') {
                if (x > skip_list.length) {
                    puts("invalid");
                } else {
                    printf("%d\n", skip_list.kth(x));
                };
            } else if (op[0] == 'C') {
                printf("%d\n", skip_list.rank(x));
            }
        }
    }
    return 0;
}

/**
8
I -1
I -1
I 2
C 0
K 2
D -1
K 1
K 2

1
2
2
invalid
*/

HDU 4585

#include <bits/stdc++.h>
#define DBG(x) cerr << #x << " = " << x << endl

using namespace std;
typedef long long LL;

const int MAX_LEVEL = 32;
const int MAX_N = 100000;

struct ListNode {
    struct Forward {
        int span;
        ListNode *forward;
    };
    pair<int, int> val;
    vector<Forward> levels;
};

namespace memory {
    ListNode nodes[MAX_N + 1 + 16];
    int cnt;

    void init() {
        cnt = 0;
    }

    ListNode *new_node(int level, pair<int, int> val) {
        nodes[cnt].levels.resize(level);
        for (int i = 0; i < level; i++) {
            nodes[cnt].levels[i].forward = nullptr;
            nodes[cnt].levels[i].span = 0;
        }
        nodes[cnt].val = val;
        return &nodes[cnt++];
    }
}

struct SkipList {
    ListNode *header;
    int level;
    int length;

    void init() {
        memory::init();
        srand(time(0));

        level = 1;
        length = 0;
        header = memory::new_node(MAX_LEVEL, make_pair(0, 0));
    }

    int get_level() {
        int level = 1;
        while (rand() % 2 && level + 1 < MAX_LEVEL)
            level++;
        return level;
    }

    void insert(pair<int, int> x) {
        ListNode *update[MAX_LEVEL];
        int rank[MAX_LEVEL];

        ListNode *p = header;
        for (int i = level - 1; i >= 0; i--) {
            rank[i] = i == (level - 1) ? 0 : rank[i + 1];
            while (p->levels[i].forward && p->levels[i].forward->val <= x) {
                rank[i] += p->levels[i].span;
                p = p->levels[i].forward;
            }
            update[i] = p;
        }
        if (p != header && p->val == x)
            return;

        int level_of_node = get_level();
        if (level_of_node > level) {
            for (int i = level; i < level_of_node; i++) {
                header->levels[i].span = length;
                update[i] = header;
                rank[i] = 0;
            }
            level = level_of_node;
        }
        ListNode *node = memory::new_node(level_of_node, x);
        for (int i = 0; i < level_of_node; i++) {
            node->levels[i].forward = update[i]->levels[i].forward;
            node->levels[i].span = update[i]->levels[i].span - (rank[0] - rank[i]);

            update[i]->levels[i].forward = node;
            update[i]->levels[i].span = rank[0] - rank[i] + 1;
        }

        for (int i = level_of_node; i < level; i++) {
            update[i]->levels[i].span++;
        }

        length++;
    }

    pair<int, int> find(pair<int, int> x) {
        ListNode *p = header;
        for (int i = level - 1; i >= 0; i--) {
            while (p->levels[i].forward && p->levels[i].forward->val < x)
                p = p->levels[i].forward;
        }

        if (p == header) {
            p = p->levels[0].forward;
            return p->val;
        }

        if (p->levels[0].forward && p->levels[0].forward->val.first - x.first < x.first - p->val.first) {
            p = p->levels[0].forward;
        }
        return p->val;
    }
} skip_list;

int main(int argc, char **argv) {
    int n;
    while (true) {
        scanf("%d", &n);
        if (n == 0) break;
        skip_list.init();
        skip_list.insert(make_pair(1000000000, 1));
        for (int i = 0; i < n; i++) {
            int k, g;
            scanf("%d%d", &k, &g);
            printf("%d %d\n", k, skip_list.find(make_pair(g, k)).second);
            skip_list.insert(make_pair(g, k));
        }
    }
    return 0;
}

/**
3
2 1
3 3
4 2
0

2 1
3 2
4 2
*/

原文地址:https://www.cnblogs.com/ToRapture/p/11898590.html

时间: 2024-10-11 14:16:56

跳表 SkipList的相关文章

Go语言实现跳表(SkipList)

跳表(skiplist)在redis/levelDB中属于核心数据结构,我简单粗暴的用Golang实现了下. 就我的简单理解来说,就一个普通的链表,在insert时,通过Random_level(),把一层变成很多层, 越上数据越小,跨度越大. 查找时从上往下找,用空间换时间. 记下测试代码: package main import ( "fmt" //"github.com/xclpkg/algorithm" "math/rand" ) fun

存储系统的基本数据结构之一: 跳表 (SkipList)

在接下来的系列文章中,我们将介绍一系列应用于存储以及IO子系统的数据结构.这些数据结构相互关联又有着巨大的区别,希望我们能够不辱使命的将他们分门别类的介绍清楚.本文为第一节,介绍一个简单而又有用的数据结构:跳表 (SkipList) 在对跳表进行讨论之前,我们首先描述一下跳表的核心思想. 跳表(Skip List)是有序线性链表的一种.通常对线性链表进行查找需要遍历,因而不能很好的使用二分查找这样快速的方法(想像一下在链表中定位中间元素的复杂度).为了提高查找速率,我们可以将这些线性链表打散,组

跳表SkipList

原文:http://www.cnblogs.com/xuqiang/archive/2011/05/22/2053516.html 跳表SkipList 1.聊一聊跳表作者的其人其事 2. 言归正传,跳表简介 3. 跳表数据存储模型 4. 跳表的代码实现分析 5. 论文,代码下载及参考资料 <1>. 聊一聊作者的其人其事  跳表是由William Pugh发明.他在 Communications of the ACM June 1990, 33(6) 668-676 发表了Skip lists

跳表SkipList—定义

1.聊一聊跳表作者的其人其事 2. 言归正传,跳表简介 3. 跳表数据存储模型 4. 跳表的代码实现分析 5. 论文,代码下载及参考资料 <1>. 聊一聊作者的其人其事 跳表是由William Pugh发明.他在 Communications of the ACM June 1990, 33(6) 668-676 发表了Skip lists: a probabilistic alternative to balanced trees,在该论文中详细解释了跳表的数据结构和插入删除操作. Will

C语言跳表(skiplist)实现

一.简介 跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入.删除.查找的复杂度均为O(logN).LevelDB的核心数据结构是用跳表实现的,redis的sorted set数据结构也是有跳表实现的.代码在这里:http://flyingsnail.blog.51cto.com/5341669/1020034 二.跳表图解 考虑一个有序表: 从该有序表中搜索元素 < 23, 43, 59 > ,需要比较的次数分别为 < 2, 4, 6 >,总共比较的次数 为 2 +

golang 实现跳表skiplist

package main import ( "math/rand" "time" "fmt" ) const ( P = 0.6 MaxLevel = 8 ) func randomLevel() int { i := 1 rand.Seed(time.Now().UnixNano()) for i < MaxLevel { p := rand.Float64() if (p < P) { i++ } else { break } }

红黑树、B(+)树、跳表、AVL等数据结构,应用场景及分析,以及一些英文缩写

在网上学习了一些材料. 这一篇:https://www.zhihu.com/question/30527705 AVL树:最早的平衡二叉树之一.应用相对其他数据结构比较少.windows对进程地址空间的管理用到了AVL树 红黑树:平衡二叉树,广泛用在C++的STL中.map和set都是用红黑树实现的.我们熟悉的STL的map容器底层是RBtree,当然指的不是unordered_map,后者是hash. B/B+树用在磁盘文件组织 数据索引和数据库索引 Trie树 字典树,用在统计和排序大量字符

K:跳表

??跳表(SkipList)是一种随机化的数据结构,目前在redis和leveldb中都有用到它,它的效率和红黑树以及 AVL 树不相上下,但跳表的原理相当简单,只要你能熟练操作链表, 就能轻松实现一个 SkipList. 考虑一个有序表: 从该有序表中搜索元素 < 23, 43, 59 >,需要比较的次数分别为 < 2, 4, 6 >,总共比较的次数为 2 + 4 + 6 = 12 次. 有没有优化的算法吗?链表是有序的,但不能使用二分查找.类似二叉搜索树,我们把一些节点提取出来

SkipList 跳表

为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗? 很难吧,这需要时间,要考虑很多细节,要参考一堆算法与数据结构之类的树, 还要参考网上的代码,相当麻烦. 用跳表吧,跳表是一种随机化的数据结构,目前开源软件 Redis 和 LevelDB 都有用到它, 它的效率和红黑树以及 AVL 树不相上下,但跳表的原理相当简单,只要你能熟练操作链表, 就能轻