python實(shí)現(xiàn)跳表SkipList的示例代碼
跳表
跳表,又叫做跳躍表、跳躍列表,在有序鏈表的基礎(chǔ)上增加了“跳躍”的功能,由William Pugh于1990年發(fā)布,設(shè)計(jì)的初衷是為了取代平衡樹(比如紅黑樹)。
Redis、LevelDB 都是著名的 Key-Value 數(shù)據(jù)庫(kù),而Redis中 的 SortedSet、LevelDB 中的 MemTable 都用到了跳表。
對(duì)比平衡樹,跳表的實(shí)現(xiàn)和維護(hù)會(huì)更加簡(jiǎn)單,跳表的搜索、刪除、添加的平均時(shí)間復(fù)雜度是 O(logn)。
跳表的結(jié)構(gòu)如圖所示:
可以發(fā)現(xiàn),對(duì)于一個(gè)節(jié)點(diǎn)Node,其含有多個(gè)next指針,不同索引的next分別代表不同層次的下一個(gè)節(jié)點(diǎn),下次是節(jié)點(diǎn)類Node的python定義:
class Node(): def __init__(self,key,value,level): ''' :param level:每個(gè)node對(duì)應(yīng)的nexts層數(shù)不同 ''' self.key=key self.value=value self.nexts=[None]*level#節(jié)點(diǎn)類型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))+"]"
關(guān)于添加、刪除、查找見一下完整代碼:
''' 跳表 Skip List ,其初衷是為了替代紅黑樹 ''' import random import mkl_random import time class SkipList(): def __init__(self): #頭節(jié)點(diǎn)不存儲(chǔ)任何數(shù)據(jù) self.MAX_LEVEL = 32 # 最大level層數(shù) self.__first=SkipList.Node(None, None, self.MAX_LEVEL)#頭節(jié)點(diǎn) self.__level=0#實(shí)際的level層數(shù) self.__size=0#Jiedian個(gè)數(shù) self.__p=0.25#用于生成添加節(jié)點(diǎn)時(shí)的隨機(jī)level return class Node(): def __init__(self,key,value,level): ''' :param level:每個(gè)node對(duì)應(yīng)的nexts層數(shù)不同 ''' 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對(duì)應(yīng)的value ''' self.keyCheck(key) node=self.__first for level in range(self.__level - 1,-1,-1): #在該層查找,key大于節(jié)點(diǎn)的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#保存當(dāng)前l(fā)evel小于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: 節(jié)點(diǎn)對(duì)應(yīng)的value值,不存在則返回None ''' self.keyCheck(key) prev=[None]*self.__level node=self.__first flag=False#該節(jié)點(diǎn)是否被查找到 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]#需要被刪除的節(jié)點(diǎn) for i in range(len(removedNode.nexts)):#該nexts一定小于等于prev的長(zhǎng)度 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):#生成一個(gè)隨機(jī)的層數(shù) 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)
到此這篇關(guān)于python實(shí)現(xiàn)跳表SkipList的文章就介紹到這了,更多相關(guān)python 跳表SkipList內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python utc datetime轉(zhuǎn)換為時(shí)間戳的方法
今天小編就為大家分享一篇python utc datetime轉(zhuǎn)換為時(shí)間戳的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-01-01python實(shí)現(xiàn)五子棋人機(jī)對(duì)戰(zhàn)游戲
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)五子棋之人機(jī)對(duì)戰(zhàn)游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06Python圖像運(yùn)算之圖像點(diǎn)運(yùn)算與灰度化處理詳解
這篇文章主要介紹了圖像點(diǎn)運(yùn)算的灰度化處理的相關(guān)知識(shí),包括各種灰度算法的實(shí)現(xiàn),以及灰度線性變換和灰度非線性變換。需要的可以參考一下2022-02-02python用字典統(tǒng)計(jì)單詞或漢字詞個(gè)數(shù)示例
這篇文章主要介紹了python用字典統(tǒng)計(jì)單詞或漢字詞個(gè)數(shù)示例,需要的朋友可以參考下2014-04-04Python判斷字符串是否為字母或者數(shù)字(浮點(diǎn)數(shù))的多種方法
本文給大家?guī)砣N方法基于Python判斷字符串是否為字母或者數(shù)字(浮點(diǎn)數(shù)),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-08-08