1. 程式人生 > >python3.6實現跳錶

python3.6實現跳錶

實現:

使用一個類表示跳錶的節點



#跳躍表節點的類

class SNode:

    def __init__(self,key=None,value=None):

        #鍵
        self.key=key
        #index表示陣列中最末的元素
        self.maxIndex=-1
        #link使用一個數組  存放全部下節點的索引  link[i]表示第i層的索引
        self.link=[]
        self.value=value

跳錶類 的構造方法

class SkipList
:
def __init__(self,size=8,larger=65535): #深度 self.size = size ''' 跳躍表的深度和你的資料有關 大約為 log n ''' #尾節點指標 self.tial=SNode() #頭結點指標 存放頭結點 self.head=SNode() #存放在插入和刪除操作中 每一個鏈上遇到的最後節點 self.last=[] self.tial.key=larger#表示尾節點
self.head.key=-65535#表示節點 #頭結點的全部指標指向尾節點 for i in range(self.size): self.head.link.append(self.tial) self.MAX_RAND=self.size

由於跳錶的節點高度是隨機的 要用一個函式 確定

 #隨機分配層數  但是不會超過最大層數
    def randomDispenseLevel(self):
         level=1
         while random.randint(0
,1)==1: level+=1 return level if level<=self.MAX_RAND else self.MAX_RAND

last陣列用來儲存動態操作(插入和刪除) 某節點後該節點前面的節點

  #獲取last數組裡的值
    def getLast(self,data):
        #print(data)
        num = self.size - 1      #陣列儲存時是自底向上    查詢是自頂向下   所以num表示層數
        p = self.head
        while num >= 0:
            while p.link[num].key <data:#和進行一次查詢一樣 如果小於,說明這個節點是待動態操作節點的前一個節點
                p = p.link[num]
            num -= 1

            self.last.append(p if p != None  else self.head)#如果節點不是空就加入last裡

        return  self.last[len(self.last)-1]#p指向最底層的節點

查詢

    def find(self,data):
        FLAGE=False#標準位   查詢是否成功
        temp=self.head #temp開始存放頭指標
        i=self.size-1 #i是最大長度-1   因為是從上往下找
        while i>=0: #如果沒有越界
            if temp.link[i].key==self.tial.key:#如果到達最後的尾指標 說明當前層沒有要找的節點

                i-=1
                continue
            if temp.link[i].key<data:#如果小於待查詢的資料  說明要將節點切換到下一個節點

                temp=temp.link[i]

                i=len(temp.link)-1
            elif temp.link[i].key==data:#如果相等說明找到了
                FLAGE=True

                return  temp.link[i],FLAGE
            else:
                if i>0:#如果沒找到  切沒有到最後一層  直接下降一層

                    i-=1
                else:
                    return temp,FLAGE
        return     temp,FLAGE

插入

    def insert(self,key,value=None):
        '''
        插入的方法
        :param key: 待插入資料的 鍵值對
        :return:    true  or false
        '''


        curNode=self.getLast(key)  # 獲取last陣列的值

        if curNode.key!=key:   #flag為false說明沒有相同元素
            #獲得層數
            lev=self.randomDispenseLevel()
            #構造一個新節點
            newNode=SNode(key,value)

            count=self.size-1 #控制節點的變化
            num=0   #控制節點裡面數組的具體號
            '''
                為什麼count是從大到小  num是從小到大


                因為查詢是從上往下  所以last陣列存放是從上往下 
                但是每個節點的link陣列存放節點物件是從下往上        

            '''
            while num<=lev-1:
                length=len(self.last[count].link)-1#獲取不同的節點link陣列長度

                while num<=length:
                    if num>lev-1:
                        break
                    newNode.link.append(self.last[count].link[num])#插入新節點 last裡的節點指向new節點
                    self.last[count].link[num] = newNode#新節點變成last裡元素的下一個節點
                    num+=1
                count -= 1 #節點切換

            self.last=[]#必須插入一次後必須將last重新變為空  因為list的append方法會不斷新增新的元素
            return  True
        return  False

刪除

 def remove(self,key):
        '''
        刪除的思路

        先進行一次find  如果存在就刪除


        先獲得last陣列

        然後進行刪除

        :param key: 待刪除資料的鍵
        :return:
        '''
        temp,flag=self.find(key)
        if flag:#如果存在這個鍵

            self.getLast(key)#獲取last陣列的值
            length=len(temp.link)-1#獲取待刪除陣列鍵的長度
            count = self.size - 1  # 控制last數組裡節點的變化
            num = 0  # 6控制待刪除節點裡面數組的具體號

            while num<=length:


                self.last[count].link[num]=temp.link[num]
                num+=1
                count-=1
            self.last=[]#必須插入一次後必須將last重新變為空  因為list的append方法會不斷新增新的元素
            return True
        return  False

輸出跳錶

   #順序輸出跳躍表
    def outpute(self):

        i = self.size - 1
        while i>=0:
           # i是最大長度-1   因為是從上往下找
            p=self.head
            if p.link==None or p.link[i].key == self.tial.key:  # 如果到達最後的尾指標 說明當前層沒有要找的節點


                print('head----->tial')
                i -= 1
                continue
            else:

                print('head',end='--->')
                while True:
                    if p.link==None or p.link[i].key == self.tial.key:
                        break
                    print(p.link[i].key, end='--->')
                    p=p.link[i]
                print('tail')
            i -= 1

測試方法

if  __name__=='__main__':
    s=SkipList(size=5)
    x=[1,2,3,4,5,6,7,8,9]
    for i in x:
        s.insert(i,i)
    print('最開始的情況')
    s.outpute()
    print('刪除4')
    print(s.remove(4))
    s.outpute()
    print('插入4')
    print(s.insert(4))
    s.outpute()
    print('刪除3')
    print(s.remove(3))
    s.outpute()
    print('刪除5')
    print(s.remove(5))
    s.outpute()
    print('刪除1')
    print(s.remove(1))
    s.outpute()

執行結果

最開始的情況
head--->4--->6--->tail
head--->3--->4--->6--->tail
head--->3--->4--->6--->tail
head--->2--->3--->4--->6--->tail
head--->1--->2--->3--->4--->5--->6--->7--->8--->9--->tail
刪除4
True
head--->6--->tail
head--->3--->6--->tail
head--->3--->6--->tail
head--->2--->3--->6--->tail
head--->1--->2--->3--->5--->6--->7--->8--->9--->tail
插入4
(<Algorithm.List.SNode.SNode object at 0x00000244AE32C320>, False)
head--->6--->tail
head--->3--->6--->tail
head--->3--->6--->tail
head--->2--->3--->6--->tail
head--->1--->2--->3--->5--->6--->7--->8--->9--->tail
刪除3
True
head--->6--->tail
head--->6--->tail
head--->6--->tail
head--->2--->6--->tail
head--->1--->2--->5--->6--->7--->8--->9--->tail
刪除5
True
head--->6--->tail
head--->6--->tail
head--->6--->tail
head--->2--->6--->tail
head--->1--->2--->6--->7--->8--->9--->tail
刪除1
True
head--->6--->tail
head--->6--->tail
head--->6--->tail
head--->2--->6--->tail
head--->2--->6--->7--->8--->9--->tail