堆排序(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);
堆排序实现代码(基于升序排列):
1 //堆排序 2 #include <iostream> 3 #include <cstring> 4 #include <string> 5 #include <cmath> 6 #include <algorithm> 7 using namespace std; 8 void heapSortDown(int a[],int start,int end) 9 { 10 int c=start; 11 int l=c*2+1; 12 int temp=a[c]; 13 for(;l<=end;c=l,l=l*2+1) 14 { 15 if(l<end&&a[l]<a[l+1]) l++; 16 if(temp>=a[l]) break; 17 else 18 { 19 a[c]=a[l]; 20 a[l]=temp; 21 } 22 } 23 } 24 void heapsort_asc(int a[],int n) 25 { 26 int i,temp; 27 for(i=n/2-1;i>=0;i--) heapSortDown(a,i,n-1); 28 for(i=n-1;i>0;i--) 29 { 30 temp=a[0]; 31 a[0]=a[i]; 32 a[i]=temp; 33 heapSortDown(a,0,i-1); 34 } 35 } 36 int main() 37 { 38 int a[]={9999,4532,1234,9067,1345,6789,5432,6547,9801,100001}; 39 int ilen=sizeof(a)/sizeof(a[0]); 40 cout<<"before sort: "; 41 for(int i=0;i<ilen;i++) cout<<a[i]<<" "; 42 cout<<endl; 43 heapsort_asc(a,ilen); 44 cout<<"after sort: "; 45 for(int i=0;i<ilen;i++) cout<<a[i]<<" "; 46 cout<<endl; 47 }
堆排序升序代码:
1 /* 2 * (最大)堆的向下调整算法 3 * 4 * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。 5 * 其中,N为数组下标索引值,如数组中第1个数对应的N为0。 6 * 7 * 参数说明: 8 * a -- 待排序的数组 9 * start -- 被下调节点的起始位置(一般为0,表示从第1个开始) 10 * end -- 截至范围(一般为数组中最后一个元素的索引) 11 */ 12 void maxheap_down(int a[], int start, int end) 13 { 14 int c = start; // 当前(current)节点的位置 15 int l = 2*c + 1; // 左(left)孩子的位置 16 int tmp = a[c]; // 当前(current)节点的大小 17 for (; l <= end; c=l,l=2*l+1) 18 { 19 // "l"是左孩子,"l+1"是右孩子 20 if ( l < end && a[l] < a[l+1]) 21 l++; // 左右两孩子中选择较大者,即m_heap[l+1] 22 if (tmp >= a[l]) 23 break; // 调整结束 24 else // 交换值 25 { 26 a[c] = a[l]; 27 a[l]= tmp; 28 } 29 } 30 } 31 32 /* 33 * 堆排序(从小到大) 34 * 35 * 参数说明: 36 * a -- 待排序的数组 37 * n -- 数组的长度 38 */ 39 void heap_sort_asc(int a[], int n) 40 { 41 int i; 42 43 // 从(n/2-1) --> 0逐次遍历。遍历之后,得到的数组实际上是一个(最大)二叉堆。 44 for (i = n / 2 - 1; i >= 0; i--) 45 maxheap_down(a, i, n-1); 46 47 // 从最后一个元素开始对序列进行调整,不断的缩小调整的范围直到第一个元素 48 for (i = n - 1; i > 0; i--) 49 { 50 // 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。 51 swap(a[0], a[i]); 52 // 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。 53 // 即,保证a[i-1]是a[0...i-1]中的最大值。 54 maxheap_down(a, 0, i-1); 55 } 56 }
参考:https://www.cnblogs.com/skywang12345/p/3602162.html(包含升序,降序)