算法笔记-堆排序
来源:互联网 发布:矩阵的奇异值是什么 编辑:程序博客网 时间:2024/06/06 13:03
前言:前几天在面试中被问到一个问题:如何在100个数中找出前5大的数?其实我知道这是一个很经典的算法题,我也曾在刷剑指offer编程题的时候做过这道题,当时我是用最简单的冒泡排序来做的,比如上面那个问题就可以用冒泡五次来找到前5大的数。这个解法的时间复杂度是O(n*k),其中n是数据规模,k是找出前k个大小的数。后来,我发现了一种更高效的解法-堆排序算法,维持一个k大小的最大堆,遍历后面的元素,如果比堆的最小元素还要小就忽略,否则更新最大堆。下面我就来详细讲解一下什么是堆排序。
堆
- 堆是什么?这里的堆指的是一种数据机构,它是一个近似的完全二叉树:
根据图片我们知道,它是一个完全二叉树,但是它跟二叉排序树不一样,二叉排序树是左孩子比父节点小,右节点比父节点大。而一个二叉堆的左右孩子没有固定的大小关系,但是父节点要么比孩子小,要么比孩子大。 - 由于1的性质,堆可以用数组来存储。给定一个节点的下标i,我们可以求出它的父节点、左孩子、右孩子分别为i/2(下取整)、2i、2i+1;一般来说,这三个操作都可以在c++中以宏定义或者内联的方式来实现。
- 二叉堆有两种形式:最大堆和最小堆。最大堆性质是除了根节点以外所有节点i都满足:
A[PARENT(i)] >= A[i];
最大堆用来对数据进行升序排序,最小堆为降序排序。
维护堆的性质
/**max_heapify用来维护堆的性质,中心思想是从一颗子树的根节点出发,看 是否符合堆的性质,然后逐级递减到叶子节点。 从a[i]、a[left(i)],a[right(i)]中找到一个最大的,用largest记录其下标。 如果a[i]是最大的,说明已经符合最大堆性质,程序结束; 如果最大的不是a[i],那么只能是它的孩子,交换a[i]与a[largest]的值, 使下标为i的节点和它的直接孩子都满足最大堆性质,但是,交换了以后, 以a[largest]的节点可能违反最大堆性质,因此需要递归调用max_heapify函数 **/ int max_heapify(int i){ int l = left(i); int r = right(i); int largest; if(l<heap_size && a[l]>a[i]){ largest = l; } else largest = i; if(r<heap_size && a[r]>a[largest]) largest = r; if(largest != i){ swap(a[i],a[largest]); max_heapify(largest); } }
建堆
void build_max_heap(){ /**为什么循环次数是heap_size/2?为什么i要递减?i可以从0到heap_size/2吗? 因为当i>heap_size/2时,该节点为叶节点,自然符合最大堆性质;因为递减的话, 对当前节点进行操作时能够保证以当前节点为根节点满足最大堆性质,降低操作时间 **/ for(int i=heap_size/2;i>=0;--i){ max_heapify(i); } }
堆排序算法
中心思想:因为根节点的值是最大的,所以每次交换根节点与最后一个叶子节点,使得最后一个节点值最大,然后”去掉”最后一个节点,这样最大的元素就排在数组最后面,而堆因为节点交换可能会违背堆的性质,因此需要调用一次max_heapify(logn)来维护堆的性质。堆排序算法不断重复,直到堆的大小从n-1到2。因为堆排序需要遍历每一个节点,而每一个节点时间是(logn),因此时间复杂度是O(n*logn)。
void heapSort(){ build_max_heap(); for(int i = heap_size-1;i>0;--i){ swap(a[0],a[i]); heap_size--; max_heapify(0); } }
运行结果:
0 0
- 算法笔记--堆排序
- 堆排序算法笔记
- 算法笔记-堆排序
- 算法导论笔记,堆排序
- 算法学习笔记----堆排序
- 算法笔记之堆排序
- 算法笔记之堆排序
- 算法学习笔记--堆排序
- 算法导论笔记之堆排序
- 算法导论笔记之----堆排序
- 算法导论学习笔记--2--堆排序
- 算法导论-堆排序学习笔记
- 算法学习笔记之堆排序
- 算法导论笔记(一) :堆排序
- 算法导论笔记:06堆排序
- 算法笔记005:堆排序【变治法】
- 《算法导论》第六章 堆排序 笔记
- 堆排序-《算法导论》学习笔记六
- mysql安装启动等常见问题总结
- 五、MYSQL 常用命令
- Caffe在Ubuntu 16.04的安装配置
- POJ-1163(The Triangle)动态规划基础题
- 简单进度条的实现
- 算法笔记-堆排序
- 蛇形填数 模拟
- qrcode
- OutputStream、Read、Writer类的常用方法
- MATLAB UDP-广播 简单例子
- python读取pdf文档-文件
- 笔记1
- JDBC连接mysql数据库最基本的步骤简介
- 【Leetcode】521. Longest Uncommon Subsequence I