python实现跳表SkipList

2022-06-17 13:06:32

跳表

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

在这里插入图片描述
可以发现,对于一个节点Node,其含有多个next指针,不同索引的next分别代表不同层次的下一个节点,下次是节点类Node的python定义:

classNode():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 randomimport mkl_randomimport timeclassSkipList():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#用于生成添加节点时的随机levelreturnclassNode():def__init__(self,key,value,level):'''
            :param level:每个node对应的nexts层数不同
            '''
            self.key=key
            self.value=value
            self.nexts=[None]*leveldef__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))+"]"defget(self,key):'''
        :param key:
        :return: key对应的value
        '''
        self.keyCheck(key)
        node=self.__firstfor levelinrange(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].valuereturnNonedefput(self,key,value):'''
        return:原来的value,原来不存在key则为空
        '''
        self.keyCheck(key)
        prev=[None]*self.__level
        node=self.__firstfor iinrange(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=valuereturn oldValue
            prev[i]=node#保存当前level小于key的node

        newLevel=self.randomLevel()
        newNode=SkipList.Node(key,value,newLevel)for iinrange(newLevel):if i<self.__level:
                newNode.nexts[i]=prev[i].nexts[i]
                prev[i].nexts[i]=newNodeelse:
                self.__first.nexts[i]=newNode
        self.__size+=1
        self.__level=max(self.__level, newLevel)returnNonedefremove(self,key):'''
        :return: 节点对应的value值,不存在则返回None
        '''
        self.keyCheck(key)
        prev=[None]*self.__level
        node=self.__first
        flag=False#该节点是否被查找到for iinrange(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]=nodeifnot flag:returnNone
        removedNode=node.nexts[0]#需要被删除的节点for iinrange(len(removedNode.nexts)):#该nexts一定小于等于prev的长度
            prev[i].next[i]=removedNode.nexts[i]
        self.__size-=1
        newLevel=self.__levelwhile newLevel>0andnot self.__first.nexts[newLevel-1]:
            newLevel-=1
        self.__level=newLevelreturn removedNode.valuedefkeyCheck(self, key):'''
        限制传入key不能为空
        '''if key!=0andnot key:raise AttributeError("key can not be None")defsize(self):return self.__sizedefisEmpty(self):return self.__size==0defrandomLevel(self):#生成一个随机的层数
        level=1while mkl_random.rand()<self.__pand level<self.MAX_LEVEL:
            level+=1return leveldef__str__(self):
        result=""for iinrange(self.__level-1,-1,-1):
            result+=str(i)
            node= self.__firstwhile node.nexts[i]:
                result+=str(node.nexts[i])
                node=node.nexts[i]
            result+='\n'print("level:"+str(self.__level))return resultdefshowFirst(self):for itemin self.__first.nexts:print(item,end=' ')print()deftimeCalculate(container, size:int):
    begin=time.time()for iinrange(size):ifisinstance(container,dict):
            container[i]= i*3else:
            container.put(i, i*3)
    error_count=0for iinrange(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)
  • 作者:von Libniz
  • 原文链接:https://blog.csdn.net/Demon_LMMan/article/details/119064581
    更新时间:2022-06-17 13:06:32