堆-堆排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆-堆排序相关的知识,希望对你有一定的参考价值。

    堆排序,与归并排序一样,时间复杂度为O(nlgn),与插入排序一样,具有空间原址性:任何时候都只需要常数个额外的元素空间存储临时数据。(二叉)堆是一个数组,可以被看成一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素。除了最底层外,该树是完全充满的,而且是从左向右填充。表示堆的数组A有两个属性:A.length为数组元素的个数,A.heap-size表示有多少个堆元素存储在数组中。树的根结点为A[0],容易得到父结点、左孩子和右孩子的下标:

技术分享

二叉堆分为最大堆和最小堆。结点的值都要满足堆序性质,最大堆中,堆中的最大元素存放在根结点中;并且,在任一子树中,该子树所包含的所有结点的值都不大于该子树根结点的值,最小堆性质相反。
堆的基本过程:
Max-Heapify过程:时间复杂度为O(lgn),是维护最大堆性质的关键。
Build-Max-Heap过程:具有线性时间复杂度,功能是从无序的输入数据数组中构造一个最大堆。
HeapSort过程:时间复杂度为O(nlgn),功能是对一个数据进行原址排序。
Max-Heap-Insert、Heap-Extract-Max、Heap-Increase-Key和Heap-Maximum过程:时间复杂度为O(lgn),功能是利用堆实现一个优先队列。

Max-Heapify的输入为一个数组A和一个下标i,通过让A[i]的值在最大堆中“逐级下降",从而使得以下标i为根结点的子树重新遵循最大堆的性质,可通过递归和非递归两种方式实现,代码如下:
 1 void 
 2 percDownRecursion(int a[],int i, int n)   // max-heapify 下滤 维护最大堆性质 递归方式
 3 {
 4     int left = left(i);
 5     int right = right(i);
 6     int large;
 7     if(left < n && a[left] > a[i])
 8         large = left;
 9     else
10         large = i;
11     if(right < n && a[right] > a[large])
12         large = right;
13     if(large != i){
14         swap(a[i],a[large]);
15         percDownRecursion(a,large,n);
16     }
17 }
 1 void percDown(int a[],int i, int n)      //max-heapify 下滤 维护最大堆性质 非递归方式
 2 {
 3         int child;
 4     int tmp;
 5     
 6     for(tmp = a[i]; left(i) < n; i = child)
 7     {
 8         child = left(i);
 9         if(child != n-1 && a[child + 1] > a[child])
10             child++;
11         if(tmp < a[child])
12             a[i] = a[child];
13         else
14             break;
15     }
16     a[i] = tmp;
17 }

    建堆,可以用自底向上的方法利用过程Max-Heapify把一个大小为n的数组A转换为最大堆,A[n/2]后的元素都是树的叶结点,每个叶结点都可以看成只包含一个元素的堆,时间复杂度为O(n)。。

1 void buildMaxHeap(int a[], int n)
2 {
3     for(int i = n/2; i >= 0; i--) // build heap 构建最大堆
4         percDownRecursion(a,i,n);
5 }

      堆排序,堆排序算法利用Build-Max-Heap将输入数组A建成最大堆,因为数组中的最大元素总在根结点A[0]中,通过把它与A[n-1]进行互换,可以让该元素放到正确的位置,缩减堆的大小并进行下滤,从而在A[0...n-2]上构造一个新的最大堆。堆排序算法会不断重复这一过程,直到堆的大小从n-1降到1。

 1 void
 2 heapSort(int a[], int n)
 3 {
 4         buildMaxHeap(a,n);
 5     for(int i = n-1; i > 0; i--)
 6     {
 7         swap(a[0],a[i]);   
 8         percDownRecursion(a,0,i); //或者调用percDown(a,0,i)
 9     }
10 }

例子:

1 int main()
2 {
3    int a[] = {97,53,59,26,41,58,31};
4    int size = 7;
5    heapSort(a,size);
6    for(int i=0; i < size; ++i)
7      printf("%d ",a[i]);
8    printf("\\n");
9  }

输出:

技术分享

以上是关于堆-堆排序的主要内容,如果未能解决你的问题,请参考以下文章

排序--08---堆排序

选择排序(简单选择排序堆排序的算法思想及代码实现)

python代码实现堆排序

一文带你了解堆排序

堆排序

算法——堆排序(大根堆--升序)