堆排序
2016-03-17 17:11
211 查看
概述
堆,可以视为一颗完全二叉树,其节点之间满足父节点不小于(不大于)两个子节点的值,这样的堆被称为大(小)根堆。用数学符号表示为:大根堆:A[parent(i)] >= A[i]
小根堆:A[parent(i)] <= A[i]
在堆排序中,需要能够快速的找到节点的父节点,及其左右孩子节点。例如数组A[0 … n],可以将下标与树的节点按照下图进行匹配。
通过上图的方式给树的节点与数组下标的建立对应关系,可以很容易的计算出节点的父节点、左孩子和右孩子节点的下标:
#define LEFT(i) (((i) << 1) + 1) #define RIGHT(i) (((i) << 1) + 2) #define PARENT(i) (((i) - 1) >> 1)
若是数组下标从1开始对应树的根节点则有:
#define LEFT(i) ((i) << 1) #define RIGHT(i) (((i) << 1) + 1) #define PARENT(i) ((i) >> 1)
堆排序的过程主要可以分为三个阶段:
建堆。建堆是利用堆化过程将一个大小为n的数组转换为最大(小)堆的过程。
堆化。堆化用于保持堆的特性,是堆排序中最为重要的过程。其思想是比较节点i和它左右孩子节点,并选择三者中最大(小)的元素。如果最大值不是节点i,则调换节点i与最大子节点的值,并递归的对子节点进行兑换过程。
排序。该操作是从堆中取出最大(小)元素,并通过堆化过程维持堆的特性。
堆排序的实现
#include <stdio.h> /**< 查找左孩子节点下标 */ #define LEFT(i) (((i) << 1) + 1) /**< 查找右孩子节点下标 */ #define RIGHT(i) (((i) << 1) + 2) /**< 查找父节点下标 */ #define PARENT(i) (((i) - 1) >> 1) /* @brief 堆化,保持堆的性质 * @param A [in] 数组地址 * @param len [in] 数组元素个数 * @param i [in] 需要堆化的元素的下标 */ static void heapify(int *A, int len, int i) { int largest; int l, r; l = LEFT(i); r = RIGHT(i); largest = i; if (l < len && A[l] > A[largest]) { largest = l; } if (r < len && A[r] > A[largest]) { largest = r; } if (largest != i) { int tmp = A[i]; A[i] = A[largest]; A[largest] = tmp; heapify(A, len, largest); /* 递归的对孩子节点进行堆化操作 */ } } /* @brief 建立堆 * @param A [in] 数组地址 * @param len [in] 数组元素个数 */ static void build_heap(int *A, int len) { int i = PARENT(len - 1); while (i >= 0) { heapify(A, len, i); i--; } } /* @brief 堆排序 * @param A [in] 待排序数组地址 * @param len [in] 待排序数组元素个数 */ void hsort(int *A, int len) { int tmp; build_heap(A, len); len--; while (len > 0) { tmp = A[0]; A[0] = A[len]; A[len] = tmp; heapify b379 (A, len, 0); len--; } } void display(int *A, int len) { int i; for (i = 0; i < len; i++) { printf("%d ", A[i]); } printf("\n"); } int main() { int A[] = {10, 32, 43, 31, 2, 45, 12, 9, 71, 41}; int len = sizeof(A) / sizeof(A[0]); display(A, len); hsort(A, len); display(A, len); return 0; }
相关文章推荐
- 【转载】App测试要点
- 深入理解JavaScript程序中内存泄漏
- 回调函数
- 二叉查找树中的删除
- vim配置
- ORA-00439 feature not enabled: Partitioning
- Linux常用命令课堂笔记
- 原型模式的简单例子
- centos重启报错Umounting file systems:umount:/opt:device is busy
- 解析命令行参数-我的一种实现方法
- 栈(顺序存储)
- java将控制台信息输出到文件
- Preprocessing data-sklearn数据预处理
- 几个简单的网络命令(ping、tennet、ssh、netstat)
- ORACLE 小时值必须介于1和12之间 解决方法
- day-3,cdpSimplePrint
- centos重启报错Umounting file systems:umount:/opt:device is busy
- GitHub上整理的一些工具
- C++ BF模式串匹配算法!
- Firebug 查看输出创建的对象,并执行相关操作。