堆排序

作者: 最困惑的时候就是能成长的时候 | 来源:发表于2019-04-01 16:28 被阅读0次

堆排序

1.前提知识

堆:(英语:heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。

  • 堆中某个节点的值总是不大于或不小于其父节点的值;

  • 堆总是一棵完全二叉树。

将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

优先队列(priority queue)

普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除。在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆数据结构来实现。

a.完全二叉树

若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。

完全二叉树是由满二叉树(一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。)而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。

(1)所有的叶结点都出现在第k层或k-l层(层次最大的两层)

(2)对任一结点,如果其右子树的最大层次为L,则其左子树的最大层次为L或L+l。

一棵二叉树至多只有最下面的两层上的结点的度数可以小于2,并且最下层上的结点都集中在该层最左边的若干位置上,则此二叉树成为完全二叉树,并且最下层上的结点都集中在该层最左边的若干位置上,而在最后一层上,右边的若干结点缺失的二叉树,则此二叉树成为完全二叉树。

b.小根堆和大根堆

假设有一棵完全二叉树,在满足作为完全二叉树的基础上,对于任意一个拥有父节点的子节点,其数值均不小于父节点的值;这样层层递推,就是根节点的值最小,这样的树,称为小根堆。

同理,又有一棵完全二叉树,对于任意一个子节点来说,均不大于其父节点的值,如此递推,就是根节点的值是最大的,这样的数,称为大根堆。

2.一些规律

最后一个非叶节点的位置为nums.length-1,所有拥有左右子节点的节点与子节点的位置关系为,假设子节点的编号为n,那么左子节点的编号为2n+1右节点的编号为2(n+1)

然后具体的做法为1.先建立大(小)顶堆,2.交换堆顶的位置和调整整个堆,每调整一次堆的长度就减少一,直到堆的大小为0或1结束

3.先实现大顶堆

public static void main(String[] args) {
        int[] array = new int[]{1,3,4,2,5};
        heapsort(array);

其结构就相当于


image.png

然后我们先实现大顶堆

  private static int[] heapsort(int[] array) {
        buildBigheap(array);
    }

从最后一个非叶节点的节点开始调整,一直调整到根节点,这样大顶堆就建立好了

private static void buildBigheap(int[] array) {
        for(int i=array.length/2-1;i>-1;i--){ //从最后一个非叶节点的节点开始调整,一直调整到根节点
            adjustheap(array,i,array.length);  
        }

然后是具体的调整过程:

private static void adjustheap(int[] array, int i,int end) {
        //如果没有左右子树或者左右子树现在已经是拍好序的顺序
        if(2*i+1 >=end){
            return;
        }else if(2*(i+1)>=end){
            if(array[2*i+1]>=array[i]){
                swap(array,2*i+1,i);
            }
        }else{
            //根已为最大
            if(array[i]>=array[2*i+1]&&array[i]>=array[2*(i+1)]){
                return;
                //左子树最大,交换后去排列左边
            }else if(array[2*i+1]>=array[i]&&array[2*i+1]>=array[2*(i+1)]){
                swap(array,2*i+1,i);
                adjustheap(array,2*i+1,end);
                //右子树最大,交换后去排列右边
            }else{
                swap(array,2*(i+1),i);
                adjustheap(array,2*(i+1),end);
            }
        }
    }

**具体就是先判断现在调整的位置,
i(位置) \begin{cases} A.如果现在所在的节点已经没有子节点,那么直接返回\\ B.如果现在只有一个左子节点,那么与根节点直接比较后返回\\ C.双子节点都在,那么就分为3种情况 \end{cases}
A状况说明(分成两种情况:1.该节点是叶节点,2,该节点往后的子节点已经被拍好序了)
B状况说明(因为当一个节点只含有左子节点可以用的时候,那么他的右节点一定是空或者已经排好序了)
C状况说明(如果根最大什么都不用做,直接返回,如果左子节点最大,那么与根交换,并对左子节点的剩余节点进行调整,同理可得右子节点)
OK
现在做完这一步我们可以看一下数组结构

image.png
image.png
这个时候的根是最大的也就是已经实现了大顶堆

4.交换堆顶元素与最后一个元素,实现排序

其实这一过程就是交换调整,每一次交换都会使堆的需排序的大小减一,那么很容易就想到当堆大小为1时,调整完毕,所以用一个for循环for i array.length ->1

 for(int i =array.length-1;i>0;i--){
            swap(array,i,0);  //交换栈顶元素与堆的最后一个数据(每次最后一个数据都会减一)
            adjustheap(array,0,i);  //调整堆为大顶堆
        }

例如第一次交换后的数据为


image.png

然后调整完的数据为:


image.png

这样做完后所有的序都已经排好了

完整代码

public static void main(String[] args) {
        int[] array = new int[]{1,3,4,2,5};
        heapsort(array);
        for(int i=0;i<array.length;i++){
            System.out.printf(array[i]+" ");
        }
    }

    private static int[] heapsort(int[] array) {
        buildBigheap(array);
        return array;
    }

    private static void buildBigheap(int[] array) {
        for(int i=array.length/2-1;i>-1;i--){
            adjustheap(array,i,array.length);
        }

        for(int i =array.length-1;i>0;i--){
            swap(array,i,0);
            adjustheap(array,0,i);
        }
    }
    private static void adjustheap(int[] array, int i,int end) {
        //如果没有左右子树或者左右子树现在已经是拍好序的顺序
        if(2*i+1 >=end){
            return;
        }else if(2*(i+1)>=end){
            if(array[2*i+1]>=array[i]){
                swap(array,2*i+1,i);
            }
        }else{
            //根已为最大
            if(array[i]>=array[2*i+1]&&array[i]>=array[2*(i+1)]){
                return;
                //左子树最大,交换后去排列左边
            }else if(array[2*i+1]>=array[i]&&array[2*i+1]>=array[2*(i+1)]){
                swap(array,2*i+1,i);
                adjustheap(array,2*i+1,end);
                //右子树最大,交换后去排列右边
            }else{
                swap(array,2*(i+1),i);
                adjustheap(array,2*(i+1),end);
            }
        }
    }

    private static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] =array[j];
        array[j] = temp;
    }

相关文章

  • 堆排序

    目录 1.堆排序介绍 2.堆排序图文说明 3.堆排序的时间复杂度和稳定性 4.堆排序实现 堆排序介绍 堆排序(He...

  • 堆排序---基础篇

    本文主要介绍堆排序的一些基本过程和分析。 大纲 堆排序简介 堆排序代码实现 1. 堆排序简介 1.1 堆排序的存储...

  • 堆和堆排序

    最小K个数 堆排序 堆排序

  • JS实现堆排序

    原理 堆排序原理 实现 说明 堆排序对大文件很有效 堆排序是不稳定排序

  • iOS算法总结-堆排序

    iOS算法总结-堆排序 iOS算法总结-堆排序

  • 堆排序

    转载:图解排序算法(三)之堆排序 预备知识 堆排序 堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选...

  • 排序

    原创 堆排序: 使用visit数组从本质出发获取大顶堆排序。

  • 堆排序

    堆排序

  • C++基础入门之模板堆排序(上):模板上的list的创造与操作

    整段源码链接C++的模板元堆排序 要点 组建数据结构list 组建对list的各种基本操作 堆排序中组建堆排序个个...

  • 3.2-选择排序-堆排序

    参考链接 选择排序:堆排序(Heap Sort) 白话经典算法系列之七 堆与堆排序 堆排序与快速排序,归并排序一样...

网友评论

      本文标题:堆排序

      本文链接:https://www.haomeiwen.com/subject/xrbvbqtx.html