堆排序概述
堆排序定义
n个关键字序列k(1), k(2), ..., k(n)称为堆,当且仅当该序列满足如下性质(简称为堆性质)
- k(i) <= k(2i) && k(i) <= k(2i+1)
- k(i) >= k(2i) && k(i) >= k(2i+1)
若将此序列所存储的向量R[1..n]看做是一颗完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:树中任一非叶结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。
大根堆和小根堆
- 根结点(亦称堆顶)的关键字是堆里所有结点关键字中最小者的堆称为小根堆
- 根节点(亦称堆顶)的关键字是堆里所有结点关键字中最大者,称为大根堆
堆排序特点
- 堆排序(heap sort)是一树形选择排序
- 在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系,在当前无序区中选择关键字最大(或最小)的记录
堆排序
堆排序推荐阅读《算法导论》,这里把算法导论里的伪代码用c语言实现,并且优化算法结构
保持堆性质(非递归c语言)
/**
* Description:从节点i开始,维护以i为根节点的子树,使以i为根的子树为最大堆(非递归)
*/
void MaxHeapIfy(int *A, int i, int n)
{
int l, r, largest, temp, loc;
for(largest = i; largest <= n;)
{
l = 2 * largest;
r = 2 * largest + 1;
loc = largest;
if(l <= n && A[l] > A[largest])
{
largest = l;
}
if(r <= n && A[r] > A[largest])
{
largest = r;
}
//如果最大值不是根节点,那么交换A[loc], A[largest]
if(largest != loc)
{
temp = A[largest];
A[largest] = A[loc];
A[loc] = temp;
}else
{
break;
}
}
}
建堆
我们采用自底向上地用MaxHeapIfy来将一个数组A变成一个大根堆。子数组A([n/2]+1 .. n)均为叶子节点,所以我们只需要自底向上遍历非叶子节点即可
/**
* Description:建立大根堆
*/
void BuildMaxHeap(int *A, int n)
{
int i;
for(i = n / 2; i >= 1; i --)
{
MaxHeapIfy(A, i, n);
}
}
堆排序算法
/**
* Description:堆排序
*/
void HeapSort(int *A, int n)
{
int temp, i, j;
BuildMaxHeap(A, n);
for(i = n, j = 1; i >= 2; i --, j ++)
{
temp = A[i];
A[i] = A[1];
A[1] = temp;
MaxHeapIfy(A, 1, n - j);
}
}
排序练习
题目
题目描述:
对输入的n个数进行排序并输出。
输入:
输入的第一行包括一个整数n(1<=n<=100)。
接下来的一行包括n个整数。
输出:
可能有多组测试数据,对于每组数据,将排序后的n个整数输出,每个数后面都有一个空格。
每组测试数据的结果占一行。
样例输入:
4
1 4 3 2
样例输出:
1 2 3 4
ac代码(堆排序)
#include <stdio.h>
#include <stdlib.h>
void max_heapify(int *A, int i, int n);
void build_heap(int *A, int n);
void heap_sort(int *A, int n);
int main()
{
int i, n, A[102];
while(scanf("%d", &n) != EOF)
{
for(i = 1; i <= n; i ++)
scanf("%d", &A[i]);
heap_sort(A, n);
for(i = 1; i <= n; i ++)
{
printf("%d ", A[i]);
}
printf("\n");
}
return 0;
}
void heap_sort(int *A, int n)
{
int i, j, exchange;
build_heap(A, n);
for(i = n, j = 1; i >= 2; i --, j ++)
{
exchange = A[1];
A[1] = A[i];
A[i] = exchange;
max_heapify(A, 1, n - j);
}
}
void max_heapify(int *A, int i, int n)
{
int large, loc, left, right, temp;
for(large = i; large <= n;)
{
left = large * 2;
right = large * 2 + 1;
loc = large;
if(left <= n && A[left] > A[large])
large = left;
if(right <= n && A[right] > A[large])
large = right;
if(large != loc)
{
temp = A[large];
A[large] = A[loc];
A[loc] = temp;
}else
{
break;
}
}
}
void build_heap(int *A, int n)
{
int i;
for(i = n / 2; i >= 1; i --)
{
max_heapify(A, i, n);
}
}