排序算法之堆排序详解(附最大堆示例代码)
来源:互联网 发布:数据散修txt下载 编辑:程序博客网 时间:2024/04/28 18:17
1.堆的概念(最大堆与最小堆)
堆排序的时间复杂度是n logN,具有nl og N时间复杂度的排序算法还有快速排序和理想状态下的归并排序,一般来说快速排序的性能优于堆排序,但堆排序在实际中也有很多的应用,后续会做具体介绍.
堆指的是堆数据结构,被看成是一个近似的完全二叉树,树上的每一个结点对应数组中的一个元素.
完全二叉树满足两个特性:
1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
最大堆性质是指除了根以外的所有结点i都要满足:A[PARENT(i)]>=A[i];,也就是说,某个结点的值至多与其父结点一样大.,因此,堆中的最大元素存放在根结点中,并且,在任一子树种,该子树所包含的所有结点的值都不大于该子树根结点的值.
最小堆性质是指除了根以外的所有结点i都有A[PARENT]<=A[i];最小堆中的最小元素存放在根结点中.
在堆排序算法中,我们使用的是最大堆,最小堆通常用于构造优先数列.
2.堆排序原理
堆排序可分为3个步骤:
1.建堆:堆排序算法利用BUILD-MAX-HEAP将输入数组A[1..n]建成最大堆,其中n=A.length.因为数组中的最大元素总在根结点A[1]中,通过把它与A[n]进行互换,我们可以让该元素放到正确的位置
2.调整堆,因为交换之后新的根结点可能会违背最大堆的性质,为了维护最大堆的性质,我们要做的就是调用MAX-HEAP(A,1),从而在A[1,n-1]上构造一个新的最大堆
3.递归调用:堆排序算法会不断重复这一过程,直到堆的大小从n-1降到2位置终止递归调取,到此排序完成.
堆排序伪代码
调整堆
MAX-HEAPIFY(A,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)
建堆
BUILD-MAX-HEAP(A)
A.heap-size = A.length
for i = (A.length/2) downto 1
MAX-HEAPPIFY(A,i)
递归调用
HEAPSORT(A)
BUILD-MAX-HEAP(A)
for i = A.length downto 2
exchange A[1] with A[i]
A.heap-size = A.heap-size - 1
MAX-HEAPIFY(A,1)
3.堆排序示例代码
最大堆的java代码实现
private static int N; /* Sort Function */ //传入一个数组进行堆排序 public static void sort(int arr[]) { //建堆 heapify(arr); for (int i = N; i > 0; i--) { swap(arr, 0, i); N = N - 1; maxheap(arr, 0); } } //建堆的方法 /* Function to build a heap */ public static void heapify(int arr[]) { N = arr.length - 1; //循环调用调整堆,直到堆的大小到2为止 for (int i = N / 2; i >= 0; i--) maxheap(arr, i); } //调整堆使其根结点为最大元素 /* Function to swap largest element in heap */ public static void maxheap(int arr[], int i) { int left = 2 * i; int right = 2 * i + 1; int max = i; if (left <= N && arr[left] > arr[i]) max = left; if (right <= N && arr[right] > arr[max]) max = right; if (max != i) { swap(arr, i, max); //递归调用堆的调整堆的方法 maxheap(arr, max); } } /* Function to swap two numbers in an array */ //交换数组i和j位置的元素 public static void swap(int arr[], int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } /* 测试方法 */ @Test public void heapSortTest() { int arr[] = {222, 5, 2, 4, 6, 1, 3, 11, 9, 10, 8, 7, 0}; sort(arr); System.out.println(Arrays.toString(arr)); }
c++代码实现
/* * C++ Program to Implement Heap Sort */#include <iostream>#include <conio.h>using namespace std;void max_heapify(int *a, int i, int n){ int j, temp; temp = a[i]; j = 2*i; while (j <= n) { if (j < n && a[j+1] > a[j]) j = j+1; if (temp > a[j]) break; else if (temp <= a[j]) { a[j/2] = a[j]; j = 2*j; } } a[j/2] = temp; return;}void heapsort(int *a, int n){ int i, temp; for (i = n; i >= 2; i--) { temp = a[i]; a[i] = a[1]; a[1] = temp; max_heapify(a, 1, i - 1); }}void build_maxheap(int *a, int n){ int i; for(i = n/2; i >= 1; i--) { max_heapify(a, i, n); }}int main(){ int n, i, x; cout<<"enter no of elements of array\n"; cin>>n; int a[20]; for (i = 1; i <= n; i++) { cout<<"enter element"<<(i)<<endl; cin>>a[i]; } build_maxheap(a,n); heapsort(a, n); cout<<"sorted output\n"; for (i = 1; i <= n; i++) { cout<<a[i]<<endl; } getch(); }
测试运行结果截图
4.优先队列简介
优先队列有两种形式:最大优先队列和最小优先队列.
优先队列是一种用来维护由一组元素构成的集合S的数据结构,其中的每一个元素都有一个相关的值,成为关键字.一个最大优先队列支持一下操作:
INSERT(S,x):把元素x插入集合S中.这一操作等价于S = S U {x}.
MAXIMUM(S):返回S中具有最大关键字的元素.
EXTRACT-MAX(S):去掉并返回S中的具有最大关键字的元素.
INCREASE-KEY(S,x,k):将元素x的关键字值增加到k,这里假设k的值不小于x的原关键字值.
最大优先队列的应用有很多,其中一个就是在共享计算机系统的作业调度
最小优先队列可以用于基于事件驱动的模拟器.
在一个包含n个元素的堆中,所有优先队列的操作都可以在O(lg n)时间内完成.
如有不足之处请指正,谢谢!
附上最小堆排序的链接:http://blog.csdn.net/morewindows/article/details/6709644/
参考过别人的链接:http://www.sanfoundry.com/java-program-implement-heap-sort/
- 排序算法之堆排序详解(附最大堆示例代码)
- 排序算法之插入排序详解(附示例代码)
- 排序算法之快速排序详解(附示例代码)
- 堆排序算法代码
- 堆排序算法详解
- 堆排序算法详解
- 堆排序算法详解
- 算法之堆排序(最大堆c++实现)
- 堆排序(最大堆)
- 堆排序(最大堆)
- 最大堆 堆排序
- 排序算法_堆排序(最大堆、最小堆)
- 算法之堆排序
- 算法之堆排序
- 算法之堆排序
- 算法之堆排序
- 算法之堆排序
- 算法之堆排序
- ZooKeeper
- aidl
- (数论)进制转换一(将十进制转换成b进制)
- mysql存储过程利用游标查询每个数据库的所有表
- 线段树—数组计算机
- 排序算法之堆排序详解(附最大堆示例代码)
- 蓝桥杯 2012 5 方块填数
- 浅谈跨域(五)——Web Sockets试用
- jsp中页面之间的跳转forward与sendRedirect的区别
- redis被黑客入侵
- 优化算法:梯度法
- java抽象类和接口的区别
- Linux下oracle数据库启动和关闭操作
- Win7旗舰版如何关闭开机磁盘自检