堆排序
堆排序概述
堆排序定义
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); } }