堆排序

堆和堆排序:为什么说堆排序没有快速排序快

帅比萌擦擦* 提交于 2019-12-17 00:06:18
“堆(Heap)” 是一种特殊的数。堆这种数据结构的应用场景非常多,最经典的莫过于堆排序了。堆排序是一种原地的、时间复杂度为 O(nlogn) 的排序算法。 快速排序,平均情况下,它的时间复杂度为 O(nlogn)。尽管这两种排序算法的时间复杂度都是 O(nlogn),甚至堆排序比快速排序的时间复杂度还要稳定, 但是,在实际的软件开发中,快速排序的性能要比堆排序好,这是为什么呢? 如何理解“堆”? 前面我们提到,堆是一种特殊的树。我们现在就来看看,什么样的树才是堆。我罗列了两点要求,只要满足这两点,它就是一个堆。 堆是一个完全二叉树; 堆中的每一个节点都大于等于(或者小于等于)其子树中每个节点的值 我分别解释一下这两点。 第一点,堆必须是一个完全二叉树。还记得我们之前讲的完全二叉树的定义吗?完全二叉树要求,除了最后一层,其他层的节点个数都是满的,最后一层的节点都靠左排列。 第二点,堆中的每个节点的值必须大于等于(或者小于等于)其子树中每个节点的值。实际上,我们还可以换一种说法,堆中每个节点的值都大于等于(或者小于等于)其左右子节点的值。这两种表述是等价的。 对于每个节点的值都大于等于子树中每个节点值的堆,我们叫作“大顶堆”。对于每个节点的值都小于等于子树中每个节点值的堆,我们叫作“小顶堆”。 定义解释清楚了,你来看看,下面这几个二叉树是不是堆? 其中第 1 个和第 2 个是大顶堆

浅谈算法和数据结构: 五 优先级队列与堆排序

邮差的信 提交于 2019-12-16 22:29:14
在很多应用中,我们通常需要按照优先级情况对待处理对象进行处理,比如首先处理优先级最高的对象,然后处理次高的对象。最简单的一个例子就是,在手机上玩游戏的时候,如果有来电,那么系统应该优先处理打进来的电话。 在这种情况下,我们的数据结构应该提供两个最基本的操作,一个是返回最高优先级对象,一个是添加新的对象。这种数据结构就是优先级队列(Priority Queue) 。 本文首先介绍优先级队列的定义,有序和无序数组以及堆数据结构实现优先级队列,最后介绍了基于优先级队列的堆排序(Heap Sort) 一 定义 优先级队列和通常的栈和队列一样,只不过里面的每一个元素都有一个”优先级”,在处理的时候,首先处理优先级最高的。如果两个元素具有相同的优先级,则按照他们插入到队列中的先后顺序处理。 优先级队列可以通过链表,数组,堆或者其他数据结构实现。 二 实现 数组 最简单的优先级队列可以通过有序或者无序数组来实现,当要获取最大值的时候,对数组进行查找返回即可。代码实现起来也比较简单,这里就不列出来了。 如上图: · 如果使用无序数组,那么每一次插入的时候,直接在数组末尾插入即可,时间复杂度为O(1),但是如果要获取最大值,或者最小值返回的话,则需要进行查找,这时时间复杂度为O(n)。 · 如果使用有序数组,那么每一次插入的时候,通过插入排序将元素放到正确的位置,时间复杂度为O(n)

PriorityQueue 的出队操作

落爺英雄遲暮 提交于 2019-12-14 21:54:10
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 在微博上看了篇文章,“ 关于PriorityQueue 二叉堆的问题 “,然后顺便看了一下 PriorityQueue 的源代码和堆排序。PriorityQueue 在出队时,会将位于数组中第一位的元素,同时也是最小的那个元素返回。之后会将数组中最后一个元素放入数组的第一位,然后进行堆调整。 可见,PriorityQueue 并不是维护一个有序的数组,而是只保证二叉堆的根节点是最小的元素。每一次出队操作都会进行堆调整,但每一次堆调整的时间复杂度都是 O(logn),所以在数据量比较大的时候还是一个不错的选择。 PriorityQueue 的堆排序相关的方法主要有两个:siftUp 和 siftDown。前者是 add、offer 等操作使用,后者是 poll 等操作使用。 来源: oschina 链接: https://my.oschina.net/u/1158769/blog/135138

