堆排序
来源:互联网 发布:西游之路坐骑进阶数据 编辑:程序博客网 时间:2024/06/06 13:01
1.堆
堆排序集合了归并排序的优点:时间复杂度位O(nlgn)
插入排序的优点:具有空间原址性(任何时候只需要常数个额外的元素空间存储临时数据)
堆是一个数组,可以被看成是一个近似的完全二叉树。堆上的每个节点对应数组中的一个元素。除了最底层外,该树是完全充满的。这样给定一个结点的下标 i,我们很容易计算得到它的父结点、左孩子和右孩子的下标。
PARENT(i)
return ⌊i/2⌋
LEFT(i)
return 2i
RIGHT(i)
return 2i+1
最大堆性质:除了根节点以外的结点 i 都要满足:A [PARENT(i)] >= A[ i ],堆中最大元素存放在根结点 中
最小堆性质:除了根节点以外的结点 i 都要满足:A [PARENT(i)] <= A[ i ],堆中最小元素存放在根结点中
排序一般用最大堆实现,最小堆常用来构造优先队列。
2.维护堆的性质
堆中结点的高度:就是该结点到叶结点最长简单路径上边的数目。包含n个元素的堆高度为 lgn。
MAX-HEAPIFY过程:调整堆为最大堆,时间复杂度为 O(nlgn)。
BUILD-MAX-HEAP过程:从无序的输入数据数组中构造一个最大堆,具有线性时间复杂度。
HEAPSORT过程 :对一个数组进行原址排序,时间复杂度为 O(nlgn)。
MAX-HEAP-INSERT、HEAP-EXTRACT-MAX、HEAP_INCREASE-KEY和HEAP-MAXIMUM过程:利用堆实现一个优先队列,时间复杂度为O(lgn)。
MAX-HEAPIFY(A,i)//MAX-HEAPIFY通过让A[i]的值在最大堆中“逐级下降”,从而使下标i为根节点的子树重新遵循最大堆的性质。l=LEFT(i)r=RIGHT(i)if l<=A.heap-size and A[l]>A[i] largest=lelse largest=iif r<=A.heap-size and A[r]>A[largest] largest=rif largest !=i exchange A[i] with A[largest] MAX-HEAPIFY(A,largest)
在程序的每一步中,从A[i]、A[LEFT(i)]、A[RIGHT(i)]中选出最大的,并将其下标存储在largest中。如果A[i]是最大的,那么以i为根节点的子树已经是最大堆,程序结束,否则,最大元素是i的某一个孩子节点,交换A[i]和A[largest]的值,使其孩子都满足最大堆的性质。交换后,下标为largest的结点的值是原来的A[i],于是以该节点为根的子树又有可能会违反最大堆的性质。因此需对该子树递归调用MAX-HEAPIFY。过程如下图:
3.建堆
我们可以用自底向上的方法利用MAX-HEAPIFY把一个大小为n的数组转化为最大堆。每个叶结点都可以看成是只包含一个元素的堆。过程BUILD-MAX-HEAP堆树中其他节点都调用一次MAX-HEAPIFY。
BUILD-MAX-HEAP(A )A.heap-size = A.lengthfor i = ⌊A.length/2⌋ downto 1 //从第一个非叶结点开始调整,直到根节点 MAX-HEAPIFY(A,i)
4.堆排序算法
初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组建成最大堆。因为数组中的最大元素总在根节点A[1]中,通过把它与A[n]进行交换,我们可以让该元素放到正确的位置。这时候我们从堆中去掉结点n,剩余的结点中,原来根节点的孩子仍然是最大堆,而新的节点可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的仍然是调用MAX-HEAPIFY(A,1)。堆排序算法会不断重复这一过程,直到堆的大小从n-1降到2.
HEAPSORT(A) //时间复杂度为O(nlgn)BUILD-MAX-HEAP(A)for i = A.length downto 2 //n-1次调用<font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><font size="3"><span style="font-size:14px;"><span style="font-size:14px;"><span style="font-size:14px;">MAX-HEAPIFY</span></span></span></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font> exchange A[1] with A[i] A.heap-size = A.heap-size - 1 MAX-HEAPIFY(A,1) //时间复杂度为O(lgn)
以下是堆排序的完整实现:
#include <stdio.h>#include <stdlib.h>#include <malloc.h>#include <time.h>void PrintArr(int *pnArr, int nLen){ for (int i = 0; i < nLen; i++) { printf("%d ", pnArr[i]); } printf("\n");}//返回i父节点下标int Parent(int i) //下标从0开始{ return (i - 1) / 2;}//返回i左孩子下标int LeftChild(int i){ return i * 2 + 1;}//返回i右孩子下标int RightChild(int i){ return i * 2 + 2;}void Swap(int *a, int *b){ int nTmp = *a; *a = *b; *b = nTmp;}void MaxHeapify(int *pnArr, int nLen, int i){ int LChild = LeftChild(i); int RChild = RightChild(i); int nMaxPos; if (LChild < nLen && pnArr[LChild] > pnArr[i]) { nMaxPos = LChild; } else { nMaxPos = i; } if (RChild < nLen && pnArr[RChild] > pnArr[nMaxPos]) { nMaxPos = RChild; } if (nMaxPos != i) { Swap(&pnArr[nMaxPos], &pnArr[i]); MaxHeapify(pnArr, nLen,nMaxPos); } }void BuildMaxHeap(int *pnArr, int nLen){ for (int i = Parent(nLen -1); i >= 0; i--) { MaxHeapify(pnArr, nLen, i); }}void HeapSort(int *pnArr, int nLen){ BuildMaxHeap(pnArr, nLen); for (int i = nLen - 1; i > 0; i--) { Swap(&pnArr[i], &pnArr[0]); nLen--; MaxHeapify(pnArr, nLen, 0); }}int main(){ int nArr[10] = {4,1,3,2,16,9,10,14,8,7}; //下标从0开始 PrintArr(nArr, 10); HeapSort(nArr, 10); PrintArr(nArr, 10);system("pause"); return 0;}
- 堆及堆排序
- 堆/堆排序特点
- 【二叉堆、堆排序】
- 二叉堆 & 堆排序
- 二叉堆 & 堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆与堆排序
- 堆和堆排序
- 堆排序(最大堆)
- 堆和堆排序
- 堆和堆排序
- 堆及堆排序
- 堆和堆排序
- 堆与堆排序
- 借助SystemBarTint实现透明标题栏(沉浸式)
- 最近对问题,分治法求解
- Android Studio 2.1 Preview 4 发布,以及新增的两点攺动.
- adb相关问题
- 合并模拟器和真机调试的静态库
- 堆排序
- UVA 11090 图论加二分
- ubuntu tftp服务搭建
- CentOS6 Shell脚本/bin/bash^M: bad interpreter错误解决方法
- IOS百度地图自定义大头针和气泡
- 【BZOJ1041】[HAOI2008]圆上的整点【数学】
- static关键字
- 田忌赛马
- 浅谈持久层框架中的缓存机制