堆排序

Posted redo19990701

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了堆排序相关的知识,希望对你有一定的参考价值。

堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值总是小于(或者大于)它的父节点,前者称为大顶堆,后者成为小顶堆

解析(大顶堆)

大顶堆即父结点的值总是大于孩子结点

图示(以树为魂,以数组为形)

逻辑表示(二叉树)

graph TD 1((11))==>2((7)) 1==>3((5)) 2==>4((3)) 2==>5((2)) 3==>6((4))

物理表示(数组)

arr[i] 11 7 5 3 2 4
i(下标) 0 1 2 3 4 5

不难发现一下几点

  • 下标为零的数是树根
  • 下标为n的数的左右孩子的下标分别是2n+1,2n+2
  • 下标为n的数的父结点下标是floor((n-1)/2)

步骤

graph TD 1(开始)-->2(堆化) 2-->3(固定最大值) 3-->4(下沉树根元素) 4-->3 4-->|循环数组长度次后退出|5(结束)

下沉操作

对一个结点进行下沉操作就是比较该结点是否比其左右孩子结点大,如果是就操作完成;如果否就将其和左右孩子结点中较大的一个进行交换,再对交换的孩子结点进行下沉操作

堆化

堆化就是将一个完全无序的数组使其满足堆的定义

做法是从倒数第一个非叶子结点开始到树根结点每个结点依次进行下沉操作,从而使其满足堆

固定最大值

当一个数组满足堆,其树根结点数字即为最大值,将其和未有序部分数组的末尾元素交换,将其固定到合适的位置.此时堆顶不满足父结点的值大于孩子结点的性质,需要对堆顶结点进行下沉操作

代码

public class Heapsort {
    private static void sink(Comparable[] arr,int currentIndex,int N){
        int lChildIndex,rChildIndex;
        while (true){
            lChildIndex=2*currentIndex+1;
            rChildIndex=2*currentIndex+2;
            if(lChildIndex>=N){
                //目标节点是叶子节点
                break;
            }else {
                //目标节点有孩子
                int largerIndex;//左右孩子中较大的一个
                if(rChildIndex<N) {
                    //目标节点有左右孩子
                    largerIndex = (arr[lChildIndex].compareTo(arr[rChildIndex]) == 1) ? lChildIndex : rChildIndex;
                }else {
                    //目标结点只有左孩子
                    largerIndex=lChildIndex;
                }
                if(arr[currentIndex].compareTo(arr[largerIndex])<0){
                    //目标节点小于子节点
                    swap(arr,currentIndex,largerIndex);
                    currentIndex=largerIndex;
                }else {
                    break;
                }
            }
        }
    }
    private static void swap(Comparable[] arr,int i,int j){
        //交换两个下标位置的元素
        Comparable temp=arr[i];
        arr[i]=arr[j];
        arr[j]=temp;
    }
    public static void sort(Comparable[] arr){
        int length=arr.length;
        for(int i=(length-1)/2;i>=0;i--){//堆化
            sink(arr,i,length);
        }
        for(int i=length;i>0;i--){
            swap(arr,0,i-1);//固定最大值
            sink(arr,0,i-1);//对堆顶进行下沉操作
        }
    }

    public static void main(String[] args) {
        Integer[] arr={20,30,20,20,90,40,70,110,60,10,100,50,80};
        sort(arr);
        for(int i:arr){
            System.out.print(i+",");
        }
    }
}

以上是关于堆排序的主要内容,如果未能解决你的问题,请参考以下文章

选择排序(简单选择排序堆排序的算法思想及代码实现)

排序--08---堆排序

python代码实现堆排序

算法-java代码实现堆排序

一文带你了解堆排序

堆排序