ui设计网站模板,网站搭建岗位及要求,网站建设 报价,flash网站建设教程排序算法 —— 堆排序
算法基础介绍
堆排序#xff08;Heap Sort#xff09;是一种基于比较的排序算法#xff0c;它利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树#xff0c;其中每个节点的值都必须大于或等于#xff08;最大堆#xff09;或小于或等于Heap Sort是一种基于比较的排序算法它利用堆这种数据结构来实现排序。堆是一种特殊的完全二叉树其中每个节点的值都必须大于或等于最大堆或小于或等于最小堆其子节点的值。
基本概念
堆是一个近似完全二叉树的数据结构满足任一非叶子节点的值不小于或不大于其左右孩子节点的值。堆通常分为最大堆和最小堆
最大堆每个节点的值都大于或等于其子节点的值。最小堆每个节点的值都小于或等于其子节点的值。
堆排序算法通过构建一个最大堆或最小堆然后将堆顶元素最大或最小值与堆的最后一个元素交换再将剩余的元素重新调整为最大堆或最小堆如此反复直到整个数组有序。
算法步骤
构建堆将无序的输入数组转换为一个最大堆或最小堆。堆排序 将堆顶元素最大或最小值与堆的最后一个元素交换将其移出堆。调整剩余元素使其重新成为一个最大堆或最小堆。重复上述步骤直到所有元素都被移出堆。
伪代码描述
function heapsort(array)build_max_heap(array)for end from size(array) down to 2 doswap array[1] with array[end]heap_size heap_size - 1sift_down(array, 1)end for
end function堆排序是一种高效的排序算法具有以下优缺点
优点
时间复杂度稳定堆排序的时间复杂度为(O(nlog(n)))其中n是数组的长度。这个复杂度在所有比较排序算法中是最优的因为比较排序的最坏时间复杂度为(O(nlog(n)))。空间复杂度低堆排序是原地排序除了常数个额外空间用于存储递归栈之外不需要额外的内存空间。不稳定的排序算法堆排序是不稳定的排序算法这意味着如果两个元素相等它们的相对顺序在排序后可能会改变。适用于各种数据类型堆排序可以适用于各种数据类型包括整数、浮点数、字符串等只要能够为这些数据类型定义合适的比较操作。易于实现堆排序的实现相对简单尤其是使用二叉堆的实现。
缺点
最坏情况性能差虽然平均时间复杂度为(O(nlog(n)))但在最坏情况下输入数据完全逆序堆排序的时间复杂度退化为(O(n^2))。不稳定排序对于某些需要稳定排序的应用场景如数据库索引堆排序可能不是最佳选择。对内存要求高虽然空间复杂度低但在排序过程中堆中的元素可能会频繁地移动这可能导致较高的内存访问开销。初始化堆的时间开销虽然堆排序的总时间复杂度是(O(nlog(n)))但这个复杂度是在整个排序过程中累积的。在实际应用中构建初始堆的过程可能会占用一定的时间。
总体而言堆排序是一个在实际应用中广泛使用的排序算法特别是当内存使用是一个关键因素时。然而对于需要稳定排序的应用或者当数据已经部分有序时可能需要考虑其他排序算法如归并排序或快速排序
应用场景
堆排序在实际开发过程中的常见应用场景包括
优先级队列堆排序是优先级队列实现的基础。在许多编程语言中优先级队列或称为最小堆就是基于堆排序原理实现的。这种数据结构允许快速插入和删除最小元素常用于任务调度、事件处理等场景。排序算法比较在开发中为了验证新算法的性能开发者可能会将堆排序与其他排序算法如快速排序、归并排序进行比较。堆排序因其简单性和稳定性常作为基准算法之一。数据挖掘在数据挖掘和机器学习领域堆排序可用于处理大规模数据集的预处理步骤如特征选择、频繁项集挖掘等。文件系统堆排序可用于文件系统的目录排序帮助用户快速找到文件。数据库索引虽然数据库通常使用B树或B树索引但在某些特殊情况下堆排序可以作为辅助算法来优化索引的构建过程。缓存管理在缓存管理系统中堆排序可用于维护缓存数据的有序性例如根据最近最少使用LRU策略来淘汰缓存项。算法教学堆排序是计算机科学教育中常用的教学示例用于讲解数据结构和算法的概念。图形处理在图形处理中堆排序可用于顶点排序以便于后续的图形操作如生成凸包、计算几何形状的交点等。游戏开发在游戏开发中堆排序可用于实现游戏对象的优先级处理例如根据对象的属性如生命值、攻击力等对对象进行排序。网络协议在网络协议处理中堆排序可用于数据包的优先级处理确保高优先级的数据包得到优先处理。
堆排序的优点如时间复杂度的稳定性和低空间复杂度使其在需要快速、高效处理大规模数据的场景中非常有用。然而它的不稳定性也是一个需要注意的点特别是在需要保持数据相对顺序的应用中。
时间复杂度
最佳情况
在最佳情况下输入数组已经是有序的堆排序只需要进行一次建堆操作然后进行一次简单的调整即可完成排序。因此最佳情况下的时间复杂度是 (O(n))。
最坏情况
在最坏情况下输入数组是完全逆序的需要进行 n-1 次建堆操作并且每次调整堆都需要将堆中的元素重新排列。因此最坏情况下的时间复杂度是 (O(n^2))。
平均情况
在平均情况下堆排序的时间复杂度是 (O(nlog(n)))。这是因为虽然最坏情况下的时间复杂度是 (O(n^2))但在大多数实际应用中数据并不是完全逆序的因此平均时间复杂度更接近于 (O(nlog(n)))。
空间复杂度
堆排序是一个原地排序算法除了用于存储递归栈的常数空间之外不需要额外的内存空间。因此空间复杂度是 (O(1))。
证明
时间复杂度证明
建堆操作建堆操作的时间复杂度是 (O(n))。调整堆调整堆的时间复杂度是 (O(n))。排序过程排序过程需要进行 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 ileft 2 * i 1right 2 * i 2if left n and arr[i] arr[left]:largest leftif right n and arr[largest] arr[right]:largest rightif 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 实现
扩展阅读
堆排序的时间复杂度优化主要集中在减少建堆和调整堆的次数上。以下是一些常见的优化方法
时间复杂度的优化方法
减少比较次数通过减少不必要的比较可以减少建堆和调整堆的时间。例如可以使用二叉堆的路径压缩技术在调整堆的过程中减少子节点与父节点的比较次数。使用斐波那契堆斐波那契堆是一种数据结构它可以在O(log n)的时间内完成堆的插入、删除和合并操作。这比二叉堆的O(log n)复杂度更优。延迟删除在某些实现中为了避免频繁地调整堆可以延迟删除操作直到需要的时候才进行。减少调整堆的次数通过选择合适的堆大小和调整策略可以减少调整堆的次数。
历史上常用的堆排序的变种算法
斐波那契堆斐波那契堆是一种改进的堆数据结构它可以在O(log n)的时间内完成堆的插入、删除和合并操作比二叉堆更优。二叉堆二叉堆是最常见的堆实现它包括最大堆和最小堆。二叉堆的调整操作通常需要O(log n)的时间复杂度。左倾堆左倾堆是一种特殊的堆实现它通过减少堆的平衡调整次数来优化性能。二项堆二项堆是一种特殊的堆实现它使用二项树的性质来优化堆的插入和删除操作。二叉索引堆二叉索引堆是一种结合了二叉堆和二叉树索引的数据结构它可以在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)的复杂度。
算法步骤
斐波那契堆排序的基本步骤如下
初始化创建一个空的斐波那契堆。插入元素将所有待排序的元素插入到斐波那契堆中。删除最小元素重复执行以下操作直到堆中只剩下一个元素 删除并返回堆中的最小元素。将删除元素的后继节点如果有插入到堆中。 排序完成最后剩下的元素是排序后的第一个元素。
伪代码描述
斐波那契堆排序(A)创建一个空的斐波那契堆对于每个元素x in A插入(斐波那契堆, x)while 斐波那契堆中元素数量 1删除并返回最小元素(斐波那契堆)将删除元素的后继节点插入(斐波那契堆)返回堆中剩下的元素Python 代码实现
class FibonacciHeap:# internal node classclass Node:def __init__(self, key, value):self.key keyself.value valueself.parent self.child self.left self.right Noneself.degree 0self.mark False# function to iterate through a doubly linked listdef iterate(self, head):node stop headflag Falsewhile True:if node stop and flag is True:breakelif node stop:flag Trueyield nodenode node.right# pointer to the head and minimum node in the root listroot_list, min_node None, None# maintain total node count in full fibonacci heaptotal_nodes 0# return min node in O(1) timedef 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_nodeif z is not None:if z.child is not None:# attach child nodes to root listchildren [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 Noneself.remove_from_root_list(z)# set new min node in heapif z z.right:self.min_node self.root_list Noneelse:self.min_node z.rightself.consolidate()self.total_nodes - 1return 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 laterdef insert(self, key, valueNone):n self.Node(key, value)n.left n.right nself.merge_with_root_list(n)if self.min_node is None or n.key self.min_node.key:self.min_node nself.total_nodes 1return n# modify the key of some node in the heap in O(1) timedef decrease_key(self, x, k):if k x.key:return Nonex.key ky x.parentif 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 heapslast h2.root_list.lefth2.root_list.left H.root_list.leftH.root_list.left.right h2.root_listH.root_list.left lastH.root_list.left.right H.root_list# update min node if neededif h2.min_node.key H.min_node.key:H.min_node h2.min_node# update total nodesH.total_nodes self.total_nodes h2.total_nodesreturn H# if a child node becomes smaller than its parent node we# cut this child node off and bring it up to the root listdef cut(self, x, y):self.remove_from_child_list(y, x)y.degree - 1self.merge_with_root_list(x)x.parent Nonex.mark False# cascading cut of parent node to obtain good time boundsdef cascading_cut(self, y):z y.parentif z is not None:if y.mark is False:y.mark Trueelse: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 treesdef 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.degreewhile A[d] ! None:y A[d]if x.key y.key:temp xx, y y, tempself.heap_link(y, x)A[d] Noned 1A[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 loopfor 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 listdef heap_link(self, y, x):self.remove_from_root_list(y)y.left y.right yself.merge_with_child_list(x, y)x.degree 1y.parent xy.mark False# merge a node with the doubly linked root listdef merge_with_root_list(self, node):if self.root_list is None:self.root_list nodeelse:node.right self.root_list.rightnode.left self.root_listself.root_list.right.left nodeself.root_list.right node# merge a node with the doubly linked child list of a root nodedef merge_with_child_list(self, parent, node):if parent.child is None:parent.child nodeelse:node.right parent.child.rightnode.left parent.childparent.child.right.left nodeparent.child.right node# remove a node from the doubly linked root listdef remove_from_root_list(self, node):if node self.root_list:self.root_list node.rightnode.left.right node.rightnode.right.left node.left# remove a node from the doubly linked child listdef remove_from_child_list(self, parent, node):if parent.child parent.child.right:parent.child Noneelif parent.child node:parent.child node.rightnode.right.parent parentnode.left.right node.rightnode.right.left node.leftdef 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_arrC模板代码实现
template class V
class FibonacciHeap;template class V
struct node
{
private:nodeV *prev;nodeV *next;nodeV *child;nodeV *parent;V value;int degree;bool marked;public:friend class FibonacciHeapV;nodeV *getPrev() { return prev; }nodeV *getNext() { return next; }nodeV *getChild() { return child; }nodeV *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:nodeV *heap;public:FibonacciHeap(){heap _empty();}virtual ~FibonacciHeap(){if (heap){_deleteAll(heap);}}nodeV *insert(V value){nodeV *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(){nodeV *old heap;heap _removeMinimum(heap);V ret old-value;delete old;return ret;}void decreaseKey(nodeV *n, V value){heap _decreaseKey(heap, n, value);}nodeV *find(V value){return _find(heap, value);}private:nodeV *_empty(){return nullptr;}nodeV *_singleton(V value){nodeV *n new nodeV;n-value value;n-prev n-next n;n-degree 0;n-marked false;n-child nullptr;n-parent nullptr;return n;}nodeV *_merge(nodeV *a, nodeV *b){if (a nullptr)return b;if (b nullptr)return a;if (a-value b-value){nodeV *temp a;a b;b temp;}nodeV *an a-next;nodeV *bp b-prev;a-next b;b-prev a;an-prev bp;bp-next an;return a;}void _deleteAll(nodeV *n){if (n ! nullptr){nodeV *c n;do{nodeV *d c;c c-next;_deleteAll(d-child);delete d;} while (c ! n);}}void _addChild(nodeV *parent, nodeV *child){child-prev child-next child;child-parent parent;parent-degree;parent-child _merge(parent-child, child);}void _unMarkAndUnParentAll(nodeV *n){if (n nullptr)return;nodeV *c n;do{c-marked false;c-parent nullptr;c c-next;} while (c ! n);}nodeV *_removeMinimum(nodeV *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;nodeV *trees[64] {nullptr};while (true){if (trees[n-degree] ! nullptr){nodeV *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;}nodeV *min n;nodeV *start n;do{if (n-value min-value)min n;n n-next;} while (n ! start);return min;}nodeV *_cut(nodeV *heap, nodeV *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);}nodeV *_decreaseKey(nodeV *heap, nodeV *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);nodeV *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;}nodeV *_find(nodeV *heap, V value){nodeV *n heap;if (n nullptr)return nullptr;do{if (n-value value)return n;nodeV *ret _find(n-child, value);if (ret)return ret;n n-next;} while (n ! heap);return nullptr;}
};template class T
void FibonacciHeapSort(vectorT data)
{FibonacciHeapT 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();
}二叉堆排序
二叉堆排序是一种基于比较的排序算法它利用二叉堆这种数据结构来进行排序。二叉堆是一种特殊的堆它是一个近似完全二叉树满足任一非叶子节点的值不大于或不小于其左右孩子节点的值。根据堆的这一特性二叉堆分为最大堆和最小堆。在最大堆中每个父节点的值都大于或等于其孩子节点的值在最小堆中每个父节点的值都小于或等于其孩子节点的值。
基本概念
二叉堆的性质对于最大堆每个父节点的值都大于或等于其孩子节点的值对于最小堆每个父节点的值都小于或等于其孩子节点的值。堆的表示通常使用数组来表示堆对于任意节点i假设数组从1开始索引其左孩子为2i右孩子为2i1父节点为i/2向下取整。
算法步骤
构建堆将无序数组构造成一个最大堆或最小堆。调整堆将堆顶元素最大或最小值与数组末尾元素交换然后调整堆使其满足堆的性质。重复调整重复步骤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*iif j 1 n and array[j] array[j 1]:j j 1if array[i] array[j]:交换array[i]和array[j]i jelse:breakend while
end 调整堆Python代码实现
class MaxHeap:def __init__(self):self.heap []def parent(self, i):return (i - 1) // 2def left_child(self, i):return 2 * i 1def right_child(self, i):return 2 * i 2def 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 iif 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 Nonemax_value self.heap[0]self.heap[0] self.heap[-1]self.heap.pop()self.heapify_down(0)return max_valuedef 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) 0def get_max(self):if self.is_empty():return Nonereturn 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 orderC模板实现
#include iostream
#include vector
#include algorithmtemplate typename T
void maxHeapify(std::vectorT 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::vectorT arr) {int n arr.size();// Build max heapfor (int i n / 2 - 1; i 0; i--) {maxHeapify(arr, i, n);}// Extract elements from heapfor (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:vectorT 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(vectorT data)
{BinaryHeapT 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 mathclass Person:def __init__(self, name, age, score):self.name nameself.age ageself.score scoredef __lt__(self, other):return self.score other.scoredef __le__(self, other):return self.score other.scoredef __eq__(self, other):return self.score other.score and self.age other.age and self.name other.namedef __ne__(self, other):return not self.__eq__(other)def __gt__(self, other):return self.score other.scoredef __ge__(self, other):return self.score other.scoredef get_name(self):return self.namedef get_age(self):return self.agedef get_score(self):return self.scoredef heapify(arr, n, i):largest ileft 2 * i 1right 2 * i 2if left n and arr[i] arr[left]:largest leftif right n and arr[largest] arr[right]:largest rightif 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) // 2def left_child(self, i):return 2 * i 1def right_child(self, i):return 2 * i 2def 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 iif 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 Nonemax_value self.heap[0]self.heap[0] self.heap[-1]self.heap.pop()self.heapify_down(0)return max_valuedef 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) 0def get_max(self):if self.is_empty():return Nonereturn 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 orderclass FibonacciHeap:# internal node classclass Node:def __init__(self, key, value):self.key keyself.value valueself.parent self.child self.left self.right Noneself.degree 0self.mark False# function to iterate through a doubly linked listdef iterate(self, head):node stop headflag Falsewhile True:if node stop and flag is True:breakelif node stop:flag Trueyield nodenode node.right# pointer to the head and minimum node in the root listroot_list, min_node None, None# maintain total node count in full fibonacci heaptotal_nodes 0# return min node in O(1) timedef 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_nodeif z is not None:if z.child is not None:# attach child nodes to root listchildren [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 Noneself.remove_from_root_list(z)# set new min node in heapif z z.right:self.min_node self.root_list Noneelse:self.min_node z.rightself.consolidate()self.total_nodes - 1return 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 laterdef insert(self, key, valueNone):n self.Node(key, value)n.left n.right nself.merge_with_root_list(n)if self.min_node is None or n.key self.min_node.key:self.min_node nself.total_nodes 1return n# modify the key of some node in the heap in O(1) timedef decrease_key(self, x, k):if k x.key:return Nonex.key ky x.parentif 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 heapslast h2.root_list.lefth2.root_list.left H.root_list.leftH.root_list.left.right h2.root_listH.root_list.left lastH.root_list.left.right H.root_list# update min node if neededif h2.min_node.key H.min_node.key:H.min_node h2.min_node# update total nodesH.total_nodes self.total_nodes h2.total_nodesreturn H# if a child node becomes smaller than its parent node we# cut this child node off and bring it up to the root listdef cut(self, x, y):self.remove_from_child_list(y, x)y.degree - 1self.merge_with_root_list(x)x.parent Nonex.mark False# cascading cut of parent node to obtain good time boundsdef cascading_cut(self, y):z y.parentif z is not None:if y.mark is False:y.mark Trueelse: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 treesdef 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.degreewhile A[d] ! None:y A[d]if x.key y.key:temp xx, y y, tempself.heap_link(y, x)A[d] Noned 1A[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 loopfor 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 listdef heap_link(self, y, x):self.remove_from_root_list(y)y.left y.right yself.merge_with_child_list(x, y)x.degree 1y.parent xy.mark False# merge a node with the doubly linked root listdef merge_with_root_list(self, node):if self.root_list is None:self.root_list nodeelse:node.right self.root_list.rightnode.left self.root_listself.root_list.right.left nodeself.root_list.right node# merge a node with the doubly linked child list of a root nodedef merge_with_child_list(self, parent, node):if parent.child is None:parent.child nodeelse:node.right parent.child.rightnode.left parent.childparent.child.right.left nodeparent.child.right node# remove a node from the doubly linked root listdef remove_from_root_list(self, node):if node self.root_list:self.root_list node.rightnode.left.right node.rightnode.right.left node.left# remove a node from the doubly linked child listdef remove_from_child_list(self, parent, node):if parent.child parent.child.right:parent.child Noneelif parent.child node:parent.child node.rightnode.right.parent parentnode.left.right node.rightnode.right.left node.leftdef 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_arrdef 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 iteratorusing 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 (siblingend * 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)
{makeHeapRandomAccessIterator(start, end);while (start ! end){--end;iter_swap(start, end);siftDown(start, end, start);}
}void heapSortTestCase()
{vectorint data {9, 8, 3, 7, 5, 6, 4, 1};heapSortvectorint::iterator(data.begin(), data.end());for (int i : data){cout i ;}cout endl;vectordouble dData {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};heapSortvectordouble::iterator(dData.begin(), dData.end());for (double i : dData){cout i ;}cout endl;vectorchar cData {a, c, b, d, e};heapSortvectorchar::iterator(cData.begin(), cData.end());for (char i : cData){cout i ;}cout endl;vectorPerson pData {Person(Alice, 20, 90), Person(Bob, 18, 85), Person(Charlie, 22, 95)};heapSortvectorPerson::iterator(pData.begin(), pData.end());for (Person i : pData){cout i.getName() i.getAge() i.getScore() endl;}cout endl;
}template typename T
void maxHeapify(vectorT 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(vectorT arr)
{int n arr.size();// Build max heapfor (int i n / 2 - 1; i 0; i--){maxHeapify(arr, i, n);}// Extract elements from heapfor (int i n - 1; i 0; i--){swap(arr[0], arr[i]);maxHeapify(arr, 0, i);}
}void binaryHeapSortTestCase()
{vectorint data {9, 8, 3, 7, 5, 6, 4, 1};binaryHeapSortint(data);for (int i : data){cout i ;}cout endl;vectordouble dData {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};binaryHeapSortdouble(dData);for (double i : dData){cout i ;}cout endl;vectorchar cData {a, c, b, d, e};binaryHeapSortchar(cData);for (char i : cData){cout i ;}cout endl;vectorPerson pData {Person(Alice, 20, 90), Person(Bob, 18, 85), Person(Charlie, 22, 95)};binaryHeapSortPerson(pData);for (Person i : pData){cout i.getName() i.getAge() i.getScore() endl;}cout endl;
}template typename T
class BinaryHeap
{
private:vectorT 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(vectorT data)
{BinaryHeapT 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()
{BinaryHeapint maxHeap;maxHeap.insert(10);maxHeap.insert(20);maxHeap.insert(15);maxHeap.insert(17);maxHeap.insert(25);maxHeap.print(); // 应该输出 25 20 15 17 10cout Peek: maxHeap.peek() endl; // 应该输出 25maxHeap.remove();maxHeap.print(); // 应该输出 20 17 15 10
}void BinaryHeapSortTestCase()
{vectorint data {9, 8, 3, 7, 5, 6, 4, 1};BinaryHeapSortint(data);for (int i : data){cout i ;}cout endl;vectordouble dData {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};BinaryHeapSortdouble(dData);for (double i : dData){cout i ;}cout endl;vectorchar cData {a, c, b, d, e};BinaryHeapSortchar(cData);for (char i : cData){cout i ;}cout endl;vectorPerson pData {Person(Alice, 20, 90), Person(Bob, 18, 85), Person(Charlie, 22, 95)};BinaryHeapSortPerson(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:nodeV *prev;nodeV *next;nodeV *child;nodeV *parent;V value;int degree;bool marked;public:friend class FibonacciHeapV;nodeV *getPrev() { return prev; }nodeV *getNext() { return next; }nodeV *getChild() { return child; }nodeV *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:nodeV *heap;public:FibonacciHeap(){heap _empty();}virtual ~FibonacciHeap(){if (heap){_deleteAll(heap);}}nodeV *insert(V value){nodeV *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(){nodeV *old heap;heap _removeMinimum(heap);V ret old-value;delete old;return ret;}void decreaseKey(nodeV *n, V value){heap _decreaseKey(heap, n, value);}nodeV *find(V value){return _find(heap, value);}private:nodeV *_empty(){return nullptr;}nodeV *_singleton(V value){nodeV *n new nodeV;n-value value;n-prev n-next n;n-degree 0;n-marked false;n-child nullptr;n-parent nullptr;return n;}nodeV *_merge(nodeV *a, nodeV *b){if (a nullptr)return b;if (b nullptr)return a;if (a-value b-value){nodeV *temp a;a b;b temp;}nodeV *an a-next;nodeV *bp b-prev;a-next b;b-prev a;an-prev bp;bp-next an;return a;}void _deleteAll(nodeV *n){if (n ! nullptr){nodeV *c n;do{nodeV *d c;c c-next;_deleteAll(d-child);delete d;} while (c ! n);}}void _addChild(nodeV *parent, nodeV *child){child-prev child-next child;child-parent parent;parent-degree;parent-child _merge(parent-child, child);}void _unMarkAndUnParentAll(nodeV *n){if (n nullptr)return;nodeV *c n;do{c-marked false;c-parent nullptr;c c-next;} while (c ! n);}nodeV *_removeMinimum(nodeV *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;nodeV *trees[64] {nullptr};while (true){if (trees[n-degree] ! nullptr){nodeV *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;}nodeV *min n;nodeV *start n;do{if (n-value min-value)min n;n n-next;} while (n ! start);return min;}nodeV *_cut(nodeV *heap, nodeV *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);}nodeV *_decreaseKey(nodeV *heap, nodeV *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);nodeV *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;}nodeV *_find(nodeV *heap, V value){nodeV *n heap;if (n nullptr)return nullptr;do{if (n-value value)return n;nodeV *ret _find(n-child, value);if (ret)return ret;n n-next;} while (n ! heap);return nullptr;}
};class DotFibonacciHeap : public FibonacciHeapint
{
public:void dump(){printf(digraph G {\n);if (heap nullptr){printf(empty;\n}\n);return;}printf(minimum - \%p\ [constraintfalse];\n, heap);nodeint *c heap;do{_dumpChildren(c);c c-getNext();} while (c ! heap);printf(}\n);}private:void _dumpChildren(nodeint *n){printf(\%p\ - \%p\ [constraintfalse,arrowheadlnormal];\n, n, n-getNext());printf(\%p\ - \%p\ [constraintfalse,arrowheadornormal];\n, n, n-getPrev());if (n-isMarked())printf(\%p\ [stylefilled,fillcolorgrey];\n, n);if (n-hasParent()){printf(\%p\ - \%p\ [constraintfalse,arrowheadonormal];\n, n, n-getParent());}printf(\%p\ [label%d];\n, n, n-getValue());if (n-hasChildren()){nodeint *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);nodeint *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(vectorT data)
{FibonacciHeapT 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()
{vectorint data {9, 8, 3, 7, 5, 6, 4, 1};FibonacciHeapSortint(data);for (int i : data){cout i ;}cout endl;vectordouble dData {9.9, 9.1, 3.3, 7.7, 5.5, 6.6, 4.4, 1.1};FibonacciHeapSortdouble(dData);for (double i : dData){cout i ;}cout endl;vectorchar cData {a, c, b, d, e};FibonacciHeapSortchar(cData);for (char i : cData){cout i ;}cout endl;vectorPerson pData {Person(Alice, 20, 90), Person(Bob, 18, 85), Person(Charlie, 22, 95)};FibonacciHeapSortPerson(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.