[算法沉淀记录] 排序算法 —— 堆排序

news2024/11/23 12:22:22

排序算法 —— 堆排序

算法基础介绍

堆排序(Heap Sort)是一种基于比较的排序算法,它利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树,其中每个节点的值都必须大于或等于(最大堆)或小于或等于(最小堆)其子节点的值。

基本概念

堆是一个近似完全二叉树的数据结构,满足任一非叶子节点的值不小于(或不大于)其左右孩子节点的值。堆通常分为最大堆和最小堆:

  • 最大堆:每个节点的值都大于或等于其子节点的值。
  • 最小堆:每个节点的值都小于或等于其子节点的值。

堆排序算法通过构建一个最大堆或最小堆,然后将堆顶元素(最大或最小值)与堆的最后一个元素交换,再将剩余的元素重新调整为最大堆或最小堆,如此反复,直到整个数组有序。

算法步骤

  1. 构建堆:将无序的输入数组转换为一个最大堆或最小堆。
  2. 堆排序
    • 将堆顶元素(最大或最小值)与堆的最后一个元素交换,将其移出堆。
    • 调整剩余元素,使其重新成为一个最大堆或最小堆。
    • 重复上述步骤,直到所有元素都被移出堆。

伪代码描述

function heapsort(array)
    build_max_heap(array)
    for end from size(array) down to 2 do
        swap array[1] with array[end]
        heap_size = heap_size - 1
        sift_down(array, 1)
    end for
end function

堆排序是一种高效的排序算法,具有以下优缺点:

优点

  1. 时间复杂度稳定:堆排序的时间复杂度为(O(nlog(n))),其中n是数组的长度。这个复杂度在所有比较排序算法中是最优的,因为比较排序的最坏时间复杂度为(O(nlog(n)))。
  2. 空间复杂度低:堆排序是原地排序,除了常数个额外空间用于存储递归栈之外,不需要额外的内存空间。
  3. 不稳定的排序算法:堆排序是不稳定的排序算法,这意味着如果两个元素相等,它们的相对顺序在排序后可能会改变。
  4. 适用于各种数据类型:堆排序可以适用于各种数据类型,包括整数、浮点数、字符串等,只要能够为这些数据类型定义合适的比较操作。
  5. 易于实现:堆排序的实现相对简单,尤其是使用二叉堆的实现。

缺点

  1. 最坏情况性能差:虽然平均时间复杂度为(O(nlog(n))),但在最坏情况下(输入数据完全逆序),堆排序的时间复杂度退化为(O(n^2))。
  2. 不稳定排序:对于某些需要稳定排序的应用场景(如数据库索引),堆排序可能不是最佳选择。
  3. 对内存要求高:虽然空间复杂度低,但在排序过程中,堆中的元素可能会频繁地移动,这可能导致较高的内存访问开销。
  4. 初始化堆的时间开销:虽然堆排序的总时间复杂度是(O(nlog(n))),但这个复杂度是在整个排序过程中累积的。在实际应用中,构建初始堆的过程可能会占用一定的时间。

总体而言,堆排序是一个在实际应用中广泛使用的排序算法,特别是当内存使用是一个关键因素时。然而,对于需要稳定排序的应用,或者当数据已经部分有序时,可能需要考虑其他排序算法,如归并排序或快速排序

应用场景

堆排序在实际开发过程中的常见应用场景包括:

  1. 优先级队列:堆排序是优先级队列实现的基础。在许多编程语言中,优先级队列(或称为最小堆)就是基于堆排序原理实现的。这种数据结构允许快速插入和删除最小元素,常用于任务调度、事件处理等场景。
  2. 排序算法比较:在开发中,为了验证新算法的性能,开发者可能会将堆排序与其他排序算法(如快速排序、归并排序)进行比较。堆排序因其简单性和稳定性,常作为基准算法之一。
  3. 数据挖掘:在数据挖掘和机器学习领域,堆排序可用于处理大规模数据集的预处理步骤,如特征选择、频繁项集挖掘等。
  4. 文件系统:堆排序可用于文件系统的目录排序,帮助用户快速找到文件。
  5. 数据库索引:虽然数据库通常使用B树或B+树索引,但在某些特殊情况下,堆排序可以作为辅助算法来优化索引的构建过程。
  6. 缓存管理:在缓存管理系统中,堆排序可用于维护缓存数据的有序性,例如,根据最近最少使用(LRU)策略来淘汰缓存项。
  7. 算法教学:堆排序是计算机科学教育中常用的教学示例,用于讲解数据结构和算法的概念。
  8. 图形处理:在图形处理中,堆排序可用于顶点排序,以便于后续的图形操作,如生成凸包、计算几何形状的交点等。
  9. 游戏开发:在游戏开发中,堆排序可用于实现游戏对象的优先级处理,例如,根据对象的属性(如生命值、攻击力等)对对象进行排序。
  10. 网络协议:在网络协议处理中,堆排序可用于数据包的优先级处理,确保高优先级的数据包得到优先处理。

堆排序的优点,如时间复杂度的稳定性和低空间复杂度,使其在需要快速、高效处理大规模数据的场景中非常有用。然而,它的不稳定性也是一个需要注意的点,特别是在需要保持数据相对顺序的应用中。

时间复杂度

最佳情况

在最佳情况下,输入数组已经是有序的,堆排序只需要进行一次建堆操作,然后进行一次简单的调整即可完成排序。因此,最佳情况下的时间复杂度是 (O(n))。

最坏情况

在最坏情况下,输入数组是完全逆序的,需要进行 n-1 次建堆操作,并且每次调整堆都需要将堆中的元素重新排列。因此,最坏情况下的时间复杂度是 (O(n^2))。

平均情况

在平均情况下,堆排序的时间复杂度是 (O(nlog(n)))。这是因为虽然最坏情况下的时间复杂度是 (O(n^2)),但在大多数实际应用中,数据并不是完全逆序的,因此平均时间复杂度更接近于 (O(nlog(n)))。

空间复杂度

堆排序是一个原地排序算法,除了用于存储递归栈的常数空间之外,不需要额外的内存空间。因此,空间复杂度是 (O(1))。

证明

时间复杂度证明
  1. 建堆操作:建堆操作的时间复杂度是 (O(n))。
  2. 调整堆:调整堆的时间复杂度是 (O(n))。
  3. 排序过程:排序过程需要进行 n-1 次调整堆的操作。
    综合以上,堆排序的总时间复杂度是 (O(n + (n-1) * O(n)) = O(n^2))。
空间复杂度证明

堆排序是一个原地排序算法,除了用于存储递归栈的常数空间之外,不需要额外的内存空间。因此,空间复杂度是 (O(1))。
综上所述,堆排序的时间复杂度在最佳情况下为 (O(n)),最坏情况下为 (O(n^2)),平均情况下为 (O(nlog(n))),空间复杂度为 (O(1))。

代码实现

Python 实现

