hanyujianke 2020-01-04
堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法。
因此,学习堆排序之前,有必要了解堆!
我们知道,堆分为"最大堆"和"最小堆"。最大堆通常被用来进行"升序"排序,而最小堆通常被用来进行"降序"排序。
鉴于最大堆和最小堆是对称关系,理解其中一种即可。本文将对最大堆实现的升序排序进行详细说明。
最大堆进行升序排序的基本思想:
① 初始化堆:将数列a[1...n]构造成最大堆。
② 交换数据:将a[1]和a[n]交换,使a[n]是a[1...n]中的最大值;然后将a[1...n-1]重新调整为最大堆。 接着,将a[1]和a[n-1]交换,使a[n-1]是a[1...n-1]中的最大值;然后将a[1...n-2]重新调整为最大值。 依次类推,直到整个数列都是有序的。
实现中用到了"数组实现的二叉堆的性质"。
在第一个元素的索引为 0 的情形中:
性质一:索引为i的左孩子的索引是 (2*i+1);
性质二:索引为i的左孩子的索引是 (2*i+2);
性质三:索引为i的父结点的索引是 floor((i-1)/2);
堆排序实现代码(基于升序排列):
//堆排序 #include <iostream> #include <cstring> #include <string> #include <cmath> #include <algorithm> using namespace std; void heapSortDown(int a[],int start,int end) { int c=start; int l=c*2+1; int temp=a[c]; for(;l<=end;c=l,l=l*2+1) { if(l<end&&a[l]<a[l+1]) l++; if(temp>=a[l]) break; else { a[c]=a[l]; a[l]=temp; } } } void heapsort_asc(int a[],int n) { int i,temp; for(i=n/2-1;i>=0;i--) heapSortDown(a,i,n-1); for(i=n-1;i>0;i--) { temp=a[0]; a[0]=a[i]; a[i]=temp; heapSortDown(a,0,i-1); } } int main() { int a[]={9999,4532,1234,9067,1345,6789,5432,6547,9801,100001}; int ilen=sizeof(a)/sizeof(a[0]); cout<<"before sort:\n"; for(int i=0;i<ilen;i++) cout<<a[i]<<" "; cout<<endl; heapsort_asc(a,ilen); cout<<"after sort:\n"; for(int i=0;i<ilen;i++) cout<<a[i]<<" "; cout<<endl; }
堆排序升序代码:
/* * (最大)堆的向下调整算法 * * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。 * 其中,N为数组下标索引值,如数组中第1个数对应的N为0。 * * 参数说明: * a -- 待排序的数组 * start -- 被下调节点的起始位置(一般为0,表示从第1个开始) * end -- 截至范围(一般为数组中最后一个元素的索引) */ void maxheap_down(int a[], int start, int end) { int c = start; // 当前(current)节点的位置 int l = 2*c + 1; // 左(left)孩子的位置 int tmp = a[c]; // 当前(current)节点的大小 for (; l <= end; c=l,l=2*l+1) { // "l"是左孩子,"l+1"是右孩子 if ( l < end && a[l] < a[l+1]) l++; // 左右两孩子中选择较大者,即m_heap[l+1] if (tmp >= a[l]) break; // 调整结束 else // 交换值 { a[c] = a[l]; a[l]= tmp; } } } /* * 堆排序(从小到大) * * 参数说明: * a -- 待排序的数组 * n -- 数组的长度 */ void heap_sort_asc(int a[], int n) { int i; // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。 for (i = n / 2 - 1; i >= 0; i--) maxheap_down(a, i, n-1); // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素 for (i = n - 1; i > 0; i--) { // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。 swap(a[0], a[i]); // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。 // 即,保证a[i-1]是a[0...i-1]中的最大值。 maxheap_down(a, 0, i-1); } }
参考:https://www.cnblogs.com/skywang12345/p/3602162.html(包含升序,降序)