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
#include
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)<cin>>a[i];
}
build_maxheap(a,n);
heapsort(a, n);
cout<<"sorted output\n";
for (i = 1; i <= n; i++)
{
cout<
测试运行结果截图
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/