排序算法(二):堆排序-Java实现

排序算法(二):堆排序-Java实现

首先对堆排序有个整体的认识,堆排序是一个不稳定的排序算法,其平均时间复杂度为O(nlogn),空间复杂度O(1)。

那么何为堆排序呢?所谓堆排序是借助于堆的概念来完成的排序算法,其是选择排序中的一种,因此通过选择排序来理解堆排序会更加容易一些

下面我们来看一下堆的概念,其实堆又是借助于二叉树的概念来定义,对于堆分为大顶堆和小顶堆两种,下面用数学表示式来精确的描述如下:

假设我们使用array数组来存储堆,因为大顶堆表述为 array[i] >=array[2*i+1] && array[i] >= array[2*1+2] , 小顶堆表示为array[i] <=array[2*i+1] && array[i] <= array[2*1+2], 但是值的注意的是array[2*i+1] 与array[2*i+2] 之间没有大小约束关系

对于堆的基本定义我们已经很清晰了,下面我们将详细的介绍一下堆排序的思路

堆排序的整体思路如下(以大顶堆为例说明,小顶堆同理哈)

  1. 根据大定堆的概念array[0]始终是最大的,因此与array[array.length-1]进行交换,此时就形成了 array[0].... array[array.length-2] 的无序数组和 array[array.length-1] 的有序数组
  2. 在1中形成的 array[0].... array[array.length-2] 无序数组中破坏了堆的特性,因此需要一次调整,调整从array.length-1处开始
    • 首先找到array.length-1 父亲节点,如果有左右孩子,进行比较进行交换,依次循环往前进行处理

  3. 依照按照1,2步骤循环进行,直到排序完成

Java 实现代码逻辑如下:

 1 public class HeapSort {
 2 
 3     public static void main(String[] args) {
 4         int[] array = new int[]{5, 3, 6, 2, 1, 9, 4, 8, 7};
 5 
 6         HeapSort heapSort = new HeapSort();
 7         heapSort.heapSort(array);
 8 
 9         for (int i = 0; i < array.length; i++) {
10             System.out.print(array[i]+" ");
11         }
12     }
13 
14 
15     public void heapSort(int[] array) {
16 
17         for (int i = 0; i < array.length; i++) {
18             // 将array[array.length-1-i]创建为堆
19             createMaxHeap(array, array.length - 1 - i);
20             // 因为大顶堆,所以最大值始终处于array[0],
21             // 交换array[0]与array[array.length-1-i]
22             swap(array, 0, array.length - 1 - i);
23         }
24     }
25 
26     // 调整成堆
27     private void createMaxHeap(int[] array, int lastIndex) {
28         // 从当前位置的父亲节点
29         for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
30             // 记录当前的位置节点
31             int k = i;
32             // 条件成立,则说明有孩子节点,此时判断是否满足堆的特性
33             while (2 * k + 1 <= lastIndex) {
34                 // 默认左孩子为最大
35                 int biggerIndex = 2 * k + 1;
36                 // 在判断一下看是否有右孩子
37                 if (biggerIndex < lastIndex) {
38                     // 如果存在右孩子,并且右孩子大,则将默认索引加1
39                     if (array[biggerIndex] < array[biggerIndex + 1]) {
40                         biggerIndex++;
41                     }
42                 }
43 
44                 // 此时在跟父亲节点作比较
45                 if (array[k] < array[biggerIndex]) {
46                     swap(array, k, biggerIndex);
47                 } else { // 如果不小于则结束本次循环,下一个节点的比较
48                     break;
49                 }
50             }
51         }
52     }
53 
54     // 交换两个元素
55     private void swap(int[] data, int i, int j) {
56         if (i == j) {
57             return;
58         }
59         data[i] = data[i] + data[j];
60         data[j] = data[i] - data[j];
61         data[i] = data[i] - data[j];
62     }

 

 博客描述不对之处,请指正,希望给大家带来帮助,谢谢。

posted @ 2017-10-09 00:47  房杰  阅读(133)  评论(0编辑  收藏  举报