数据结构---跳跃表

跳表是一个随机化的数据结构,实质是一种可以进行二分查找的有序链表。

跳表在原有的有序链表上增加了多级索引,通过索引来实现快速查询。

跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。

先来看看二分查找:时间复杂度O(log2n)

def bin_search(data_list, val):    
    low = 0                         # 最小数下标    
    high = len(data_list) - 1       # 最大数下标    
    while low <= high:        
        mid = (low + high) // 2     # 中间数下标        
        if data_list[mid] == val:   # 如果中间数下标等于val, 返回            
            return mid        
        elif data_list[mid] > val:  # 如果val在中间数左边, 移动high下标            
            high = mid - 1        
        else:                       # 如果val在中间数右边, 移动low下标            
            low = mid + 1    
    return # val不存在, 返回None
ret = bin_search(list(range(1, 10)), 3)
print(ret)

用数组来模拟二分查找 很方便,连续的内存空间,利用偏移量就能取出值 然后比较。。。

 跳跃表的原理很好理解,看了网上的实现,写的比较难懂,可能我功力有限,索性就自己写一套

import random
class SkipNode(object):
    def __init__(self,data):
        self.data = data
        self.next = None
        self.down = None

    def __str__(self):
        return "[%s]-" % self.data
class SkipList(object):
    def __init__(self,maxlevel = 100):
        self.maxlevel = maxlevel
        self.level = 0
        self.count = 0
        self.head = None

    def randomLevel(self):
        level = 1
        while random.randint(1,100) % 2 == 0 and level < self.maxlevel:
            level += 1
        return level

    def insert(self,data):
        path = []
        rand_level = self.randomLevel()
        print("rand_level:%s data:%s" % (rand_level,data))
        start_cursor = None
        if rand_level > self.level:
            i = self.level
            while i < rand_level:
                node = SkipNode(-1)
                node.down = self.head
                self.head = node
                i += 1
            self.level = rand_level
            start_cursor = self.head
        else:
            start_cursor = self.head
            curlevel = self.level
            while curlevel > rand_level:
                start_cursor = start_cursor.down
                curlevel -= 1
        
        t = start_cursor
        while t != None:
            if t.next != None:
                if data < t.next.data:
                    path.append(t)
                    t = t.down
                else:
                    t = t.next
            else:
                path.append(t)
                t = t.down
        
        index = len(path) - 1
        downtmp = None
        while index >=0:
            pn = path[index]
            node = SkipNode(data)
            node.next = pn.next
            pn.next = node
            node.down = downtmp
            downtmp = node
            index -= 1
        pass

    def search(self,data):
        t = self.head
        s = "search:" + str(data) + "-->"
        while t != None:
            s += str(t)
            if t.data == data:
                print(s)
                return True
            else:
                if t.next:
                    if t.next.data > data:
                        t = t.down
                    else:
                        t = t.next
                else:
                    t = t.down
        print(s)
        return False

    def delete(self,data):
        t = self.head
        print("delete:" + str(data))
        while t != None:
            if t.next:
                if t.next.data == data:
                    t.next = t.next.next
                    t = t.down
                else:
                    if t.next.data < data:
                        t = t.next
                    else:
                        t = t.down
            else:
                t = t.down
        pass

    def dump(self):
        head = self.head
        while head:
            s = ""
            node = head
            while node:
                s = s + str(node)
                node = node.next
            print(s)
            head = head.down
        pass

 插入insert 分析:

1:抛硬币 得出最大能到第几层rand_level,最下一层是1

2:如果rand_level 比 self.level 大,也就是说要产生新的索引层,当前的data是要从新加的层开始一直到最底层(1层) 每层都要加入这个索引。。有新的索引层产生就要生成一个新的行头结点,同时更新跳跃表的头结点

i = self.level
while i < rand_level:
    node = SkipNode(-1)
    node.down = self.head
    self.head = node
    i += 1
self.level = rand_level
start_cursor = self.head

 如果不需要生成新的索引行,那就找到rand_level 这个数值对应的索引行的头结点

start_cursor = self.head
curlevel = self.level
while curlevel > rand_level:
    start_cursor = start_cursor.down
    curlevel -= 1

start_cursor 表示需要插入data结点 这一索引层的头结点。。。从start_cursor开始一直到第一层,每层插入data结点就好,由于是单链表,插入一个节点需要知道插入位置的前驱节点,所以要找到这些前驱节点

t = start_cursor
while t != None:
    if t.next != None:
        if data < t.next.data:
            path.append(t)
            t = t.down
        else:
            t = t.next
    else:
        path.append(t)
        t = t.down

t.next 为None 表示已经到了行索引列表的末尾了,这个时候就要跳到下一层了。。

从上到下,把找到的所有节点 按照先后顺序放入到path 这个list当中,最后要做的工作就是 在这些节点的后边插入新节点就好。。。

index = len(path) - 1
downtmp = None
while index >=0:
    pn = path[index]
    node = SkipNode(data)
    node.next = pn.next
    pn.next = node
    node.down = downtmp
    downtmp = node
    index -= 1

由于要设置down指针,所以逆序遍历这些节点就好了。。。。

搜索节点分析

当前节点值data和要查找的data 一样 那就不说了 这就是要找的节点。。。

如果data值不等,那就先看看下一个节点,如果next 不存在 直接跳到下一层,如果next存在,值比search data值小,那就next 继续查  否则就要跳到下一层,逻辑还是比较简单的。。

删除节点分析

删除节点和添加节点类似,要找到前驱节点,因为删除节点的时候,节点的前驱节点的next指针要更新的。。。。

如果当前节点t的next的data 和 data 想等,直接t.next = t.next.next 然后t = t.down 直接跳到下一层

如果当前节点t的next的data和data 不等,就要判断大小关系,next.data < data 可以继续next,否则就要在当前节点跳到下一层。。。

def main():
    import random
    skip = SkipList(5)
    datalist = []
    for i in range(30):
        x = random.randint(1,1000)
        if x not in datalist:
            datalist.append(x)
    for x in datalist:
        skip.insert(x)
    f = datalist[10]
    skip.dump()
    print(skip.search(f))
    print("###########################")
    skip.delete(f)
    skip.dump()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值