排序算法:插入排序、希尔排序、冒泡、快速排序、选择排序、堆排序以及归并和基数排序

风流意气都作罢 提交于 2019-12-13 18:31:47
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 由于博客迁移至 www.coderyi.com ,文章请看 http://www.coderyi.com/archives/412 排序分为内部排序和外部排序,内部排序指待排序的记录在内存中,外部排序的记录数量很大,以至于内存放不下而放在外存中,排序过程需要访问外存。这里仅介绍内部排序,包括插入排序、交换排序、选择排序、归并排序、基数排序。 1 插入排序 1.1直接插入(straight insertion sort) 算法思路:数组{k1,k2,……,kn},排序一开始k1是一个有序序列,让k2插入得到一个表长为2的有序序列,依此类推,最后让kn插入上述表长为n-1的有序序列,得到表长为n的有序序列。 c实现的代码: // 从小到大排序 int a[]={98,97,34,345,33}; int k=sizeof(a)/sizeof(a[0]); int j; for (int i=1; i<k; i++) { int temp=a[i]; for (j=i-1; j>=0&&a[j]>temp; j--) { a[j+1]=a[j]; } a[j+1]=temp; } 1.2折半插入(binary insertion sort) 算法思路:当直接插入进行到某一趟时,对于r[i]来讲,前面i

直接选择排序(Straight Selection Sort)

