堆排序

堆排序的思想:

1.首先写一个维护二叉堆的函数,其作用是使完全二叉树的某个根节点下开始的所有父节点都比其左右子节点大(堆的性质);

2.然后自底向顶建立一棵完全二叉树,建树的过程就是第一次维护二叉堆的过程。然后交换堆顶元素和堆底的最后一个元素,形成一个新的堆。新的堆是指原来的堆中去除二叉堆中底层的最后一个元素的堆;

3.最后利用1中的维护函数维护新堆,然后交换堆顶元素和堆底最后一个元素,又形成一个新堆。反复迭代此步骤,直至堆中只剩1个元素。至此,堆排序完成,每次从堆顶交换的元素依次排列就是排序的结果。

堆排序的一些结论:

1.堆排序的时间复杂度为n*log2n。很多书上直接写成nlogn,意思是一样的;

2.堆排序是不稳定排序。所谓不稳定是指一个数组中值相同而数组下标不同的两个元素,其数组下标有可能互换,即元素发生了互换。

 1 堆排序的代码:
 2 
 3 #include<iostream>
 4 using namespace std;
 5 
 6 //定义一个struct heap_t类型的结构体,Heap是struct heap_t的别名,即Heap=struct heap_t
 7 typedef struct heap_t
 8 { 
 9     int *arr; //指向一个存储堆值的数组
10     int heapMaxIndex; //数组索引下标的最大值,即数组的长度-1
11     int arrLength; //数组的长度
12 }Heap;
13 
14 15 //维护堆函数。该函数是堆排序的基础,作用是使下标为nodei的节点作为根节点的子树,所有的父节点值均比起左右子节点的值大(堆的性质) 16 void maxHeapify(Heap *hp, unsigned int nodei) 17 { 18 unsigned int l=((nodei+1)<<1)-1; //left child 的下标 19 unsigned int r=(nodei+1)<<1 ; // right child 的下标 20 unsigned int largest = 0; //用于存储父节点、左子树、右子树3个节点中的最大值的下标 21 int heapMaxI = hp->heapMaxIndex; //数组索引下标的最大值,等于数组的长度-1 22 23 if(l <= (unsigned)heapMaxI && hp->arr[l] > hp->arr[nodei]) 24 largest = l ; 25 else 26 largest = nodei ; 27 28 if(r <= (unsigned)heapMaxI && hp->arr[r] > hp->arr[largest]) 29 largest = r ; 30 31 if(largest!=nodei) 32 { 33 //交换堆顶和对底的元素 34 int tmp ; 35 tmp = hp->arr[largest]; 36 hp->arr[largest] = hp->arr[nodei]; 37 hp->arr[nodei] = tmp; 38 39 maxHeapify(hp,largest); //这句是该函数的关键。largest!=nodei,说明下标为nodei的父节点的值和其子节点中下标为largest的值发生了交换,则largest中存储的nodei。这次交换可能会使nodei(这时已经交换换成了,nodei变成了原来树的子节点)作为父节点所在的子树不符合堆的性质,所以需要递归调用一下该函数,使得整个二叉树符合堆的性质 40 } 41 42 else 43 { 44 return ; 45 } 47 } 48 49 50 //建堆函数,新建的堆保证了每个父节点都比其左右子节点大,这就符合了堆的性质。 51 Heap *createHeap(int *arrp, int arrLength,Heap *heap) 52 { 53 int i; 54 heap->arr = arrp; 55 heap->heapMaxIndex = arrLength-1; 56 heap->arrLength = arrLength; 57 58 //注意,建堆是从底下向上建的,因为从底下向上,维护堆的复杂度依次递增(建堆的过程中就是第一次维护堆的过程) 59 for(i = (arrLength>>1)-1; i >=0; i--) 60 maxHeapify(heap,i); 61 return heap; 62 } 63 66 //堆排序函数,对一个堆进行排序 67 void heapSort(Heap *hp) 68 { 69 int tmp; 70 int last; 71 while(hp->heapMaxIndex>0) //将堆顶放到堆的最后,堆元素个数-1,对新堆进行排序,直至新堆的元素个数为1 72 { 73 last = hp->heapMaxIndex ; 74 //exchange 75 tmp = hp->arr[last]; 76 hp->arr[last] = hp->arr[0]; 77 hp->arr[0] = tmp; 78 hp->heapMaxIndex -= 1; 79 maxHeapify(hp,0); //堆顶元素和堆的最后一个元素交换后,需要维护堆。维护堆的过程是自顶向下维护堆,因为交换的是堆顶的元素,整个堆都需要被维护 80 } 81 } 82 83 int main() 84 { 85 int a[]={15,25,32,23,1,-4,35,2,-85,42,0,12,26,56,45,12,145,17,25,21}; 86 87 Heap hpa,*phpa; 88 phpa = createHeap(a,20,&hpa); 89 heapSort(phpa); 90 91 for(int i=0;i<20;i++) 92 { 93 cout<<a[i]<<" "; 94 } 95 cout<<endl; 96 97 return 0; 98 }
原文地址:https://www.cnblogs.com/jswu-ustc/p/8313098.html