堆排序
2016-03-28 20:24
295 查看
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)。
在程序的每一步中,从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。
4.堆排序算法
初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组建成最大堆。因为数组中的最大元素总在根节点A[1]中,通过把它与A
进行交换,我们可以让该元素放到正确的位置。这时候我们从堆中去掉结点n,剩余的结点中,原来根节点的孩子仍然是最大堆,而新的节点可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的仍然是调用MAX-HEAPIFY(A,1)。堆排序算法会不断重复这一过程,直到堆的大小从n-1降到2.
以下是堆排序的完整实现:
堆排序集合了归并排序的优点:时间复杂度位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=l else largest=i if r<=A.heap-size and A[r]>A[largest] largest=r if 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.length for i = ⌊A.length/2⌋ downto 1 //从第一个非叶结点开始调整,直到根节点 MAX-HEAPIFY(A,i)
4.堆排序算法
初始时候,堆排序算法利用BUILD-MAX-HEAP将输入数组建成最大堆。因为数组中的最大元素总在根节点A[1]中,通过把它与A
进行交换,我们可以让该元素放到正确的位置。这时候我们从堆中去掉结点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; }
相关文章推荐
- Android Studio 2.1 Preview 4 发布,以及新增的两点攺动.
- 使用brew安装软件
- AOJ2249Contest Page(最短路径spfa)
- 送伞
- 数组指针和指针数组
- Win7下配置"JAVA环境变量"—JDK的安装与配置
- 数据库-T-SQL 语句-高级查询
- 程序员面试心得总结
- 【软件工程】复利计算程序单元测试
- NSString、NSData、char* 类型之间的转换-备
- 红黑树代码实践
- 28 map
- Android学习:数据持久化技术(一,File & SharePreference)
- nginx优化篇之Linux 内核参数的优化
- Maven配置
- Leetcode 111. Minimum Depth of Binary Tree My Submissions QuestionEditorial Solution
- 项目14-三角形类雏形(3)
- 【HDOJ 5652】 India and China Origins(并查集)
- vitamio for android的使用
- HDU 2841 容斥原理