美文网首页
跳跃表python实践

跳跃表python实践

作者: 钢筋铁骨 | 来源:发表于2020-04-14 15:43 被阅读0次

    redis的zset常用场景:
    统计日活;打赏排行榜;天梯榜等
    zset底层基于跳跃表实现

    跳跃表代码实现,练习版

    import random
    random.seed(1)
    MAX_LEVEL = 4
    
    
    def randomLevel():
        """
        跳表的节点高度计算函数
        """
        k = 0
        while random.randint(0, 1):
            k += 1
        k = k if k < MAX_LEVEL else MAX_LEVEL
        return k
    
    
    def travel(skiplist):
        """
        遍历跳表,当成二维数组来思考
        :param skiplist:
        :return:
        """
        head = skiplist.head # head负责往下走
        print ("遍历跳表开始")
        while head:
            level_str = 'header'
            current = head # current负责往右走
            while current.right:
                current = current.right
                level_str += " -> %s" % (current.key)
            print (level_str)
            head = head.down
        print ("遍历跳表结束")
    
    
    class Node(object):
        def __init__(self, key, value=None, extra_data={}, level=0):
            self.key = key
            self.value = value
            self.extra_data = extra_data
            self.level = level
            self.right = None
            self.down = None
    
    
    class SkipList(object):
    
        def __init__(self):
            self.head = Node(float('-inf'))
            self.head.right = Node(float('inf'))
    
        def search(self, target):
            """未验证"""
            current = self.head
            while current:
                if current.key < target <= current.right.key:
                    if current.right.key == target:
                        print ("找到节点:", current.key, current.value)
                        return True
                    current = current.down
                else:
                    current = current.right
            return False
    
        def find_node(self, target):
            """递归的写法"""
            return self.searchNode(self.head, target)
    
        def searchNode(self, node, key):
            while key >= node.right.key:
                node = node.right
            if key == node.key:
                print ("找到节点:", node.key, node.extra_data, "层:", node.level)
                return True
            if node.down == None:
                return False
            return self.searchNode(node.down, key)
    
        def insertNode(self, current, key, value):
            while key >= current.right.key:
                current = current.right
            # 为什么return None,因为跳表的key是唯一的,redis的zset中,如果key已经存在,则根据该元素的score更新排名
            if key == current.key:
                return None
            # 已经走到了level 0层时的逻辑
            if current.down == None:
                node = Node(key, value) # node是插入的节点
                # eg: 在5 --> 15 之间插入Node(10),此时current是Node(5)
                node.right = current.right
                current.right = node
                node.level = current.level
                return node
            downnode = self.insertNode(current.down, key, value)
            if downnode: # 这里处理的是上一层
                node = Node(key)
                node.right = current.right
                current.right = node
                node.down = downnode
                node.level = current.level
                return node
            return None
    
        def insert(self, key, value):
            k = randomLevel()
            # 如果k和self.head.level都是0时,说明不用建高速,直接在0层添加即可
            # 如果k=1,self.head.level是0时,就需要一层一层网上找,找到最高层,for循环是为了把这几层的边界弄出来
            for l in range(self.head.level+1, k+1):
            #   这个地方画图想象,先获取上一层的左右,最左.right指向最右;
            #   最左.down指向下一层的head(刚好是self.head),然后让self.head爬楼升1
                headleft, headright = Node(float("-inf"), level=l), Node(float("inf"), level=l)
                headleft.right = headright
                headleft.down = self.head
                self.head = headleft
            head = self.head # 跳表最高层的头
            while head.level != k:
                head = head.down
            self.insertNode(head, key, value)
            print ("k=%s, key=%s, value=%s, insert OK" %(k, key, value))
    
        def erase(self, num):
            current = self.head
            is_removed = False
            while current:
                if current.val < num <= current.right.val:
                    if current.right.val == num:
                        current.right = current.right.right
                        is_removed = True
                    current = current.down
                else:
                    current = current.right
            return is_removed
    
    
    if __name__ == '__main__':
        skiplist = SkipList()
        skiplist.insert(4, random.randint(1,100))
        skiplist.insert(5, random.randint(1,100))
        skiplist.insert(15, random.randint(1,100))
        skiplist.insert(25, random.randint(1,100))
        skiplist.insert(35, random.randint(1,100))
        print (skiplist.find_node(25))
        print (skiplist.find_node(15))
        travel(skiplist=skiplist)
    

    相关文章

      网友评论

          本文标题:跳跃表python实践

          本文链接:https://www.haomeiwen.com/subject/qdrtvhtx.html