SkipList

原理简介

      说到怎样在一组数据中快速的查找某个元素,我们最先想到的肯定是二分查找,而使用二分查找就要构建一个顺序排列线性表结构,虽然加快了查询的效率,但是增、删、改的效率大大下降。而链表类的数据结构增删改操作效率是很高的,因为它只需要更改相应的指针即可,而不像数组类的顺序线性表增删改操作需要变更内存空间。我们也知道链表的查询效率很低,那么有没有一种能提高链表查询效率的算法呢?

在这里插入图片描述

       上图是一个最常见的有序单链表,,最普遍的查询就是迭代,这是一个时间复杂度为O(n)的操作,从而导致链表的增删改的效率也随之下降。由此跳表就出生了,它是一种针对于有序链表的基于二分查找思想的查询算法,它的时间复杂度趋近于logn,可以大大提升链表的查询效率。
       那么跳表具体是怎么实现的呢?还是看上图中的有序单链表,假设我现在要查找的元素是10,那么传统的迭代至少要查找8次才能找到对应的元素,依据二分查找的思想有一大部分的数据查找是可以避免的,假设我比较完一不符合之后按序直接比较9,那么只需在比较一次就能查找到10,可以避免很多无意义的查询。那么链表怎么实现这种操作呢?
在这里插入图片描述
       上图就是一个跳表的简易图,就是通过多级指针来减少无意义的查询,就是1的元素不仅有一个指针指向3,也有可能有一个指针指向9或者其他的,从而达到一种趋近于二分查找思想的算法。

实现

节点类

class Node:
    """
    跳表节点类
    forwards列表就是之前说的多级指针
    """

    def __init__(self, level, key=None, value=None):
        self.key = key
        self.value = value
        self.forwards = [None] * level

跳跃链表

定级

       怎么确定新增时的级别呢?答案就是抛硬币,就是随机数来确定新增的级别。

MAX_LEVEL = 16
def random_level():
    level = 0
    for i in range(-1, MAX_LEVEL):
        level += random.randint(0, 1)
    return level
完整代码

class SkipList:
    """
    跳表
    """

    def __init__(self):
        self.head = Node(level=MAX_LEVEL)
        self.level = 0
        self.size = 0

    def insert(self, key, value):
        """
        新增
        找出每一级要更新的节点
        通过随机数确定更新的级数
        如果大于当前跳表级别  跳表扩张一级
        :param key:    key
        :param value:  value
        :return:       insert res
        """
        if key is None:
            return False
        update = [None] * MAX_LEVEL
        try:
            for i in range(self.level - 1, -1, -1):
                q = self.head
                while q.forwards[i] and q.forwards[i].key <= key:
                    q = q.forwards[i]
                if q and q.key == key:
                    return False
                update[i] = q
            ins_level = random_level()
            if ins_level > self.level:
                update[self.level] = self.head
                ins_level = self.level + 1
                self.level = ins_level
            ins_node = Node(level=ins_level, key=key, value=value)
            for i in range(ins_level):
                ins_node.forwards[i] = update[i].forwards[i]
                update[i].forwards[i] = ins_node
            self.size += 1
        except Exception as e:
            print(e)
            return False
        return True

    def find(self, key):
        """
        寻找某个key对应value
        :param key: key
        :return: value
        """
        if not key:
            return None
        p = self.head
        for i in range(self.level - 1, -1, -1):
            while p.forwards[i] and p.forwards[i].key <= key:
                if p.forwards[i].key == key:
                    return p.forwards[i].value
                p = p.forwards[i]
        return None

    def delete(self, key):
        """
        同新增  依然是要找到对应节点的前驱节点
        :param key: key
        :return: t/f
        """
        if not key:
            return False
        update = [None] * MAX_LEVEL
        q = None
        for i in range(MAX_LEVEL - 1, -1, -1):
            q = self.head
            while q.forwards[i] and q.forwards[i].key < key:
                q = q.forwards[i]
            update[i] = q
        del_node = q.forwards[0]
        del q
        if del_node and del_node.key == key:
            for i in range(self.level):
                if update[i] and update[i].forwards[i] == del_node:
                    del_node.forwards[i] = None
                    update[i].forwards[i] = update[i].forwards[i].forwards[i]
            del del_node
            for i in range(self.level - 1, -1, -1):
                if self.head.forwards[i] is None:
                    self.level -= 1
            self.size -= 1
            return True
        else:
            return False

    def print_all(self):
        for i in range(self.level - 1, -1, -1):
            p = self.head
            while p.forwards[i]:
                print(str(p.forwards[i].key) + "-->", end="")
                p = p.forwards[i]
            print('\r\n')

源码

源码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值