奇妙能力倩

最怕你一生碌碌无为 还安慰自己平凡可贵

堆排序(●'◡'●)

前言

菜鸟漫漫成长路——堆排序。

  • 满二叉树:所有节点的孩子都是全的,即最后一层都是叶节点。
  • 完全二叉树:叶节点只可以出现在最下层和次下层,且最下层的叶节点依次在左边。

首先,我们了解一下怎么用一个数组来表示一个完全二叉树。
这里写图片描述
上面七个小格子代表的是一个长度为7的数组,如果将它写成二叉树的形式就是图上所示。可是我们要怎么建立起关系来呢?其实通过数组的下标就能非常简单的实现。当当前节点为i的时候,则它的左孩子的下标为i*2+1,右孩子为i*2+2,父节点为(i-1)/2。比如说,3的左孩子为4右孩子为5,3的数组下标为0,则4的下标为0*2+1=1,5的下标为0*2+2。

堆就是一种特殊的完全二叉树。它又分为大根堆和小根堆。大根堆就是父节点的数比左孩子以及右孩子都大。小根堆就是父节点的数比左孩子以及右孩子都小。

构建大根堆(加一个新节点到堆里,并向上调整)

了解了大根堆以及对应下标的关系之后,我们要建立大根堆就很简单啦。

这里写图片描述

  1. 首先,我们假设这个堆的大小为1,则,当前构建的大根堆只有③一个节点。如图a。
  2. 接着我们将堆的大小扩为2,将④这个节点加入。加入后我们进行比较,发现比它的父节点③要大,所以,我们将数组0和1的位置交换。如图b。
  3. 接着再将堆的大小扩为3,将⑤这个节点加入。加入后我们进行比较,发现比它的父节点④要大,所以,我们将数组0和2的位置交换。如图c。
  4. 继续将堆的大小+1,扩为4。将⑥这个节点加入。加入后我们进行比较,发现比它的父节点③要大,继续比较发现交换后,⑥仍然比父节点⑤要大,继续交换。如图d所示。

Code

    public static void heapInsert(int[]a,int index){
        while(a[index]>a[(index-1)/2]){
            swap(a,index,(index-1)/2);//交换两个数
            index = (index-1)/2;
        }
    }

调整大根堆

当大根堆某个值变小了,我们要怎么把它调整回一个大根堆呢?其实也很简单。找到这个节点的左孩子和右孩子,并和这个孩子的最大值交换。依次向下进行对比,直到到达叶节点,或者比它的左右孩子都大即可停止。

Code

    public static void heapify(int[]a,int index,int size){
        int left = index*2+1;
        while(left < size ){
            int largest = left+1 < size && a[left] < a[left+1] ? left+1:left;
            largest = a[largest]>a[index]? largest:left;
            if (largest == index){
                break;
            }
            swap(a,largest,index);
            index = largest;
            left = index*2+1;
        }
    }

堆排序

其实堆排序就是根据上面两种方法来进行合作。假设我们的数组长度为4。首先我们构建好了一个大根堆后,大根堆的第一个节点就是我们整个数组最大的数。接下来我们将第一个节点和我们最后的一个节点交换,交换后,我们将大根堆的size-1=3。那么此时我们假设数组下标为0,1,2的三个数为大根堆,是不是就相当于我们调整大根堆的操作。调整好后,最大的数又到了堆顶,我们再将他与末尾交换,再将size-1。。。。。。依次下去,到最后大根堆的size为0后数组就从小到大排序好啦。

Code

    public static void heapSort(int[]a){
        if (a == null || a.length<2){
            return;
        }
        for (int i = 0;i <a.length;i++){
            heapInsert(a,i);
        }
        int size = a.length;
        swap(a,0,--size);
        while(size > 0){
            heapify(a,0,size);
            swap(a,0,--size);
        }

完整代码

public class HeapSort {
    public static void heapSort(int[]a){
        if (a == null || a.length<2){
            return;
        }
        for (int i = 0;i <a.length;i++){
            heapInsert(a,i);
        }
        int size = a.length;
        swap(a,0,--size);
        while(size > 0){
            heapify(a,0,size);
            swap(a,0,--size);
        }
    }
    public static void heapInsert(int[]a,int index){
        while(a[index]>a[(index-1)/2]){
            swap(a,index,(index-1)/2);//交换两个数
            index = (index-1)/2;
        }
    }
    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public static void heapify(int[]a,int index,int size){
        int left = index*2+1;
        while(left < size ){
            int largest = left+1 < size && a[left] < a[left+1] ? left+1:left;
            largest = a[largest]>a[index]? largest:left;
            if (largest == index){
                break;
            }
            swap(a,largest,index);
            index = largest;
            left = index*2+1;
        }
    }
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

堆排序(●'◡'●)

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