美文网首页
跳表(skip list)

跳表(skip list)

作者: 云飞扬1 | 来源:发表于2020-02-25 20:06 被阅读0次

跳表是通过链表来存储有序数组,查找、插入、删除数据非常高效。代码如下(kotlin编写):

class SkipList {

    companion object {
        //跳表的最大高度
        const val MAX_LEVEL = 16
    }

    /**
     * 这里使用带头链表,方便操作
     *
     * head            7                    //第2层索引
     * head      3     7     11             //第1层索引
     * head   1  3  5  7  9  11  13  15     //第0层,原始链表
     *
     * 对于 head 节点,nextNodes[0] = 1,nextNodes[1] = 3,nextNodes[2] = 7
     * 对于节点 3,nextNode[0] = 5,nextNodes[1] = 7,nextNodes[2] = null
     */
    class Node {
        //只存储非负整数
        var data: Int = -1
        //通过数组来存储该节点在每层索引上的下一个节点指针
        //nextNodes[0] 表示该节点在原始链表上的下一个节点指针
        //nextNodes[1] 表示该节点在第1层索引上的下一个节点指针
        //nextNodes[2] 表示该节点在第2层索引上的下一个节点指针,依次类推,直到 nextNodes[MAX_LEVEL - 1]
        var nextNodes: Array<Node?> = arrayOfNulls(MAX_LEVEL)

        override fun toString(): String {
            return "data: $data"
        }
    }

    //带头链表,为了放标操作,其实不存储任何实际数据
    private var head = Node()

    //当前跳表的实际层数,刚开始为 1
     var levelCount = 1

    /**
     * 查找节点
     */
    fun find(value: Int): Node? {
        //从最上面的索引开始查找,从上往下,一直到原始链表上查找
        var p = head
        for (i in levelCount - 1 downTo 0) {
            while (p.nextNodes[i] != null && (p.nextNodes[i]!!.data) < value) {
                p = p.nextNodes[i]!!
            }
        }
        return if (p.nextNodes[0]?.data == value) p.nextNodes[0] else null
    }

    /**
     * 插入数据
     */
    fun insert(value: Int) {
        var level = randomLevel()
        var newNode = Node()
        newNode.data = value

        //定义一个数组,保存每层索引待插入节点的前置节点
        var update = Array(level) { head }
        var p = head
        for (i in level - 1 downTo 0) {
            while (p.nextNodes[i] != null && p.nextNodes[i]!!.data < value) {
                p = p.nextNodes[i]!!
            }
            update[i] = p
        }

        //每层索引插入新节点
        for (i in update.indices) {
            newNode.nextNodes[i] = update[i].nextNodes[i]
            update[i].nextNodes[i] = newNode
        }

        if (levelCount < level) levelCount = level
    }

    fun delete(value: Int) {
        //同样先找到待删除节点的前置节点
        var update = arrayOfNulls<Node>(levelCount)
        var p = head
        for (i in levelCount - 1 downTo 0) {
            while (p.nextNodes[i] != null && p.nextNodes[i]!!.data < value) {
                p = p.nextNodes[i]!!
            }
            update[i] = p
        }

        //先如果能找到节点
        if (p.nextNodes[0]?.data == value ) {
            for (i in update.indices) {
                //前置节点的下一节点与待删除数据相等,则需要更新链表
                var updateNode = update[i]
                if (updateNode != null && updateNode.nextNodes[i] != null && updateNode.nextNodes[i]!!.data == value) {
                    updateNode.nextNodes[i] = updateNode.nextNodes[i]!!.nextNodes[i]
                }
            }
        }

        while (levelCount > 1 && head.nextNodes[levelCount - 1] == null) {
            levelCount--
        }
    }

    /**
     * 随机返回 [1, MAX_LEVEL] 之间的数
     */
    private fun randomLevel(): Int {
        var level = 1
        while (Math.random() < 0.5 && level < MAX_LEVEL) {
            level++
        }
        return level
    }
}

查找时间复杂度:O(logn)
插入时间复杂度:O(logn)
删除时间复杂度:O(logn)
空间复杂度为O(n),如果跳表存储的是一些大对象数据,那么相对于这些数据来说,额外需要的存储空间并不大。

相关文章

  • skip list(跳表)

    第一次看到这种数据结构还是刚接触ocean base架构的时候。粗略扫了几眼,以为是一个简单的二级索引,没有仔细考...

  • 跳表(skip list)

    跳表是通过链表来存储有序数组,查找、插入、删除数据非常高效。代码如下(kotlin编写): 查找时间复杂度:O(l...

  • 跳表(skip list)

    我们知道二叉搜索算法能够高效的查询数据,但是需要一块连续的内存,而且增删改效率很低。跳表,是基于链表实现的一种类似...

  • 跳表(skip list)java实现

    跳表(skip list)java实现 WiKi 【转载】http://blog.csdn.net/brillia...

  • 跳跃表

    Skip List定义 Skip List 完整实现 下面是跳表的基本操作 节点的创建 列表的初始化列表的初始化需...

  • skipList

    Skip List--跳表(全网最详细的跳表文章没有之一)https://www.jianshu.com/p/9d...

  • 数据结构中的跳表

    跳表的定义: 跳表(Skip List)是由 William Pugh 发明的一种查找数据结构,支持对数据的快速查...

  • 30-跳表(Skip List)

    首先来思考一个问题。 一个有序链表(下图),搜索,添加,删除的平均时间复杂度是多少? 通过对链表这种数据结构的了解...

  • 今天终于知道 Redis 为什么要用跳跃表了

    首先,Redis 中的有序集合(Sorted Set)就是用跳表(Skip list)来实现的。 如果你了解过平衡...

  • 今天终于知道 Redis 为什么要用跳跃表了

    首先,Redis 中的有序集合(Sorted Set)就是用跳表(Skip list)来实现的。 如果你了解过平衡...

网友评论

      本文标题:跳表(skip list)

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