假如想象 提交于 2019-12-13 17:49:59
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 1、定义 选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。 常用的选择排序方法有直接选择排序和堆排序。 2、基本思想 n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果: ① 初始状态:无序区为R[1..n],有序区为空。 ② 第1趟排序 在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。 …… ③ 第i趟排序 第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[1..i]和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。 这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。 3、算法描述 直接选择排序的具体算法如下:   void SelectSort(SeqList R)  { int i,j,k; for(i=1;i<n;i++){//做第i趟排序(1≤i≤n

学习堆排序总结

末鹿安然 提交于 2019-12-12 14:28:19
#include <bits/stdc++.h> using namespace std; int n,r[1000]; void SIFT(int r[],int i,int m) { int j,temp; temp=r[i]; j=2*i; while(j<=m){ if((j<m)&&(r[j]<r[j+1])) j++;//判断左右子树谁大一些 if(temp<r[j]){//如果子树比根大 r[i]=r[j]; i=j,j=2*i;//状态转移到他的子树去; } else break; } r[i]=temp; } void heapsort(int r[]) { int i; int temp; for(int i=n/2;i>=1;i--)//逻辑结构{ SIFT(r,i,n);//从叶子节点开始建堆; for(i=n;i>=1;i--){ swap(r[1],r[i]);//将最大的点放到最后面; SIFT(r,1,i-1);//再次排序将最大的点放到1; } } int main() { cin>>n; for(int i=1;i<n+1;i++) cin>>r[i]; heapsort(r); for(int i=1;i<n+1;i++) cout<<r[i]<<' '; return 0; } 一切尽在注释中; 堆排快,是因为它是二叉树;

第九章:内部排序

被刻印的时光 ゝ 提交于 2019-12-10 21:59:13
排序:将一个数据元素(或记录)的任意序列,重新排列成一个按关键字有序的序列。 稳定性——若两个记录A和B的关键字值相等,且排序后A、B的先后次序保持不变,则称这种排序算法是稳定的。 1.插入排序 思想:每步将一个待排序的对象,按其关键码大小,插入到前面已经排好序的一组对象的适当位置上,直到对象全部插入为止。 简言之,边插入边排序,保证子序列中随时都是排好序的。 1) 直接插入排序 在已形成的有序表中线性查找,并在适当位置插入,把原来位置上的元素向后顺移 时间效率: 因为在最坏情况下,所有元素的比较次数总和为(0+1+…+n-1)→O(n^2)。 其他情况下也要考虑移动元素的次数。 故时间复杂度为O(n^2) 空间效率:仅占用1个缓冲单元——O(1) 算法的稳定性:稳定 直接插入排序算法的实现: void InsertSort ( SqList &L ) { //对顺序表L作直接插入排序 for ( i = 2; i <=L.length; i++) //假定第一个记录有序 { L.r[0]= L.r[i]; j=i-1 ; //先将待插入的元素放入“哨兵”位置 while(L[0] .key<L[j].key) { L.r[j+1]= L.r[j]; j-- ; } //只要子表元素比哨兵大就不断后移 L.r[j+1]= L.r[0]; //直到子表元素小于哨兵,将哨兵值送入 /

堆排序

让人想犯罪 __ 提交于 2019-12-09 21:33:55
# include <iostream> # include <stdio.h> using namespace std ; void heapify ( int tree [ ] , int n , int i ) { if ( i >= n ) { return ; } int c1 = 2 * i + 1 ; int c2 = 2 * i + 2 ; int max = i ; if ( c1 < n && tree [ c1 ] > tree [ max ] ) { max = c1 ; } if ( c2 < n && tree [ c2 ] > tree [ max ] ) { max = c2 ; } if ( max != i ) { swap ( tree [ max ] , tree [ i ] ) ; heapify ( tree , n , max ) ; } } void BuildHeap ( int tree [ ] , int n ) { int last_node = n - 1 ; int parent = ( last_node - 1 ) / 2 ; for ( int i = parent ; i >= 0 ; i -- ) { heapify ( tree , n , i ) ; } } void HeapSort ( int tree

20191209-八大排序之堆排序

大兔子大兔子 提交于 2019-12-09 21:04:51
1. 堆排序 算法核心思想 堆排序利用堆的特点, 最大堆要求节点的元素都要不小于其孩子,最小堆要求节点元素都不大于其左右孩子,那么处于最大堆的根节点的元素一定是这个堆中的最大值,每次把堆顶元素放置在二叉树的尾部,然后重新建堆这样循环处理,最终就能完成排序。 核心算法逻辑如下: 建堆 把堆顶的元素和最后一个元素交换,这样,最大的元素就排到了最后面 把堆的尺寸缩小 1,并调用 shift_down(0),目的是把新的数组顶端数据调整到相应位置 重复上面的1到3步,之后遍历完堆 在堆中,节点i的左子节点是2*i+1,右子节点是2*i+2,故最小值堆满足如下的特点: Node(i).value < Node(2*i+1).value Node(i).value < Node(2*i+2).value 代码实现 建堆,建堆的过程通过数组的给定数组的下标,建立以给定下标为根的堆,具体过程如下: def heapify(arr,root_index,arr_length): """给定数组,数组的下标,当前需要建堆的数组长度""" left_index = 2*root_index+1 right_index = 2*root_index+2 max_index = root_index #找到以arr[root_index]为根的堆的与左右子树3个节点中最大值的索引 if left_index

十大排序算法之堆排序

佐手、 提交于 2019-12-09 18:21:40
简介 堆积排序(Heapsort)是指利用堆积树(堆)这种资料结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。堆排序是不稳定的排序方法,辅助空间为O(1), 最坏时间复杂度为O(nlog2n) ,堆排序的堆序的平均性能较接近于最坏性能。 实例 Java 代码 public class Main { public static void main ( String [ ] args ) { int [ ] sort = { 3 , 2 , 1 , 4 , 6 , 5 , 8 , 9 , 10 , 7 } ; System . out . println ( "排序前:" ) ; printArray ( sort ) ; heapSort ( sort ) ; System . out . println ( "\n排序后:" ) ; printArray ( sort ) ; } public static void printArray ( int [ ] a ) { for ( int i = 0 ; i < a . length ; i ++ ) { System . out . print ( a [ i ] + " " ) ; } System . out . println ( ) ; } public static void heapSort (