在程序设计相关领域,堆(Heap)的概念主要涉及到两个方面:
- 一种数据结构,逻辑上是一颗完全二叉树,存储上是一个数组对象(二叉堆)。
- 垃圾收集存储区,是软件系统可以编程的内存区域。
本文所说的堆,指的是前者。
堆排序的时间复杂度是O(nlgN),与快速排序达到相同的时间复杂度。但是在实际应用中,我们往往采用快速排序而不是堆排序。这是因为快速排序的一个好的实现,往往比堆排序具有更好的表现。堆排序的主要用途,是在形成和处理优先级队列方面。另外,如果计算要求是类优先级队列(比如,只要返回最大或者最小元素,只有有限的插入要求等),堆同样是很适合的数据结构。
基础知识
堆一般用数组表示,比如数组A数组的长度Length(A),堆在数组中的元素个数HeapSize(A)。一般说来,HeapSize(A) <= Length(A),因为数组A当中可能有一些元素不在堆中。
假设节点I是数组A中下标为i的节点。
- Parent(i) : return Floor(i/2); //I的父节点下标,Floor(i)表示比i小的最大整数。
- Left(i) : return 2*i; //I的左子节点
- Right(i) : return 2*i+1; //I的右子节点
含有n个元素的堆A的高度是: Floor(lgn)。
堆的基本操作
- MaxHeapify( A, i ):
保持堆的性质。假设数组A和下标i,假定以Left(i)和Right(i)为根结点的左右两棵子树都已经是最大堆,节点i的值可能小于其子节点。调整节点i的位置。
- BuildMaxHeap( A ):
从一个给定的数组建立最大堆。子数组A[ floor(n/2)+1 .... ... n]中的元素都是树的叶节点(完全二叉树的基本性质)。从索引 ceiling(n/2)开始一直到1,对每一个元素都执行MaxHeapify,最终得到一个最大堆。
- 堆排序 HeapSort( A ):
堆排序算法的基本思想是,将数组A创建为一个最大堆,然后交换堆的根(最大元素)和最后一个叶节点x,将x从堆中去掉形成新的堆A1,然后重复以上动作,直到堆中只有一个节点。
- 优先级队列算法-增加某元素的值(优先级) : HeapIncreaseKey( A, i, key )
增加某一个元素的优先级后(元素的值),该元素应该向上移动,才能保持堆的性质。
- 优先级队列算法-插入一个元素: Insert( S, x ) 将x元素插入到优先级队列S中。
主要思路是,将堆的最后一个叶节点之后,扩展一个为无穷小的新叶节点,然后增大它的值为x的值。
c++实现代码
//HeapSort.h文件 class HeapSort { public: //HeapSort(); //HeapSort(const HeapSort &orig); //virtual ~HeapSort(); void shift(int r[], int i, int m); void heapSortInt(int array[], int n); private: };
<span style="color: rgb(18, 28, 70); font-family: Verdana, 宋体; line-height: 18px; text-indent: 24px; background-color: rgb(240, 240, 240);">#include "HeapSort1.h"</span> using namespace std; //HeapSort::HeapSort(const HeapSort &orig){} //HeapSort::~HeapSort(){} void HeapSort::shift(int k[], int i, int n) //这个函数就是求三个节点中最大的。 { int j; int temp = k[i];//i个节点对应的数组值 j = 2*i;//左孩的下标 while (j <= n) { if (j < n&&k[j] < k[j + 1]) j++; //右孩大 if (temp>k[j]) //父节点大 break; //实际上发现只做一次循环,才能用break,否则应该用continue k[j / 2] = k[j]; //大的赋给节点 j = j * 2; } k[j / 2] = temp; } void HeapSort::heapSortInt(int k[], int n)//这个函数实现建堆和排序交换后的调整 { for (int i = n / 2; i > 0; i--) //建堆 shift(k, i, n); for (int j = n; j > 0; j--) { int temp = k[j]; k[j] = k[1]; k[1] = temp; shift(k, 1, j - 1); //对发生变化的第一个节点调整 } }
<pre name="code" class="cpp">#include "HeapSort1.h" #include <iostream> #include <stdlib.h> using namespace std; void main() { int n = 10; int a[] = { 0, 12, 432, 436, 54646, 76, 687, 6879, 89, 2, 5 };//第一个元素为0, cout << "大顶堆排序前的序列:" << endl; for (int i = 1; i <= 10; i++) { cout << a[i] << endl; } HeapSort hs; hs.heapSortInt(a, n); cout << "大顶堆排序后的序列:" << endl; for (int i = 1; i <= 10; i++) { cout << a[i] << endl; } system("pause"); }