《算法导论》读书笔记--堆排序
2016-01-08 16:35
176 查看
预备知识:
堆通常被看做一个近似完全的二叉树,使用数组A[1...N]表示堆,数组中一个元素代表堆上一个结点,堆存在以下性质:
根节点:A[1]
父结点:Parent[i] = i/2
左子节点:Left[i] = 2i
右子节点:Right[i] = 2i + 1
数组长度为:A.length
数组中有效数据长度为:A.heap-size
堆分为最大堆和最小堆,在最大堆中 Parent[i] >= A[i],在最小堆中 Parent[i] <= A[i]
维护堆的性质(MAX-HEAPIFY):调节父结点与子结点位置,使他们满足最大堆的大小关系。将A[i]的值在最大堆中“逐级下降”,从而使以下标i为根结点的子树重新遵循最大堆的性质。
时间复杂度为:T(n) <= T(2/3n)+O(1) 根据主定理公式可以计算出 时间复杂度为O(lgn)
建堆(BUILD-MAX-HEAP):将无序的数组转换为最大堆。
堆排序算法(HEAPSORT):因为建堆后,数组中的数据并不是有序的,但最大值一定位于根结点A[1],根据此性质,可以进行排序
Demo:
堆通常被看做一个近似完全的二叉树,使用数组A[1...N]表示堆,数组中一个元素代表堆上一个结点,堆存在以下性质:
根节点:A[1]
父结点:Parent[i] = i/2
左子节点:Left[i] = 2i
右子节点:Right[i] = 2i + 1
数组长度为:A.length
数组中有效数据长度为:A.heap-size
堆分为最大堆和最小堆,在最大堆中 Parent[i] >= A[i],在最小堆中 Parent[i] <= A[i]
维护堆的性质(MAX-HEAPIFY):调节父结点与子结点位置,使他们满足最大堆的大小关系。将A[i]的值在最大堆中“逐级下降”,从而使以下标i为根结点的子树重新遵循最大堆的性质。
MAX-HEAPIFY(A,i) l = Left[i] r = Right[i] if l <= A.heap-size and A[l] > A[i] lagest = l else lagest = i if r <= A.heap-size and A[r] > A[lagest] lagest = r if i != lagest //当根结点不是最大值时 exchage A[i] with A[lagest] MAX-HEAPIFY(A,lagest)//交换位置后,以该结点为根的子树可能违法最大堆的性质,所以需要递归调用
时间复杂度为:T(n) <= T(2/3n)+O(1) 根据主定理公式可以计算出 时间复杂度为O(lgn)
建堆(BUILD-MAX-HEAP):将无序的数组转换为最大堆。
BUILD-MAX-HEAP(A) A.heap-size = A.length for i = [A.heap-size/2] downto 1 //此处i的值为A.heap-size/2向下取整的值,因为A[A.heap/2+1...A.heap-size]为叶子结点,没有子结点,所以只需考虑前半部分的值 MAX-HEAPIFY(A,i)时间复杂度为 O(n)
堆排序算法(HEAPSORT):因为建堆后,数组中的数据并不是有序的,但最大值一定位于根结点A[1],根据此性质,可以进行排序
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 //有效长度减1,表示该元素已经归位 MAX-HEAPIFY(A,1) //因为将原堆末尾元素提到了根结点,所以需要对根结点重新执行MAX-HEAPIFY维护堆的性质。时间复杂度为O(nlogn)
Demo:
#include <iostream> #include <stdio.h> using namespace std; #define LENGTH 10 int heap_size = 0; void swap(int *a,int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } void max_headpify(int *A,int i)//维护堆的性质,下沉元素 { int lagest; int l = i*2; int r = i*2+1; if((l <= heap_size) && (A[l] > A[i])) lagest = l; else lagest = i; if((r <= heap_size) && (A[r] > A[lagest])) lagest = r; if(lagest != i) { swap(&A[i],&A[lagest]); max_headpify(A,lagest); } } void build_max_heap(int *A)//构建堆 { heap_size = LENGTH; for(int i = LENGTH/2;i >= 1;i--) max_headpify(A,i); } void heapsort(int *A)//堆排序 { build_max_heap(A); for(int i = LENGTH;i >= 2;i--) { swap(&A[1],&A[i]); heap_size--; max_headpify(A,1); } } int main() { int A[LENGTH+1]; for(int i = 1;i <= LENGTH;i++) { cin>>A[i]; } heapsort(A); for(int i = 1;i <= LENGTH;i++) { printf("%d\n",A[i]); } system("pause"); return 0; }
相关文章推荐
- loadrunner之C语言编程
- iOS - 线程管理
- [转] Java序列化与反序列化
- 使用@media做自适应
- js调用Android、ios原生代码
- oc断点动态命令
- 模拟器网络请求报 1005
- 安卓开发中非常炫的效果集合
- 3D 深度摄像头开发
- mysql 日期函数
- Linux raw socket
- 想起来好久没更新博客了
- 树的创建与遍历
- android textview 首行缩进 多行显示
- Gulp安装及配合组件构建前端开发一体化(转)
- 自定义seekBar(一)
- Java代碼加密
- Winform 嵌入Word Excel Powerpoint
- 探索Windows Azure 监控和自动伸缩系列2 - 获取虚拟机的监控定义和监控数据
- 使用PuTTY连接树莓派