排序篇(5)--堆排序
2017-03-03 14:40
183 查看
首先明确堆的性质:
堆是具有下列性质的完全二叉树,每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆。
主要是解决两个问题:
(1)如何由一个无序序列构建成一个堆?
(2)如果在输出堆顶元素后,调整剩余元素成为一个新的堆?
运行结果如下:
堆排序的时间复杂度为O(nlogn),由于堆排序堆原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(nlogn),这在性能上显然优于之前所介绍的排序算法。由于记录的比较与交换是跳跃式进行,因此堆排序也是一种不稳定的排序算法。
同时,由于初始构建堆所需的比较次数较多,因此,它并不适合排序序列个数较少的情况。
文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此谢过…
堆是具有下列性质的完全二叉树,每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆。
一、堆排序算法
基本思想:以大顶堆为例,将待排序的序列构造成一个大顶堆。此时,整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就能得到n个元素中的次大值。如此反复执行,便能得到一个有序序列了。主要是解决两个问题:
(1)如何由一个无序序列构建成一个堆?
(2)如果在输出堆顶元素后,调整剩余元素成为一个新的堆?
二、堆排序算法实现
package Sort; import java.util.Arrays; /** * Created by L_kanglin on 2017/3/3. */ public class TestHeapSort { public static void main(String[] args) { int[] a={49,38,65,97,76,13,27,49,78,34,12,64}; int arrayLength=a.length; //将每一次的建推都打印出来 for(int i=0;i<arrayLength-1;i++){ //建堆 buildMaxHeap(a,arrayLength-1-i); //交换堆顶和最后一个元素 swap(a,0,arrayLength-1-i); System.out.println(Arrays.toString(a)); } } //对data数组从0到lastIndex建大顶堆 public static void buildMaxHeap(int[] data, int lastIndex){ //从lastIndex处节点(最后一个节点)的父节点开始 for(int i=(lastIndex-1)/2;i>=0;i--){ //k保存正在判断的节点 int k=i; //如果当前k节点的子节点存在 while(k*2+1<=lastIndex){ //k节点的左子节点的索引 int biggerIndex=2*k+1; //如果biggerIndex小于lastIndex,即biggerIndex+1代表的k节点的右子节点存在 if(biggerIndex<lastIndex){ //若果右子节点的值较大 if(data[biggerIndex]<data[biggerIndex+1]){ //biggerIndex总是记录较大子节点的索引 biggerIndex++; } } //如果k节点的值小于其较大的子节点的值 if(data[k]<data[biggerIndex]){ //交换他们 swap(data,k,biggerIndex); //将biggerIndex赋予k,开始while循环的下一次循环,重新保证k节点的值大于其左右子节点的值 k=biggerIndex; }else{ break; } } } } //交换 private static void swap(int[] data, int i, int j) { int tmp=data[i]; data[i]=data[j]; data[j]=tmp; } }
运行结果如下:
[13, 78, 65, 49, 76, 64, 27, 49, 38, 34, 12, 97] [12, 76, 65, 49, 34, 64, 27, 49, 38, 13, 78, 97] [13, 49, 65, 49, 34, 64, 27, 12, 38, 76, 78, 97] [38, 49, 64, 49, 34, 13, 27, 12, 65, 76, 78, 97] [12, 49, 38, 49, 34, 13, 27, 64, 65, 76, 78, 97] [27, 49, 38, 12, 34, 13, 49, 64, 65, 76, 78, 97] [13, 34, 38, 12, 27, 49, 49, 64, 65, 76, 78, 97] [27, 34, 13, 12, 38, 49, 49, 64, 65, 76, 78, 97] [12, 27, 13, 34, 38, 49, 49, 64, 65, 76, 78, 97] [13, 12, 27, 34, 38, 49, 49, 64, 65, 76, 78, 97] [12, 13, 27, 34, 38, 49, 49, 64, 65, 76, 78, 97]
三、堆排序复杂度分析
堆排序的运行时间主要是消耗在初始构建和在重建堆时的反复筛选上。堆排序的时间复杂度为O(nlogn),由于堆排序堆原始记录的排序状态并不敏感,因此它无论是最好、最坏和平均时间复杂度均为O(nlogn),这在性能上显然优于之前所介绍的排序算法。由于记录的比较与交换是跳跃式进行,因此堆排序也是一种不稳定的排序算法。
同时,由于初始构建堆所需的比较次数较多,因此,它并不适合排序序列个数较少的情况。
文章只是作为自己的学习笔记,借鉴了网上的许多案例,如果觉得阔以的话,希望多交流,在此谢过…
相关文章推荐
- 排序之堆排序
- 简单选择排序与堆排序
- 简单排序Java实现(三):希尔排序,堆排序
- (排序详解之 堆排序)
- 内排序(插入排序、冒泡排序、选择排序、shell排序、快速排序、归并排序、堆排序)
- 内部排序之三:堆排序(含完整源码)
- C# 插入排序 冒泡排序 选择排序 高速排序 堆排序 归并排序 基数排序 希尔排序
- 排序——堆排序
- 【数据结构】排序番外篇 堆,堆排序与其前身选择排序
- 选择排序------堆排序
- 【数据结构与算法】内部排序之三:堆排序(含完整源码)
- 程序员必知的8大排序(①直接插入排序②希尔排序③简单选择排序④堆排序⑤冒泡排序⑥快速排序⑦归并排序⑧基数排序)
- 快排,堆排序,基数排序手写记录
- 经典排序之堆排序
- 【转】排序算法复习(Java实现)(二): 归并排序,堆排序,桶式排序,基数排序
- 一天一排序之“堆排序(heapsort)”
- 算法导论-排序(三) 堆排序
- 经典排序之堆排序
- 排序(六)-堆排序
- 可视化的排序三:选择排序和堆排序