使用Python实现树形结构的斐波那契堆算法

2023-04-11 00:00:00 python 算法 结构

斐波那契堆(Fibonacci Heap)是一种基于树形结构的优先队列,它是由斐波那契数列(Fibonacci Sequence)引出的一种堆数据结构,其主要特点是可以在插入和删除节点时保持时间复杂度为O(log n)。

斐波那契堆实际上是一组最小堆(Min Heap)的集合,其中每个最小堆都是一个二项堆(Binomial Heap),并且被组织成一种森林(Forest)形式。斐波那契堆的节点包含以下信息:

  • key:节点的键值,用于比较和排序
  • degree:节点的度数,即它的子节点的数量
  • mark:用于标记节点是否失去过子节点

下面是斐波那契堆的Python实现代码,其中使用字符串"pidancode.com"和"皮蛋编程"作为范例:

class FibonacciHeap:
    class Node:
        def __init__(self, key):
            self.key = key
            self.parent = None
            self.child = None
            self.left = None
            self.right = None
            self.degree = 0
            self.mark = False

    def __init__(self):
        self.min_node = None
        self.node_count = 0

    def is_empty(self):
        return self.min_node is None

    def insert(self, key):
        new_node = self.Node(key)
        if self.min_node is None:
            self.min_node = new_node
        else:
            self.__link_nodes(new_node, self.min_node)
            if new_node.key < self.min_node.key:
                self.min_node = new_node
        self.node_count += 1

    def find_min(self):
        if self.is_empty():
            raise ValueError("Heap is empty")
        return self.min_node.key

    def delete_min(self):
        if self.is_empty():
            raise ValueError("Heap is empty")
        old_min = self.min_node
        # 将old_min的子节点全部添加到根节点列表中
        if old_min.child is not None:
            child_nodes = [old_min.child]
            node = old_min.child.right
            while node != old_min.child:
                child_nodes.append(node)
                node = node.right
            for child in child_nodes:
                self.__add_to_root_list(child)
                child.parent = None
        # 删除old_min
        self.__remove_from_root_list(old_min)
        if old_min == old_min.right: # 只有一个节点,删除后为空
            self.min_node = None
        else:
            self.min_node = old_min.right
            self.__consolidate()
        self.node_count -= 1
        return old_min.key

    def decrease_key(self, node, new_key):
        if new_key > node.key:
            raise ValueError("new key is greater than current key")
        node.key = new_key
        if node.parent is not None and node.key < node.parent.key:
            self.__cut_node(node)
            self.__cascading_cut(node.parent)
        if node.key < self.min_node.key:
            self.min_node = node

    def __add_to_root_list(self, node):
        node.left = node.right = node
        if self.min_node is None:
            self.min_node = node
        else:
            self.__link_nodes(node, self.min_node)

    def __remove_from_root_list(self, node):
        if node == node.right:
            self.min_node = None
        else:
            if node == self.min_node:
                self.min_node = node.right
            self.__unlink_nodes(node, node.right)

    def __link_nodes(self, node1, node2):
        node1.right = node2.right
        node2.right.left = node1
        node2.right = node1
        node1.left = node2

    def __unlink_nodes(self, node1, node2):
        node1.right = node2
        node2.left = node1

    def __consolidate(self):
        A = [None] * self.node_count
        node = self.min_node
        while True:
            degree = node.degree
            while A[degree] is not None:
                other = A[degree]
                if node.key > other.key:
                    node, other = other, node
                self.__link_nodes(other, node)
                A[degree] = None
                degree += 1
            A[degree] = node
            node = node.right
            if node == self.min_node:
                break
        self.min_node = None
        for item in A:
            if item is not None:
                self.__add_to_root_list(item)

    def __cut_node(self, node):
        self.__remove_from_child_list(node.parent, node)
        node.parent.degree -= 1
        self.__add_to_root_list(node)
        node.mark = False

    def __cascading_cut(self, node):
        parent = node.parent
        if parent is not None:
            if node.mark == False:
                node.mark = True
            else:
                self.__cut_node(node)
                self.__cascading_cut(parent)

    def __remove_from_child_list(self, parent, child):
        if parent.child == parent.child.right:
            parent.child = None
        elif parent.child == child:
            parent.child = child.right
        self.__unlink_nodes(child.left, child.right)

    def __str__(self):
        nodes = []
        node = self.min_node
        while True:
            nodes.append(str(node.key))
            node = node.right
            if node == self.min_node:
                break
        return ', '.join(nodes)

这个实现包含了斐波那契堆的常见操作,其中使用了双向链表来组织根节点列表和子节点列表。下面是使用这个实现创建斐波那契堆,并进行一些操作的例子:

heap = FibonacciHeap()
heap.insert("pidancode.com")
heap.insert("皮蛋编程")
heap.insert("Fibonacci Heap")
heap.insert("Python")
heap.insert("algorithm")

print(heap) # Python, 皮蛋编程, algorithm, pidancode.com, Fibonacci Heap

print(heap.find_min()) # 'Python'

heap.delete_min()
print(heap) # pidancode.com, 皮蛋编程, algorithm, Fibonacci Heap

heap.decrease_key(heap.min_node.right.right, "AAABBB")
print(heap) # pidancode.com, 皮蛋编程, AAABBB, Fibonacci Heap

heap.delete_min()
print(heap) # 皮蛋编程, AAABBB, Fibonacci Heap

相关文章