跳表

跳表,又叫做跳跃表、跳跃列表,在有序链表的基础上增加了“跳跃”的功能,由william pugh于1990年发布,设计的初衷是为了取代平衡树(比如红黑树)。
redis、leveldb 都是著名的 key-value 数据库,而redis中 的 sortedset、leveldb 中的 memtable 都用到了跳表。
对比平衡树,跳表的实现和维护会更加简单,跳表的搜索、删除、添加的平均时间复杂度是 o(logn)。
跳表的结构如图所示:

可以发现,对于一个节点node,其含有多个next指针,不同索引的next分别代表不同层次的下一个节点,下次是节点类node的python定义:

class node():
     def __init__(self,key,value,level):
         '''
         :param level:每个node对应的nexts层数不同
         '''
         self.key=key
         self.value=value
         self.nexts=[none]*level#节点类型next指针,初始值为空

     def __str__(self):
         #return "[key:"+str(self.key)+", value:"+str(self.value)+" len:"+str(len(self.nexts))+"]"
         return "["+str(self.key)+","+str(self.value)+","+str(len(self.nexts))+"]"

关于添加、删除、查找见一下完整代码:

'''
跳表 skip list ,其初衷是为了替代红黑树
'''
import random

import mkl_random
import time

class skiplist():
    def __init__(self):
        #头节点不存储任何数据
        self.max_level = 32  # 最大level层数
        self.__first=skiplist.node(none, none, self.max_level)#头节点
        self.__level=0#实际的level层数
        self.__size=0#jiedian个数
        self.__p=0.25#用于生成添加节点时的随机level
        return

    class node():
        def __init__(self,key,value,level):
            '''
            :param level:每个node对应的nexts层数不同
            '''
            self.key=key
            self.value=value
            self.nexts=[none]*level

        def __str__(self):
            #return "[key:"+str(self.key)+", value:"+str(self.value)+" len:"+str(len(self.nexts))+"]"
            return "["+str(self.key)+","+str(self.value)+","+str(len(self.nexts))+"]"

    def get(self,key):
        '''
        :param key:
        :return: key对应的value
        '''
        self.keycheck(key)
        node=self.__first
        for level in range(self.__level - 1,-1,-1):
            #在该层查找,key大于节点的key向前查找
            while node.nexts[level] and node.nexts[level].key<key:
                node=node.nexts[level]
            if node.nexts[level] and node.nexts[level].key==key:#相等则找到,否则向下寻找
                return node.nexts[level].value
        return none

    def put(self,key,value):
        '''
        return:原来的value,原来不存在key则为空
        '''
        self.keycheck(key)
        prev=[none]*self.__level
        node=self.__first
        for i in range(self.__level - 1, -1, -1):
            while node.nexts[i] and node.nexts[i].key<key:
                node=node.nexts[i]
            if node.nexts[i] and node.nexts[i].key==key:
                oldvalue=node.nexts[i].value
                node.nexts[i].value=value
                return oldvalue
            prev[i]=node#保存当前level小于key的node

        newlevel=self.randomlevel()
        newnode=skiplist.node(key,value,newlevel)
        for i in range(newlevel):
            if i<self.__level:
                newnode.nexts[i]=prev[i].nexts[i]
                prev[i].nexts[i]=newnode
            else:
                self.__first.nexts[i]=newnode
        self.__size+=1
        self.__level=max(self.__level, newlevel)
        return none

    def remove(self,key):
        '''
        :return: 节点对应的value值,不存在则返回none
        '''
        self.keycheck(key)
        prev=[none]*self.__level
        node=self.__first
        flag=false#该节点是否被查找到
        for i in range(self.__level - 1, -1, -1):
            while node.nexts[i] and node.nexts[i].key<key:
                node=node.nexts[i]
            if node.nexts[i].key==key:
                flag=true
            prev[i]=node
        if not flag:
            return none
        removednode=node.nexts[0]#需要被删除的节点
        for i in range(len(removednode.nexts)):#该nexts一定小于等于prev的长度
            prev[i].next[i]=removednode.nexts[i]
        self.__size-=1
        newlevel=self.__level
        while newlevel>0 and not self.__first.nexts[newlevel - 1]:
            newlevel-=1
        self.__level=newlevel
        return removednode.value

    def keycheck(self, key):
        '''
        限制传入key不能为空
        '''
        if key!=0 and not key:
            raise attributeerror("key can not be none")

    def size(self):
        return self.__size

    def isempty(self):
        return self.__size == 0

    def randomlevel(self):#生成一个随机的层数
        level=1
        while mkl_random.rand()<self.__p and level<self.max_level:
            level+=1
        return level

    def __str__(self):
        result=""
        for i in range(self.__level - 1, -1, -1):
            result+=str(i)
            node = self.__first
            while node.nexts[i]:
                result+=str(node.nexts[i])
                node=node.nexts[i]
            result+='\n'
        print("level:"+str(self.__level))
        return result

    def showfirst(self):
        for item in self.__first.nexts:
            print(item,end=' ')
        print()

def timecalculate(container, size:int):
    begin=time.time()
    for i in range(size):
        if isinstance(container,dict):
            container[i]= i * 3
        else:
            container.put(i, i * 3)
    error_count = 0
    for i in range(size):
        if container.get(i) != i * 3:
            #print("wrong " + str(i) + ":" + str(skiplist.get(i)))
            error_count+=1
    end=time.time()
    print(type(container))
    print(f'error rate:{float(error_count) / size:0.5f}')
    print(f'time cost:{float(end-begin)*1000:0.3f} ms')


if __name__=='__main__':
    timecalculate({},1000000)
    timecalculate(skiplist(),10000)

到此这篇关于python实现跳表skiplist的文章就介绍到这了,更多相关python 跳表skiplist内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!