堆排序是由 1991 年的计算机先驱奖获得者斯坦福大学计算机科学系教授罗伯特. 弗洛伊德 (Robert W.Floyd) 和威廉姆斯 (J.Williams) 在 1964 年共同发明了的一种排序算法( Heap Sort );
堆排序是由 1991 年的计算机先驱奖获得者斯坦福大学计算机科学系教授罗伯特. 弗洛伊德 (Robert W.Floyd) 和威廉姆斯 (J.Williams) 在 1964 年共同发明了的一种排序算法( Heap Sort );
堆排序 (Heapsort) 是指利用堆积树 (堆) 这种数据结构所设计的一种排序算法, 它是选择排序的一种可以利用数组的特点快速定位指定索引的元素堆分为大根堆和小根堆, 是完全二叉树大根堆的要求是每个节点的值都不大于其父节点的值, 即 A[PARENT[i]] >= A[i]在数组的非降序排序中, 需要使用的就是大根堆, 因为根据大根堆的要求可知, 最大的值一定在堆顶
堆
基本介绍
先直观感受一下, 下面就是一个堆:
20 17 8 7 16 3
什么?? 上面不就一个数组吗?!
没错,(二叉)堆数据结构是一种数组对象
不过, 让我们用另外一种方式来看这个数组:
对于表示堆的数组 arr[0n-1], 我们以 arr[0]为根, 给定某个节点下标 i, 令其父节点和左右后代节点的下标为:parent(i)=(i-1)/2;
left(i)=2*i+1;
right(i)=2*i+2;
(具体实现时, 可用移位来实现乘以 2 和除以 2)
于是, 它可以看作一棵完全二叉树:
可是, 这也只是一棵完全二叉树, 有啥特别之处呢?
特点就是: 除根节点以外的每个节点 i, 都有 arr[ parent(i) ] >= arr[i]
堆分为最大堆和最小堆, 上面就是最大堆, 最小堆的特点则是: 除根节点以外的每个节点 i, 都有 arr[ parent(i) ] <= arr[i]
堆排序一般使用最大堆, 最大堆中的最大元素位于根节点
因为具有 n 个元素的堆是基于一颗完全二叉树的, 所以其高度为 O(log n)
算法分析
其实这种算法看起来挺复杂, 但是如果真正理解了就会感觉非常简单的;
基本思想: 把待排序的元素按照大小在二叉树位置上排列, 排序好的元素要满足: 父节点的元素要大于等于其子节点; 这个过程叫做堆化过程, 如果根节点存放的是最大的数, 则叫做大根堆; 如果是最小的数, 自然就叫做小根堆了根据这个特性(大根堆根最大, 小根堆根最小), 就可以把根节点拿出来, 然后再堆化下, 再把根节点拿出来,,,, 循环到最后一个节点, 就排序好了
基本步骤:
其实整个排序主要核心就是堆化过程, 堆化过程一般是用父节点和他的孩子节点进行比较, 取最大的孩子节点和其进行交换; 但是要注意这应该是个逆序的, 先排序好子树的顺序, 然后再一步步往上, 到排序根节点上然后又相反 (因为根节点也可能是很小的) 的, 从根节点往子树上排序最后才能把所有元素排序好;
保持堆的性质
在清楚什么是最大堆之后, 我们来谈一谈如何保持堆的性质, 也就是说, 如果堆中有节点不满足堆的性质, 我们如何进行调整
首先, 我们假定以节点 i 的左右儿子为根的两棵二叉树都是最大堆, 而以节点 i 为根的二叉树可能不是最大堆, 则调整的过程如下:
从元素 arr[i], arr[left(i)], arr[right(i)]中找出最大的元素, 将下标存在 largest 中;
如果 arr[i]是最大的, 说明以节点 i 为根的二叉树是最大堆, 无须调整, 程序结束; 否则, 交换 arr[i]和 arr[largest], 于是 arr[i], arr[left(i)], arr[right(i)]三者满足了最大堆的性质, 但是交换后, 下标为 largest 的节点存放 arr[i]的值, 以该节点为根的子树又可能违反最大堆的性质, 因此需要对该子树递归调用本调整过程
时间复杂度
来源: http://www.bubuko.com/infodetail-2488772.html