def heapify(arr, n, i):
    largest = i
    left = 2 * i + 1
    right = 2 * i + 2

    if left < n and arr[i] < arr[left]:
        largest = left

    if right < n and arr[largest] < arr[right]:
        largest = right

    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heapsort(arr):
    n = len(arr)

    for i in range(n//2 - 1, -1, -1):
        heapify(arr, n, i)

    for i in range(n-1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

C++ 模板实现

Java 实现

扩展阅读

堆排序的时间复杂度优化主要集中在减少建堆和调整堆的次数上。以下是一些常见的优化方法:

时间复杂度的优化方法

  1. 减少比较次数:通过减少不必要的比较,可以减少建堆和调整堆的时间。例如,可以使用二叉堆的路径压缩技术,在调整堆的过程中减少子节点与父节点的比较次数。
  2. 使用斐波那契堆:斐波那契堆是一种数据结构,它可以在O(log n)的时间内完成堆的插入、删除和合并操作。这比二叉堆的O(log n)复杂度更优。
  3. 延迟删除:在某些实现中,为了避免频繁地调整堆,可以延迟删除操作,直到需要的时候才进行。
  4. 减少调整堆的次数:通过选择合适的堆大小和调整策略,可以减少调整堆的次数。

历史上常用的堆排序的变种算法

  1. 斐波那契堆:斐波那契堆是一种改进的堆数据结构,它可以在O(log n)的时间内完成堆的插入、删除和合并操作,比二叉堆更优。
  2. 二叉堆:二叉堆是最常见的堆实现,它包括最大堆和最小堆。二叉堆的调整操作通常需要O(log n)的时间复杂度。
  3. 左倾堆:左倾堆是一种特殊的堆实现,它通过减少堆的平衡调整次数来优化性能。
  4. 二项堆:二项堆是一种特殊的堆实现,它使用二项树的性质来优化堆的插入和删除操作。
  5. 二叉索引堆:二叉索引堆是一种结合了二叉堆和二叉树索引的数据结构,它可以在O(log n)的时间内完成堆的插入、删除和合并操作。

这些变种算法的目的是通过优化堆的实现细节,减少堆排序的时间复杂度,使其在实际应用中更加高效。在选择堆排序的变种算法时,需要考虑数据的特点和应用场景,以确定最适合的算法。

斐波那契堆排序

斐波那契堆排序(Fibonacci Heap Sort)是一种堆排序的变种,由Michael L. Fredman, Robert Sedgewick, Daniel D. Sleator, 和Robert E. Tarjan在1986年提出。斐波那契堆是一种数据结构,它提供了一种堆操作的实现,这些操作包括插入、删除最小元素、删除最小元素的父节点等,其时间复杂度几乎都是O(log n)。

基本概念

斐波那契堆是一种堆数据结构,它支持以下操作:

  • 插入:将一个元素添加到堆中。
  • 删除最小元素:移除堆中的最小元素。
  • 删除最小元素的父节点:移除并返回堆中与最小元素具有相同父节点的最小元素。
  • 合并:将两个斐波那契堆合并成一个堆。
    斐波那契堆通过减少堆的平衡调整次数来优化性能。在斐波那契堆中,插入和删除操作通常需要O(log n)的时间复杂度,而传统的二叉堆通常需要O(log n)的复杂度。
算法步骤

斐波那契堆排序的基本步骤如下:

  1. 初始化:创建一个空的斐波那契堆。
  2. 插入元素:将所有待排序的元素插入到斐波那契堆中。
  3. 删除最小元素:重复执行以下操作,直到堆中只剩下一个元素:
    • 删除并返回堆中的最小元素。
    • 将删除元素的后继节点(如果有)插入到堆中。
  4. 排序完成:最后剩下的元素是排序后的第一个元素。
伪代码描述
斐波那契堆排序(A)
    创建一个空的斐波那契堆
    对于每个元素x in A
        插入(斐波那契堆, x)
    while 斐波那契堆中元素数量 > 1
        删除并返回最小元素(斐波那契堆)
        将删除元素的后继节点插入(斐波那契堆)
    返回堆中剩下的元素
Python 代码实现
class FibonacciHeap:

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

    # function to iterate through a doubly linked list
    def iterate(self, head):
        node = stop = head
        flag = False
        while True:
            if node == stop and flag is True:
                break
            elif node == stop:
                flag = True
            yield node
            node = node.right

    # pointer to the head and minimum node in the root list
    root_list, min_node = None, None

    # maintain total node count in full fibonacci heap
    total_nodes = 0

    # return min node in O(1) time
    def find_min(self):
        return self.min_node

    # extract (delete) the min node from the heap in O(log n) time
    # amortized cost analysis can be found here (http://bit.ly/1ow1Clm)
    def extract_min(self):
        z = self.min_node
        if z is not None:
            if z.child is not None:
                # attach child nodes to root list
                children = [x for x in self.iterate(z.child)]
                for i in range(0, len(children)):
                    self.merge_with_root_list(children[i])
                    children[i].parent = None
            self.remove_from_root_list(z)
            # set new min node in heap
            if z == z.right:
                self.min_node = self.root_list = None
            else:
                self.min_node = z.right
                self.consolidate()
            self.total_nodes -= 1
        return z

    # insert new node into the unordered root list in O(1) time
    # returns the node so that it can be used for decrease_key later
    def insert(self, key, value=None):
        n = self.Node(key, value)
        n.left = n.right = n
        self.merge_with_root_list(n)
        if self.min_node is None or n.key < self.min_node.key:
            self.min_node = n
        self.total_nodes += 1
        return n

    # modify the key of some node in the heap in O(1) time
    def decrease_key(self, x, k):
        if k > x.key:
            return None
        x.key = k
        y = x.parent
        if y is not None and x.key < y.key:
            self.cut(x, y)
            self.cascading_cut(y)
        if x.key < self.min_node.key:
            self.min_node = x

    # merge two fibonacci heaps in O(1) time by concatenating the root lists
    # the root of the new root list becomes equal to the first list and the second
    # list is simply appended to the end (then the proper min node is determined)
    def merge(self, h2):
        H = FibonacciHeap()
        H.root_list, H.min_node = self.root_list, self.min_node
        # fix pointers when merging the two heaps
        last = h2.root_list.left
        h2.root_list.left = H.root_list.left
        H.root_list.left.right = h2.root_list
        H.root_list.left = last
        H.root_list.left.right = H.root_list
        # update min node if needed
        if h2.min_node.key < H.min_node.key:
            H.min_node = h2.min_node
        # update total nodes
        H.total_nodes = self.total_nodes + h2.total_nodes
        return H

    # if a child node becomes smaller than its parent node we
    # cut this child node off and bring it up to the root list
    def cut(self, x, y):
        self.remove_from_child_list(y, x)
        y.degree -= 1
        self.merge_with_root_list(x)
        x.parent = None
        x.mark = False

    # cascading cut of parent node to obtain good time bounds
    def cascading_cut(self, y):
        z = y.parent
        if z is not None:
            if y.mark is False:
                y.mark = True
            else:
                self.cut(y, z)
                self.cascading_cut(z)

    # combine root nodes of equal degree to consolidate the heap
    # by creating a list of unordered binomial trees
    def consolidate(self):
        A = [None] * int(math.log(self.total_nodes) * 2)
        nodes = [w for w in self.iterate(self.root_list)]
        for w in range(0, len(nodes)):
            x = nodes[w]
            d = x.degree
            while A[d] != None:
                y = A[d]
                if x.key > y.key:
                    temp = x
                    x, y = y, temp
                self.heap_link(y, x)
                A[d] = None
                d += 1
            A[d] = x
        # find new min node - no need to reconstruct new root list below
        # because root list was iteratively changing as we were moving
        # nodes around in the above loop
        for i in range(0, len(A)):
            if A[i] is not None:
                if A[i].key < self.min_node.key:
                    self.min_node = A[i]

    # actual linking of one node to another in the root list
    # while also updating the child linked list
    def heap_link(self, y, x):
        self.remove_from_root_list(y)
        y.left = y.right = y
        self.merge_with_child_list(x, y)
        x.degree += 1
        y.parent = x
        y.mark = False

    # merge a node with the doubly linked root list
    def merge_with_root_list(self, node):
        if self.root_list is None:
            self.root_list = node
        else:
            node.right = self.root_list.right
            node.left = self.root_list
            self.root_list.right.left = node
            self.root_list.right = node

    # merge a node with the doubly linked child list of a root node
    def merge_with_child_list(self, parent, node):
        if parent.child is None:
            parent.child = node
        else:
            node.right = parent.child.right
            node.left = parent.child
            parent.child.right.left = node
            parent.child.right = node

    # remove a node from the doubly linked root list
    def remove_from_root_list(self, node):
        if node == self.root_list:
            self.root_list = node.right
        node.left.right = node.right
        node.right.left = node.left

    # remove a node from the doubly linked child list
    def remove_from_child_list(self, parent, node):
        if parent.child == parent.child.right:
            parent.child = None
        elif parent.child == node:
            parent.child = node.right
            node.right.parent = parent
        node.left.right = node.right
        node.right.left = node.left
        
def fibonacci_heap_sort(arr):
    heap = FibonacciHeap()
    for key in arr:
        heap.insert(key)
    sorted_arr = []
    while heap.total_nodes > 0:
        sorted_arr.append(heap.extract_min().key)
    return sorted_arr
C++模板代码实现
template <class V>
class FibonacciHeap;

template <class V>
struct node
{
private:
    node<V> *prev;
    node<V> *next;
    node<V> *child;
    node<V> *parent;
    V value;
    int degree;
    bool marked;

public:
    friend class FibonacciHeap<V>;
    node<V> *getPrev() { return prev; }
    node<V> *getNext() { return next; }
    node<V> *getChild() { return child; }
    node<V> *getParent() { return parent; }
    V getValue() { return value; }
    bool isMarked() { return marked; }

    bool hasChildren() { return child; }
    bool hasParent() { return parent; }
};

template <class V>
class FibonacciHeap
{
protected:
    node<V> *heap;

public:
    FibonacciHeap()
    {
        heap = _empty();
    }

    virtual ~FibonacciHeap()
    {
        if (heap)
        {
            _deleteAll(heap);
        }
    }

    node<V> *insert(V value)
    {
        node<V> *ret = _singleton(value);
        heap = _merge(heap, ret);
        return ret;
    }

    void merge(FibonacciHeap &other)
    {
        heap = _merge(heap, other.heap);
        other.heap = _empty();
    }

    bool isEmpty()
    {
        return heap == nullptr;
    }

    V getMinimum()
    {
        return heap->value;
    }

    V removeMinimum()
    {
        node<V> *old = heap;
        heap = _removeMinimum(heap);
        V ret = old->value;
        delete old;
        return ret;
    }

    void decreaseKey(node<V> *n, V value)
    {
        heap = _decreaseKey(heap, n, value);
    }

    node<V> *find(V value)
    {
        return _find(heap, value);
    }

private:
    node<V> *_empty()
    {
        return nullptr;
    }

    node<V> *_singleton(V value)
    {
        node<V> *n = new node<V>;
        n->value = value;
        n->prev = n->next = n;
        n->degree = 0;
        n->marked = false;
        n->child = nullptr;
        n->parent = nullptr;
        return n;
    }

    node<V> *_merge(node<V> *a, node<V> *b)
    {
        if (a == nullptr)
            return b;
        if (b == nullptr)
            return a;
        if (a->value > b->value)
        {
            node<V> *temp = a;
            a = b;
            b = temp;
        }
        node<V> *an = a->next;
        node<V> *bp = b->prev;
        a->next = b;
        b->prev = a;
        an->prev = bp;
        bp->next = an;
        return a;
    }

    void _deleteAll(node<V> *n)
    {
        if (n != nullptr)
        {
            node<V> *c = n;
            do
            {
                node<V> *d = c;
                c = c->next;
                _deleteAll(d->child);
                delete d;
            } while (c != n);
        }
    }

    void _addChild(node<V> *parent, node<V> *child)
    {
        child->prev = child->next = child;
        child->parent = parent;
        parent->degree++;
        parent->child = _merge(parent->child, child);
    }

    void _unMarkAndUnParentAll(node<V> *n)
    {
        if (n == nullptr)
            return;
        node<V> *c = n;
        do
        {
            c->marked = false;
            c->parent = nullptr;
            c = c->next;
        } while (c != n);
    }

    node<V> *_removeMinimum(node<V> *n)
    {
        _unMarkAndUnParentAll(n->child);
        if (n->next == n)
        {
            n = n->child;
        }
        else
        {
            n->next->prev = n->prev;
            n->prev->next = n->next;
            n = _merge(n->next, n->child);
        }
        if (n == nullptr)
            return n;
        node<V> *trees[64] = {nullptr};

        while (true)
        {
            if (trees[n->degree] != nullptr)
            {
                node<V> *t = trees[n->degree];
                if (t == n)
                    break;
                trees[n->degree] = nullptr;
                if (n->value < t->value)
                {
                    t->prev->next = t->next;
                    t->next->prev = t->prev;
                    _addChild(n, t);
                }
                else
                {
                    t->prev->next = t->next;
                    t->next->prev = t->prev;
                    if (n->next == n)
                    {
                        t->next = t->prev = t;
                        _addChild(t, n);
                        n = t;
                    }
                    else
                    {
                        n->prev->next = t;
                        n->next->prev = t;
                        t->next = n->next;
                        t->prev = n->prev;
                        _addChild(t, n);
                        n = t;
                    }
                }
                continue;
            }
            else
            {
                trees[n->degree] = n;
            }
            n = n->next;
        }
        node<V> *min = n;
        node<V> *start = n;
        do
        {
            if (n->value < min->value)
                min = n;
            n = n->next;
        } while (n != start);
        return min;
    }

    node<V> *_cut(node<V> *heap, node<V> *n)
    {
        if (n->next == n)
        {
            n->parent->child = nullptr;
        }
        else
        {
            n->next->prev = n->prev;
            n->prev->next = n->next;
            n->parent->child = n->next;
        }
        n->next = n->prev = n;
        n->marked = false;
        return _merge(heap, n);
    }

    node<V> *_decreaseKey(node<V> *heap, node<V> *n, V value)
    {
        if (n->value < value)
            return heap;
        n->value = value;
        if (n->parent)
        {
            if (n->value < n->parent->value)
            {
                heap = _cut(heap, n);
                node<V> *parent = n->parent;
                n->parent = nullptr;
                while (parent != nullptr && parent->marked)
                {
                    heap = _cut(heap, parent);
                    n = parent;
                    parent = n->parent;
                    n->parent = nullptr;
                }
                if (parent != nullptr && parent->parent != nullptr)
                    parent->marked = true;
            }
        }
        else
        {
            if (n->value < heap->value)
            {
                heap = n;
            }
        }
        return heap;
    }

    node<V> *_find(node<V> *heap, V value)
    {
        node<V> *n = heap;
        if (n == nullptr)
            return nullptr;
        do
        {
            if (n->value == value)
                return n;
            node<V> *ret = _find(n->child, value);
            if (ret)
                return ret;
            n = n->next;
        } while (n != heap);
        return nullptr;
    }
};

template <class T>
void FibonacciHeapSort(vector<T> &data)
{
    FibonacciHeap<T> heap;
    auto dataSize = data.size();
    for (auto i = 0; i < dataSize; i++)
        heap.insert(data[i]);
    for (auto i = 0; i < dataSize; i++)
        data[i] = heap.removeMinimum();
}

二叉堆排序

二叉堆排序是一种基于比较的排序算法,它利用二叉堆这种数据结构来进行排序。二叉堆是一种特殊的堆,它是一个近似完全二叉树,满足任一非叶子节点的值不大于或不小于其左右孩子节点的值。根据堆的这一特性,二叉堆分为最大堆和最小堆。在最大堆中,每个父节点的值都大于或等于其孩子节点的值;在最小堆中,每个父节点的值都小于或等于其孩子节点的值。

基本概念
  1. 二叉堆的性质:对于最大堆,每个父节点的值都大于或等于其孩子节点的值;对于最小堆,每个父节点的值都小于或等于其孩子节点的值。
  2. 堆的表示:通常使用数组来表示堆,对于任意节点i(假设数组从1开始索引),其左孩子为2i,右孩子为2i+1,父节点为i/2(向下取整)。
算法步骤
  1. 构建堆:将无序数组构造成一个最大堆(或最小堆)。
  2. 调整堆:将堆顶元素(最大或最小值)与数组末尾元素交换,然后调整堆,使其满足堆的性质。
  3. 重复调整:重复步骤2,直到堆中只剩下一个元素,此时数组已排序。
伪代码
二叉堆排序(array):
    构建最大堆(array)
    for i = length(array) downto 2:
        交换array[1]和array[i]
        调整堆(array, 1, i - 1)
    end for
end 二叉堆排序
构建最大堆(array):
    n = length(array)
    for i = n/2 downto 1:
        调整堆(array, i, n)
    end for
end 构建最大堆
调整堆(array, i, n):
    while 2*i <= n:
        j = 2*i
        if j + 1 <= n and array[j] < array[j + 1]:
            j = j + 1
        if array[i] < array[j]:
            交换array[i]和array[j]
            i = j
        else:
            break
    end while
end 调整堆
Python代码实现
class MaxHeap:
    def __init__(self):
        self.heap = []
    def parent(self, i):
        return (i - 1) // 2
    def left_child(self, i):
        return 2 * i + 1
    def right_child(self, i):
        return 2 * i + 2
    def has_left_child(self, i):
        return self.left_child(i) < len(self.heap)
    def has_right_child(self, i):
        return self.right_child(i) < len(self.heap)
    def swap(self, i, j):
        self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
    def heapify_up(self, i):
        while i > 0 and self.heap[self.parent(i)] < self.heap[i]:
            self.swap(i, self.parent(i))
            i = self.parent(i)
    def heapify_down(self, i):
        largest = i
        if self.has_left_child(i) and self.heap[self.left_child(i)] > self.heap[largest]:
            largest = self.left_child(i)
        if self.has_right_child(i) and self.heap[self.right_child(i)] > self.heap[largest]:
            largest = self.right_child(i)
        if largest != i:
            self.swap(i, largest)
            self.heapify_down(largest)
    def insert(self, key):
        self.heap.append(key)
        self.heapify_up(len(self.heap) - 1)
    def extract_max(self):
        if len(self.heap) == 0:
            return None
        max_value = self.heap[0]
        self.heap[0] = self.heap[-1]
        self.heap.pop()
        self.heapify_down(0)
        return max_value
    def build_heap(self, arr):
        self.heap = arr.copy()
        for i in range(len(self.heap) // 2, -1, -1):
            self.heapify_down(i)
    def is_empty(self):
        return len(self.heap) == 0
    def get_max(self):
        if self.is_empty():
            return None
        return self.heap[0]
    def __str__(self):
        return str(self.heap)
    
def max_heap_sort(arr):
    max_heap = MaxHeap()
    max_heap.build_heap(arr)
    sorted_arr = []
    while not max_heap.is_empty():
        sorted_arr.append(max_heap.extract_max())
    return sorted_arr[::-1]  # Reverse to get ascending order
C++模板实现
#include <iostream>
#include <vector>
#include <algorithm>

template <typename T>
void maxHeapify(std::vector<T>& arr, int i, int n) {
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    int largest = i;
    if (left < n && arr[left] > arr[largest]) {
        largest = left;
    }
    if (right < n && arr[right] > arr[largest]) {
        largest = right;
    }
    if (largest != i) {
        std::swap(arr[i], arr[largest]);
        maxHeapify(arr, largest, n);
    }
}

template <typename T>
void heapSort(std::vector<T>& arr) {
    int n = arr.size();
    // Build max heap
    for (int i = n / 2 - 1; i >= 0; i--) {
        maxHeapify(arr, i, n);
    }
    // Extract elements from heap
    for (int i = n - 1; i >= 0; i--) {
        std::swap(arr[0], arr[i]);
        maxHeapify(arr, 0, i);
    }
}

这段代码首先定义了一个maxHeapify函数,用于调整堆,使其满足最大堆的性质。然后定义了heapSort函数,该函数首先构建一个最大堆,然后通过不断将堆顶元素与数组末尾元素交换并调整堆,实现了排序。最后在main函数中测试了排序算法。

二叉堆实现
template <typename T>
class BinaryHeap
{
private:
    vector<T> heap;
    // 用于将新插入的元素上浮到正确位置
    void siftUp(int index)
    {
        while (index > 0 && heap[(index - 1) / 2] < heap[index])
        {
            swap(heap[index], heap[(index - 1) / 2]);
            index = (index - 1) / 2;
        }
    }
    // 用于将堆顶元素下沉到正确位置
    void siftDown(int index)
    {
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int largest = index;
        if (left < heap.size() && heap[left] > heap[largest])
        {
            largest = left;
        }
        if (right < heap.size() && heap[right] > heap[largest])
        {
            largest = right;
        }
        if (largest != index)
        {
            swap(heap[index], heap[largest]);
            siftDown(largest);
        }
    }

public:
    BinaryHeap() {}
    // 插入元素
    void insert(T value)
    {
        heap.push_back(value);
        siftUp(heap.size() - 1);
    }
    // 删除堆顶元素
    void remove()
    {
        if (heap.empty())
        {
            return;
        }
        heap[0] = heap.back();
        heap.pop_back();
        if (!heap.empty())
        {
            siftDown(0);
        }
    }
    // 获取堆顶元素
    T peek() const
    {
        if (heap.empty())
        {
            throw out_of_range("Heap is empty");
        }
        return heap[0];
    }
    // 获取并删除顶元素
    T pop()
    {
        T value = peek();
        remove();
        return value;
    }
    // 判断堆是否为空
    bool isEmpty() const
    {
        return heap.empty();
    }
    // 输出堆中的元素
    void print() const
    {
        for (const auto &elem : heap)
        {
            cout << elem << " ";
        }
        cout << endl;
    }
};

template <class T>
void BinaryHeapSort(vector<T> &data)
{
    BinaryHeap<T> heap;
    auto dataSize = data.size();
    for (auto i = 0; i < dataSize; i++)
        heap.insert(data[i]);
    for (auto i = 0; i < dataSize; i++)
        data[i] = heap.pop();
}

完整的项目代码

Python 代码

import math

class Person:
    def __init__(self, name, age, score):
        self.name = name
        self.age = age
        self.score = score

    def __lt__(self, other):
        return self.score < other.score

    def __le__(self, other):
        return self.score <= other.score

    def __eq__(self, other):
        return self.score == other.score and self.age == other.age and self.name == other.name

    def __ne__(self, other):
        return not self.__eq__(other)

    def __gt__(self, other):
        return self.score > other.score

    def __ge__(self, other):
        return self.score >= other.score

    def get_name(self):
        return self.name

    def get_age(self):
        return self.age

    def get_score(self):
        return self.score

def heapify(arr, n, i):
    largest = i
    left = 2 * i + 1
    right = 2 * i + 2

    if left < n and arr[i] < arr[left]:
        largest = left

    if right < n and arr[largest] < arr[right]:
        largest = right

    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def heapsort(arr):
    n = len(arr)

    for i in range(n//2 - 1, -1, -1):
        heapify(arr, n, i)

    for i in range(n-1, 0, -1):
        arr[i], arr[0] = arr[0], arr[i]
        heapify(arr, i, 0)

def test_heap_sort():
    data = [9, 8, 3, 7, 5, 6, 4, 1]
    heapsort(data)
    print(data)

    d_data = [9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1]
    heapsort(d_data)
    print(d_data)

    c_data = ['a', 'c', 'b', 'd', 'e']
    heapsort(c_data)
    print(c_data)

    p_data = [Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)]
    heapsort(p_data)
    for person in p_data:
        print(person.get_name(), person.get_age(), person.get_score())

class MaxHeap:
    def __init__(self):
        self.heap = []
    def parent(self, i):
        return (i - 1) // 2
    def left_child(self, i):
        return 2 * i + 1
    def right_child(self, i):
        return 2 * i + 2
    def has_left_child(self, i):
        return self.left_child(i) < len(self.heap)
    def has_right_child(self, i):
        return self.right_child(i) < len(self.heap)
    def swap(self, i, j):
        self.heap[i], self.heap[j] = self.heap[j], self.heap[i]
    def heapify_up(self, i):
        while i > 0 and self.heap[self.parent(i)] < self.heap[i]:
            self.swap(i, self.parent(i))
            i = self.parent(i)
    def heapify_down(self, i):
        largest = i
        if self.has_left_child(i) and self.heap[self.left_child(i)] > self.heap[largest]:
            largest = self.left_child(i)
        if self.has_right_child(i) and self.heap[self.right_child(i)] > self.heap[largest]:
            largest = self.right_child(i)
        if largest != i:
            self.swap(i, largest)
            self.heapify_down(largest)
    def insert(self, key):
        self.heap.append(key)
        self.heapify_up(len(self.heap) - 1)
    def extract_max(self):
        if len(self.heap) == 0:
            return None
        max_value = self.heap[0]
        self.heap[0] = self.heap[-1]
        self.heap.pop()
        self.heapify_down(0)
        return max_value
    def build_heap(self, arr):
        self.heap = arr.copy()
        for i in range(len(self.heap) // 2, -1, -1):
            self.heapify_down(i)
    def is_empty(self):
        return len(self.heap) == 0
    def get_max(self):
        if self.is_empty():
            return None
        return self.heap[0]
    def __str__(self):
        return str(self.heap)
    
def max_heap_sort(arr):
    max_heap = MaxHeap()
    max_heap.build_heap(arr)
    sorted_arr = []
    while not max_heap.is_empty():
        sorted_arr.append(max_heap.extract_max())
    return sorted_arr[::-1]  # Reverse to get ascending order

class FibonacciHeap:

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

    # function to iterate through a doubly linked list
    def iterate(self, head):
        node = stop = head
        flag = False
        while True:
            if node == stop and flag is True:
                break
            elif node == stop:
                flag = True
            yield node
            node = node.right

    # pointer to the head and minimum node in the root list
    root_list, min_node = None, None

    # maintain total node count in full fibonacci heap
    total_nodes = 0

    # return min node in O(1) time
    def find_min(self):
        return self.min_node

    # extract (delete) the min node from the heap in O(log n) time
    # amortized cost analysis can be found here (http://bit.ly/1ow1Clm)
    def extract_min(self):
        z = self.min_node
        if z is not None:
            if z.child is not None:
                # attach child nodes to root list
                children = [x for x in self.iterate(z.child)]
                for i in range(0, len(children)):
                    self.merge_with_root_list(children[i])
                    children[i].parent = None
            self.remove_from_root_list(z)
            # set new min node in heap
            if z == z.right:
                self.min_node = self.root_list = None
            else:
                self.min_node = z.right
                self.consolidate()
            self.total_nodes -= 1
        return z

    # insert new node into the unordered root list in O(1) time
    # returns the node so that it can be used for decrease_key later
    def insert(self, key, value=None):
        n = self.Node(key, value)
        n.left = n.right = n
        self.merge_with_root_list(n)
        if self.min_node is None or n.key < self.min_node.key:
            self.min_node = n
        self.total_nodes += 1
        return n

    # modify the key of some node in the heap in O(1) time
    def decrease_key(self, x, k):
        if k > x.key:
            return None
        x.key = k
        y = x.parent
        if y is not None and x.key < y.key:
            self.cut(x, y)
            self.cascading_cut(y)
        if x.key < self.min_node.key:
            self.min_node = x

    # merge two fibonacci heaps in O(1) time by concatenating the root lists
    # the root of the new root list becomes equal to the first list and the second
    # list is simply appended to the end (then the proper min node is determined)
    def merge(self, h2):
        H = FibonacciHeap()
        H.root_list, H.min_node = self.root_list, self.min_node
        # fix pointers when merging the two heaps
        last = h2.root_list.left
        h2.root_list.left = H.root_list.left
        H.root_list.left.right = h2.root_list
        H.root_list.left = last
        H.root_list.left.right = H.root_list
        # update min node if needed
        if h2.min_node.key < H.min_node.key:
            H.min_node = h2.min_node
        # update total nodes
        H.total_nodes = self.total_nodes + h2.total_nodes
        return H

    # if a child node becomes smaller than its parent node we
    # cut this child node off and bring it up to the root list
    def cut(self, x, y):
        self.remove_from_child_list(y, x)
        y.degree -= 1
        self.merge_with_root_list(x)
        x.parent = None
        x.mark = False

    # cascading cut of parent node to obtain good time bounds
    def cascading_cut(self, y):
        z = y.parent
        if z is not None:
            if y.mark is False:
                y.mark = True
            else:
                self.cut(y, z)
                self.cascading_cut(z)

    # combine root nodes of equal degree to consolidate the heap
    # by creating a list of unordered binomial trees
    def consolidate(self):
        A = [None] * int(math.log(self.total_nodes) * 2)
        nodes = [w for w in self.iterate(self.root_list)]
        for w in range(0, len(nodes)):
            x = nodes[w]
            d = x.degree
            while A[d] != None:
                y = A[d]
                if x.key > y.key:
                    temp = x
                    x, y = y, temp
                self.heap_link(y, x)
                A[d] = None
                d += 1
            A[d] = x
        # find new min node - no need to reconstruct new root list below
        # because root list was iteratively changing as we were moving
        # nodes around in the above loop
        for i in range(0, len(A)):
            if A[i] is not None:
                if A[i].key < self.min_node.key:
                    self.min_node = A[i]

    # actual linking of one node to another in the root list
    # while also updating the child linked list
    def heap_link(self, y, x):
        self.remove_from_root_list(y)
        y.left = y.right = y
        self.merge_with_child_list(x, y)
        x.degree += 1
        y.parent = x
        y.mark = False

    # merge a node with the doubly linked root list
    def merge_with_root_list(self, node):
        if self.root_list is None:
            self.root_list = node
        else:
            node.right = self.root_list.right
            node.left = self.root_list
            self.root_list.right.left = node
            self.root_list.right = node

    # merge a node with the doubly linked child list of a root node
    def merge_with_child_list(self, parent, node):
        if parent.child is None:
            parent.child = node
        else:
            node.right = parent.child.right
            node.left = parent.child
            parent.child.right.left = node
            parent.child.right = node

    # remove a node from the doubly linked root list
    def remove_from_root_list(self, node):
        if node == self.root_list:
            self.root_list = node.right
        node.left.right = node.right
        node.right.left = node.left

    # remove a node from the doubly linked child list
    def remove_from_child_list(self, parent, node):
        if parent.child == parent.child.right:
            parent.child = None
        elif parent.child == node:
            parent.child = node.right
            node.right.parent = parent
        node.left.right = node.right
        node.right.left = node.left
        
def fibonacci_heap_sort(arr):
    heap = FibonacciHeap()
    for key in arr:
        heap.insert(key)
    sorted_arr = []
    while heap.total_nodes > 0:
        sorted_arr.append(heap.extract_min().key)
    return sorted_arr

def test_max_heap_sort():
    data = [9, 8, 3, 7, 5, 6, 4, 1]
    max_heap_sort(data)
    print(data)

    d_data = [9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1]
    max_heap_sort(d_data)
    print(d_data)

    c_data = ['a', 'c', 'b', 'd', 'e']
    max_heap_sort(c_data)
    print(c_data)

    p_data = [Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)]
    max_heap_sort(p_data)
    for person in p_data:
        print(person.get_name(), person.get_age(), person.get_score())

def test_fibonacci_heap_sort():
    data = [9, 8, 3, 7, 5, 6, 4, 1]
    fibonacci_heap_sort(data)
    print(data)

    d_data = [9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1]
    fibonacci_heap_sort(d_data)
    print(d_data)

    c_data = ['a', 'c', 'b', 'd', 'e']
    fibonacci_heap_sort(c_data)
    print(c_data)

    p_data = [Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)]
    fibonacci_heap_sort(p_data)
    for person in p_data:
        print(person.get_name(), person.get_age(), person.get_score())

if __name__ == "__main__":
    test_heap_sort()
    test_max_heap_sort()
    test_fibonacci_heap_sort()

C++ 代码

#include <iostream>
#include <array>
#include <algorithm>
#include <vector>
#include <string>
#include <cmath>
#include <list>
#include <iterator>

using namespace std;

class Person
{
public:
    Person() = default;
    ~Person() = default;

    Person(string name, int age, int score)
    {
        this->name = name;
        this->age = age;
        this->socre = score;
    }

    // Override the operator> for other function to use.
    bool operator>(const Person &other) const
    {
        // Compare the socre of two Person objects.
        return this->socre > other.socre;
    }

    // Override the operator< for other function to use.
    bool operator<(const Person &other) const
    {
        // Compare the socre of two Person objects.
        return this->socre < other.socre;
    }

    // Override the operator== for other function to use.
    bool operator==(const Person &other) const
    {
        // Compare the socre, age and name of two Person objects.
        return this->socre == other.socre &&
               this->age == other.age &&
               this->name == other.name;
    }

    // Override the operator!= for other function to use.
    bool operator!=(const Person &other) const
    {
        // Compare the socre, age and name of two Person objects.
        return this->socre != other.socre ||
               this->age != other.age ||
               this->name != other.name;
    }

    // Override the operator<= for other fnction to use.
    bool operator<=(const Person &other) const
    {
        // Compare the socre, age and name of two Person objects.
        return this->socre <= other.socre &&
               this->age <= other.age &&
               this->name <= other.name;
    }

    // Override the operator>= for other function to use.
    bool operator>=(const Person &other) const
    {
        // Compare the socre, age and name of two Person objects.
        return this->socre >= other.socre &&
               this->age >= other.age &&
               this->name >= other.name;
    }

    // Now there are some get parameters function for this calss:
    const string &getName() const { return this->name; }
    int getAge() const { return this->age; }
    int getScore() const { return this->socre; }

private:
    string name;
    int age;
    int socre;
};

template <typename RandomAccessIterator>
void siftDown(RandomAccessIterator start, RandomAccessIterator end, RandomAccessIterator root)
{
    auto child = root;
    advance(child, distance(start, root) + 1);
    if (child < end)
    {
        auto sibling = child;
        ++sibling;
        if (sibling<end && * sibling> * child)
        {
            child = sibling;
        }
        if (*child > *root)
        {
            iter_swap(root, child);
            siftDown(start, end, child);
        }
    }
}

template <typename RandomAccessIterator>
void makeHeap(RandomAccessIterator start, RandomAccessIterator end)
{
    if (start != end)
    {
        auto length = distance(start, end);
        auto parent = start;
        advance(parent, (length - 2) / 2);
        while (true)
        {
            siftDown(start, end, parent);
            if (parent == start)
                break;
            --parent;
        }
    }
}

template <typename RandomAccessIterator>
void heapSort(RandomAccessIterator start, RandomAccessIterator end)
{
    makeHeap<RandomAccessIterator>(start, end);
    while (start != end)
    {
        --end;
        iter_swap(start, end);
        siftDown(start, end, start);
    }
}

void heapSortTestCase()
{
    vector<int> data = {9, 8, 3, 7, 5, 6, 4, 1};
    heapSort<vector<int>::iterator>(data.begin(), data.end());
    for (int i : data)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<double> dData = {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};
    heapSort<vector<double>::iterator>(dData.begin(), dData.end());
    for (double i : dData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<char> cData = {'a', 'c', 'b', 'd', 'e'};
    heapSort<vector<char>::iterator>(cData.begin(), cData.end());
    for (char i : cData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<Person> pData = {Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)};
    heapSort<vector<Person>::iterator>(pData.begin(), pData.end());
    for (Person i : pData)
    {
        cout << i.getName() << " " << i.getAge() << " " << i.getScore() << endl;
    }
    cout << endl;
}

template <typename T>
void maxHeapify(vector<T> &arr, int i, int n)
{
    int left = 2 * i + 1;
    int right = 2 * i + 2;
    int largest = i;
    if (left < n && arr[left] > arr[largest])
    {
        largest = left;
    }
    if (right < n && arr[right] > arr[largest])
    {
        largest = right;
    }
    if (largest != i)
    {
        swap(arr[i], arr[largest]);
        maxHeapify(arr, largest, n);
    }
}

template <typename T>
void binaryHeapSort(vector<T> &arr)
{
    int n = arr.size();
    // Build max heap
    for (int i = n / 2 - 1; i >= 0; i--)
    {
        maxHeapify(arr, i, n);
    }
    // Extract elements from heap
    for (int i = n - 1; i >= 0; i--)
    {
        swap(arr[0], arr[i]);
        maxHeapify(arr, 0, i);
    }
}

void binaryHeapSortTestCase()
{
    vector<int> data = {9, 8, 3, 7, 5, 6, 4, 1};
    binaryHeapSort<int>(data);
    for (int i : data)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<double> dData = {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};
    binaryHeapSort<double>(dData);
    for (double i : dData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<char> cData = {'a', 'c', 'b', 'd', 'e'};
    binaryHeapSort<char>(cData);
    for (char i : cData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<Person> pData = {Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)};
    binaryHeapSort<Person>(pData);
    for (Person i : pData)
    {
        cout << i.getName() << " " << i.getAge() << " " << i.getScore() << endl;
    }
    cout << endl;
}

template <typename T>
class BinaryHeap
{
private:
    vector<T> heap;
    // 用于将新插入的元素上浮到正确位置
    void siftUp(int index)
    {
        while (index > 0 && heap[(index - 1) / 2] < heap[index])
        {
            swap(heap[index], heap[(index - 1) / 2]);
            index = (index - 1) / 2;
        }
    }
    // 用于将堆顶元素下沉到正确位置
    void siftDown(int index)
    {
        int left = 2 * index + 1;
        int right = 2 * index + 2;
        int largest = index;
        if (left < heap.size() && heap[left] > heap[largest])
        {
            largest = left;
        }
        if (right < heap.size() && heap[right] > heap[largest])
        {
            largest = right;
        }
        if (largest != index)
        {
            swap(heap[index], heap[largest]);
            siftDown(largest);
        }
    }

public:
    BinaryHeap() {}
    // 插入元素
    void insert(T value)
    {
        heap.push_back(value);
        siftUp(heap.size() - 1);
    }
    // 删除堆顶元素
    void remove()
    {
        if (heap.empty())
        {
            return;
        }
        heap[0] = heap.back();
        heap.pop_back();
        if (!heap.empty())
        {
            siftDown(0);
        }
    }
    // 获取堆顶元素
    T peek() const
    {
        if (heap.empty())
        {
            throw out_of_range("Heap is empty");
        }
        return heap[0];
    }
    // 获取并删除顶元素
    T pop()
    {
        T value = peek();
        remove();
        return value;
    }
    // 判断堆是否为空
    bool isEmpty() const
    {
        return heap.empty();
    }
    // 输出堆中的元素
    void print() const
    {
        for (const auto &elem : heap)
        {
            cout << elem << " ";
        }
        cout << endl;
    }
};

template <class T>
void BinaryHeapSort(vector<T> &data)
{
    BinaryHeap<T> heap;
    auto dataSize = data.size();
    for (auto i = 0; i < dataSize; i++)
        heap.insert(data[i]);
    for (auto i = 0; i < dataSize; i++)
        data[i] = heap.pop();
}

void BinaryHeapUnitTest()
{
    BinaryHeap<int> maxHeap;
    maxHeap.insert(10);
    maxHeap.insert(20);
    maxHeap.insert(15);
    maxHeap.insert(17);
    maxHeap.insert(25);
    maxHeap.print();                            // 应该输出 25 20 15 17 10
    cout << "Peek: " << maxHeap.peek() << endl; // 应该输出 25
    maxHeap.remove();
    maxHeap.print(); // 应该输出 20 17 15 10
}

void BinaryHeapSortTestCase()
{
    vector<int> data = {9, 8, 3, 7, 5, 6, 4, 1};
    BinaryHeapSort<int>(data);
    for (int i : data)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<double> dData = {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};
    BinaryHeapSort<double>(dData);
    for (double i : dData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<char> cData = {'a', 'c', 'b', 'd', 'e'};
    BinaryHeapSort<char>(cData);
    for (char i : cData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<Person> pData = {Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)};
    BinaryHeapSort<Person>(pData);
    for (Person i : pData)
    {
        cout << i.getName() << " " << i.getAge() << " " << i.getScore() << endl;
    }
    cout << endl;
}

template <class V>
class FibonacciHeap;

template <class V>
struct node
{
private:
    node<V> *prev;
    node<V> *next;
    node<V> *child;
    node<V> *parent;
    V value;
    int degree;
    bool marked;

public:
    friend class FibonacciHeap<V>;
    node<V> *getPrev() { return prev; }
    node<V> *getNext() { return next; }
    node<V> *getChild() { return child; }
    node<V> *getParent() { return parent; }
    V getValue() { return value; }
    bool isMarked() { return marked; }

    bool hasChildren() { return child; }
    bool hasParent() { return parent; }
};

template <class V>
class FibonacciHeap
{
protected:
    node<V> *heap;

public:
    FibonacciHeap()
    {
        heap = _empty();
    }

    virtual ~FibonacciHeap()
    {
        if (heap)
        {
            _deleteAll(heap);
        }
    }

    node<V> *insert(V value)
    {
        node<V> *ret = _singleton(value);
        heap = _merge(heap, ret);
        return ret;
    }

    void merge(FibonacciHeap &other)
    {
        heap = _merge(heap, other.heap);
        other.heap = _empty();
    }

    bool isEmpty()
    {
        return heap == nullptr;
    }

    V getMinimum()
    {
        return heap->value;
    }

    V removeMinimum()
    {
        node<V> *old = heap;
        heap = _removeMinimum(heap);
        V ret = old->value;
        delete old;
        return ret;
    }

    void decreaseKey(node<V> *n, V value)
    {
        heap = _decreaseKey(heap, n, value);
    }

    node<V> *find(V value)
    {
        return _find(heap, value);
    }

private:
    node<V> *_empty()
    {
        return nullptr;
    }

    node<V> *_singleton(V value)
    {
        node<V> *n = new node<V>;
        n->value = value;
        n->prev = n->next = n;
        n->degree = 0;
        n->marked = false;
        n->child = nullptr;
        n->parent = nullptr;
        return n;
    }

    node<V> *_merge(node<V> *a, node<V> *b)
    {
        if (a == nullptr)
            return b;
        if (b == nullptr)
            return a;
        if (a->value > b->value)
        {
            node<V> *temp = a;
            a = b;
            b = temp;
        }
        node<V> *an = a->next;
        node<V> *bp = b->prev;
        a->next = b;
        b->prev = a;
        an->prev = bp;
        bp->next = an;
        return a;
    }

    void _deleteAll(node<V> *n)
    {
        if (n != nullptr)
        {
            node<V> *c = n;
            do
            {
                node<V> *d = c;
                c = c->next;
                _deleteAll(d->child);
                delete d;
            } while (c != n);
        }
    }

    void _addChild(node<V> *parent, node<V> *child)
    {
        child->prev = child->next = child;
        child->parent = parent;
        parent->degree++;
        parent->child = _merge(parent->child, child);
    }

    void _unMarkAndUnParentAll(node<V> *n)
    {
        if (n == nullptr)
            return;
        node<V> *c = n;
        do
        {
            c->marked = false;
            c->parent = nullptr;
            c = c->next;
        } while (c != n);
    }

    node<V> *_removeMinimum(node<V> *n)
    {
        _unMarkAndUnParentAll(n->child);
        if (n->next == n)
        {
            n = n->child;
        }
        else
        {
            n->next->prev = n->prev;
            n->prev->next = n->next;
            n = _merge(n->next, n->child);
        }
        if (n == nullptr)
            return n;
        node<V> *trees[64] = {nullptr};

        while (true)
        {
            if (trees[n->degree] != nullptr)
            {
                node<V> *t = trees[n->degree];
                if (t == n)
                    break;
                trees[n->degree] = nullptr;
                if (n->value < t->value)
                {
                    t->prev->next = t->next;
                    t->next->prev = t->prev;
                    _addChild(n, t);
                }
                else
                {
                    t->prev->next = t->next;
                    t->next->prev = t->prev;
                    if (n->next == n)
                    {
                        t->next = t->prev = t;
                        _addChild(t, n);
                        n = t;
                    }
                    else
                    {
                        n->prev->next = t;
                        n->next->prev = t;
                        t->next = n->next;
                        t->prev = n->prev;
                        _addChild(t, n);
                        n = t;
                    }
                }
                continue;
            }
            else
            {
                trees[n->degree] = n;
            }
            n = n->next;
        }
        node<V> *min = n;
        node<V> *start = n;
        do
        {
            if (n->value < min->value)
                min = n;
            n = n->next;
        } while (n != start);
        return min;
    }

    node<V> *_cut(node<V> *heap, node<V> *n)
    {
        if (n->next == n)
        {
            n->parent->child = nullptr;
        }
        else
        {
            n->next->prev = n->prev;
            n->prev->next = n->next;
            n->parent->child = n->next;
        }
        n->next = n->prev = n;
        n->marked = false;
        return _merge(heap, n);
    }

    node<V> *_decreaseKey(node<V> *heap, node<V> *n, V value)
    {
        if (n->value < value)
            return heap;
        n->value = value;
        if (n->parent)
        {
            if (n->value < n->parent->value)
            {
                heap = _cut(heap, n);
                node<V> *parent = n->parent;
                n->parent = nullptr;
                while (parent != nullptr && parent->marked)
                {
                    heap = _cut(heap, parent);
                    n = parent;
                    parent = n->parent;
                    n->parent = nullptr;
                }
                if (parent != nullptr && parent->parent != nullptr)
                    parent->marked = true;
            }
        }
        else
        {
            if (n->value < heap->value)
            {
                heap = n;
            }
        }
        return heap;
    }

    node<V> *_find(node<V> *heap, V value)
    {
        node<V> *n = heap;
        if (n == nullptr)
            return nullptr;
        do
        {
            if (n->value == value)
                return n;
            node<V> *ret = _find(n->child, value);
            if (ret)
                return ret;
            n = n->next;
        } while (n != heap);
        return nullptr;
    }
};

class DotFibonacciHeap : public FibonacciHeap<int>
{
public:
    void dump()
    {
        printf("digraph G {\n");
        if (heap == nullptr)
        {
            printf("empty;\n}\n");
            return;
        }
        printf("minimum -> \"%p\" [constraint=false];\n", heap);
        node<int> *c = heap;
        do
        {
            _dumpChildren(c);
            c = c->getNext();
        } while (c != heap);
        printf("}\n");
    }

private:
    void _dumpChildren(node<int> *n)
    {
        printf("\"%p\" -> \"%p\" [constraint=false,arrowhead=lnormal];\n", n, n->getNext());
        printf("\"%p\" -> \"%p\" [constraint=false,arrowhead=ornormal];\n", n, n->getPrev());
        if (n->isMarked())
            printf("\"%p\" [style=filled,fillcolor=grey];\n", n);
        if (n->hasParent())
        {
            printf("\"%p\" -> \"%p\" [constraint=false,arrowhead=onormal];\n", n, n->getParent());
        }
        printf("\"%p\" [label=%d];\n", n, n->getValue());
        if (n->hasChildren())
        {
            node<int> *c = n->getChild();
            do
            {
                printf("\"%p\" -> \"%p\";\n", n, c);
                _dumpChildren(c);
                c = c->getNext();
            } while (c != n->getChild());
        }
    }
};

void DotFibonacciHeapUnitTest()
{
    DotFibonacciHeap h;
    h.insert(2);
    h.insert(3);
    h.insert(1);
    h.insert(4);
    h.removeMinimum();
    h.removeMinimum();
    h.insert(5);
    h.insert(7);
    h.removeMinimum();
    h.insert(2);
    node<int> *nine = h.insert(90);
    h.removeMinimum();
    h.removeMinimum();
    h.removeMinimum();
    for (int i = 0; i < 20; i += 2)
        h.insert(30 - i);
    for (int i = 0; i < 4; i++)
        h.removeMinimum();
    for (int i = 0; i < 20; i += 2)
        h.insert(30 - i);
    h.insert(23);
    for (int i = 0; i < 7; i++)
        h.removeMinimum();
    h.decreaseKey(nine, 1);
    h.decreaseKey(h.find(28), 2);
    h.decreaseKey(h.find(23), 3);

    h.dump();
}

template <class T>
void FibonacciHeapSort(vector<T> &data)
{
    FibonacciHeap<T> heap;
    auto dataSize = data.size();
    for (auto i = 0; i < dataSize; i++)
        heap.insert(data[i]);
    for (auto i = 0; i < dataSize; i++)
        data[i] = heap.removeMinimum();
}

void FibonacciHeapSortTestCase()
{
    vector<int> data = {9, 8, 3, 7, 5, 6, 4, 1};
    FibonacciHeapSort<int>(data);
    for (int i : data)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<double> dData = {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};
    FibonacciHeapSort<double>(dData);
    for (double i : dData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<char> cData = {'a', 'c', 'b', 'd', 'e'};
    FibonacciHeapSort<char>(cData);
    for (char i : cData)
    {
        cout << i << " ";
    }
    cout << endl;

    vector<Person> pData = {Person("Alice", 20, 90), Person("Bob", 18, 85), Person("Charlie", 22, 95)};
    FibonacciHeapSort<Person>(pData);
    for (Person i : pData)
    {
        cout << i.getName() << " " << i.getAge() << " " << i.getScore() << endl;
    }
    cout << endl;
}

int main()
{
    cout << "Heap Sort Case:" << endl;
    heapSortTestCase();
    cout << "Binary Heap Sort Case Without DataStructure:" << endl;
    binaryHeapSortTestCase();
    cout << "Binary Heap Sort Case With DataStructure:" << endl;
    BinaryHeapUnitTest();
    BinaryHeapSortTestCase();
    cout << "Fibonacci Heap Sort Case:" << endl;
    DotFibonacciHeapUnitTest();
    FibonacciHeapSortTestCase();
    return 0;
}

个人格言

追寻与内心共鸣的生活,未来会逐渐揭晓答案。

Pursue the life that resonates with your heart, and the future will gradually reveal the answer.

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1472664.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Huggingface学习笔记

课程地址&#xff1a;【HuggingFace简明教程,BERT中文模型实战示例.NLP预训练模型,Transformers类库,datasets类库快速入门.】 什么是huggingface&#xff1f; huggingface是一个开源社区&#xff0c;提供了先进的NLP模型、数据集以及工具。 主要模型&#xff1a; 安装环境&…

Rust升级慢,使用国内镜像进行加速

背景 rustup 是 Rust 官方的跨平台 Rust 安装工具&#xff0c;国内用户使用rustup update的时候&#xff0c;网速非常慢&#xff0c;可以使用国内的阿里云镜像源来进行加速 0x01 配置方法 1. Linux与Mac OS用户配置环境变量 修改~/.bash_profile文件添加如下内容&#xff1…

Docker基础篇(六) dockerfile体系结构语法

FROM&#xff1a;基础镜像&#xff0c;当前新镜像是基于哪个镜像的 MAINTAINER &#xff1a;镜像维护者的姓名和邮箱地址 RUN&#xff1a;容器构建时需要运行的命令 EXPOSE &#xff1a;当前容器对外暴露出的端口号 WORKDIR&#xff1a;指定在创建容器后&#xff0c;终端默认登…

lv21 QT入门与基础控件 1

1 QT简介 QT是挪威Trolltech开发的多平台C图形用户界面应用程序框架 典型应用 2 工程搭建 2.1 新建ui工程 不要写中文路径 2.1 不勾选UI&#xff08;主讲&#xff09; 3 QT信号与槽机制 语法&#xff1a;Connect&#xff08;A, SIGNLA(aaa()), B, SLOT(bbb())&#xff09;…

算法--贪心

这里写目录标题 区间问题区间选点引入算法思想例题代码 最大不相交区间的数量算法思想例题代码 区间分组算法思想例题代码 一级目录二级目录二级目录二级目录 区间问题 区间选点 引入 区间问题会给定几个区间&#xff0c;之后要求我们在数轴上选取尽量少的点&#xff0c;使得…

电脑休眠之后唤不醒

现象&#xff1a;午休时间电脑休眠了&#xff0c;醒来之后发现在密码输入界面&#xff0c;但鼠标键盘没反应。按重启键或电源机重新开机&#xff0c;结果开不了机。 原因&#xff1a;1、内存条脏了&#xff0c;导致内存条读取失败 2、休眠的时候硬盘休眠了&#xff0c;导致按…

欢迎免费申报讯方技术HarmonyOS人才训练营!

在今年1月备受瞩目的鸿蒙生态千帆启航仪式上&#xff0c;华为宣布&#xff1a;HarmonyOS NEXT星河预览版正式面向开发者开放申请&#xff0c;意味着鸿蒙将建立更广泛的生态系统&#xff0c;迎来更多的应用和软硬件产品&#xff0c;加速自我技术迭代&#xff0c;同时推动华为全场…

变革中的容器技术

容器化技术的优点 容器化是一种将应用程序和其所需的依赖项&#xff0c;封装在一个可在任何基础架构上一致运行的轻量级可执行文件&#xff08;即容器&#xff09;的技术。容器化技术可以大大简化应用程序的部署、管理和维护&#xff0c;提高运维效率和可靠性。 容器化技术有…

LeetCode_Java_动态规划(2)(题目+思路+代码)

131.分割回文串 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串 。返回 s 所有可能的分割方案。 回文串 是正着读和反着读都一样的字符串。 示例 1&#xff1a; 输入&#xff1a;s "aab" 输出&#xff1a;[["a&qu…

工具篇-- 定时任务xxl-job的集群部署

文章目录 前言一、xxl-job-admin 集群部署&#xff1a;1.1 部署步骤&#xff1a;1.2 部署求和建议&#xff1a;1.3 集群部署模拟&#xff08;单机&#xff09;&#xff1a; 二、xxl-job 执行器 集群部署&#xff1a;2.1 集群部署要求&#xff1a;2.2 集群部署模拟&#xff1a; …

pthread_exit和pehread_join函数

pthread_exit&#xff1a; 在线程中禁止调用exit函数&#xff0c;否则会导致整个进程退出&#xff0c;取而代之的是调用pthread_exit函数&#xff0c;这个函数只会使一个线程退出&#xff0c;如果主线程使用pthread_exit函数也不会使整个进程退出&#xff0c;不会影响其他线程…

【基础知识】MPP架构和hadoop架构比对

架构比对 简单一句描述。 mpp架构&#xff0c;就是找一群和自己能力差不多的任一起做事&#xff0c;每个人做的事情是一致的。 hadoop架构&#xff0c;就是找一群能力差一些的人&#xff0c;但只需要他们每个人只做一部分工作。 举例说明 一个特色小饭店如何成为连锁餐饮巨…

【国密算法】深入理解国密算法:原理、实践及注意事项

目录 引言 1. 国密算法概述 2. 国密算法的实践应用 2.1 对称加密&#xff08;SM1算法&#xff09; 2.2 非对称加密&#xff08;SM2算法&#xff09; 2.3 哈希算法&#xff08;SM3算法&#xff09; 3. 国密算法的注意事项 结论 引言 国密算法&#xff0c;即中国密码算法…

AI数字人SadTalker实战

1.概述 AI数字人在营销和品牌推广中扮演着至关重要的角色&#xff0c;许多企业和个人正积极利用数字技术来打造属于自己的财富。有没有一种简单而免费的方式来创建自己的数字人呢&#xff1f;本篇博客笔者将为大家介绍如何搭建属于自己的AI数字人。 2.内容 2.1 什么是SadTalker…

内存卡无法读取?这里有救!

一、遭遇内存卡无法读取的困境 在日常生活和工作中&#xff0c;我们越来越依赖电子设备来存储和传输数据。然而&#xff0c;当遇到内存卡无法读取的问题时&#xff0c;很多人会感到困惑和焦虑。无论是重要的工作文件、珍贵的家庭照片&#xff0c;还是其他个人数据&#xff0c;…

基于springboot+vue的音乐网站(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

C++力扣题目 42--接雨水 84--柱状图中最大的矩形

42. 接雨水 力扣题目链接(opens new window) 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]输出&#xff1a;6解释&#xff…

C++17之折叠表达式

相关文章系列 深入理解可变参数(va_list、std::initializer_list和可变参数模版) 目录 1.介绍 2.应用 2.1.使用折叠表达式 2.2.支持的运算符 2.3.使用折叠处理类型 3.总结 1.介绍 折叠表达式是C17新引进的语法特性。使用折叠表达式可以简化对C11中引入的参数包的处理&…

原型设计工具Axure RP

Axure RP是一款专业的快速原型设计工具。Axure&#xff08;发音&#xff1a;Ack-sure&#xff09;&#xff0c;代表美国Axure公司&#xff1b;RP则是Rapid Prototyping&#xff08;快速原型&#xff09;的缩写。 下载链接&#xff1a;https://www.axure.com/ 下载 可以免费试用…

windows安装onlyoffice8.0

安装erlang 安装Erlang25.3 下载地址 设置环境变量 ERLANG_HOME C:\Program Files\Erlang OTP Path下设置%ERLANG_HOME%\bin 打开cmd输入erl不报错即可 安装rabbitmq rabbitmq和erlang对应的关系 下载地址 执行完exe文件后&#xff0c;找到安装目录下的sbin&am…