python3.6实现跳表

实现:

原理什么的别人的博客有很多,我这就给个链接。
数据结构—–跳表
跳表 skiplist

使用一个类表示跳表的节点



#跳跃表节点的类

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

猜你喜欢

转载自blog.csdn.net/qq_38612955/article/details/81080041