最大最小堆排序--Java实现

最小堆排序:

自底向上进行大顶堆的调整。

//用于将堆调整成大顶堆,init是为了判断当前调整是否为初始化调整。
static void smallHeapAdjust(Integer[] list,int length,boolean init) throws Exception {
    int index = (length - 1) / 2;
    int maxIndex = 0;

    //当最后一个非叶子节点为堆的根节点时,返回。
    if(index <= 0){
        return;
    }

    //用于初始化时调整且判断是否为完全二叉树
    if(list[index] != null && init){
        if(list[(index+1)*2-1] != null){
            if(list[(index+1)*2-1] > list[index]){
                int temp = list[index];
                list[index] = list[(index+1)*2-1];
                list[(index+1)*2-1] = temp;
            }
        }
        else{
            if(list[(index+1)*2] != null){
                throw new Exception("非完全二叉树");
            }
        }
    }

    maxIndex = list[index*2-1] > list[index*2] ? index*2-1 : index*2;

    if(list[maxIndex] > list[index-1]){
        int temp = list[maxIndex];
        list[maxIndex] = list[index-1];
        list[index-1] = temp;
    }

    smallHeapAdjust(list,length - 2,init);

}

  

判断当前大顶堆是否符合规则

//用于判断当前堆是否为大顶堆,init用于初始化判断
public static boolean checkSmallHeap(Integer[] list,int length,boolean init) throws Exception {
    for(int i = 1;i <= (length - 1) / 2;i++){
        if(list[i-1] < list[(i * 2 - 1)] || list[i-1] < list[i*2]){
            return false;
        }

        if(i == (length - 1) / 2){
            if(list[i+1] != null && init){
                if(list[(i+1)*2-1] != null){
                    if(list[(i+1)*2-1] > list[i+1]){
                        return false;
                    }
                }
                else{
                    if(list[(i+1)*2] != null){
                        throw new Exception("非完全二叉树");
                    }
                }
            }
        }
    }
    return true;
}

  

先对无序堆进行初始化,再将堆顶元素与无序区的最后一个元素进行交换,再重新调整。

//最小堆排序
public static void smallestHeapSort(Integer[] list) throws Exception {
  //初始化大顶堆
    while (!checkSmallHeap(list,list.length,true)){
        smallHeapAdjust(list,list.length,true);
    }

    //将调整完成的大顶堆的根节点与无序区的最后一个节点进行交换,交换完成之后,最后一个节点就被归为有序区
    for(int i = list.length;i >= 1;i--){
        int temp = list[0];
        list[0] = list[i-1];
        list[i-1] = temp;

        //每次交换完之后需要对无序区的堆进行调整
        while (!checkSmallHeap(list,i-1,false)){
            smallHeapAdjust(list,i-1,false);
        }
    }
}

  

首先根据该数组元素构建一个完全二叉树,得到

 

 

 

 

 然后需要构造初始堆,则从最后一个非叶节点开始调整,调整过程如下:

20和16交换后导致16不满足堆的性质,因此需重新调整

这样就得到了初始堆。

即每次调整都是从父节点、左孩子节点、右孩子节点三者中选择最大者跟父节点进行交换(交换之后可能造成被交换的孩子节点不满足堆的性质,因此每次交换之后要重新对被交换的孩子节点进行调整)。有了初始堆之后就可以进行排序了。

此时3位于堆顶不满堆的性质,则需调整继续调整

 

 

 

 

 

 

 这样整个区间便已经有序了。

 

最大堆排序:

将调整判断大顶堆改为调整判断小顶堆

 

引自:(8条消息) 堆排序原理及算法实现(最大堆):自己总结_Smart_xzy的博客-CSDN博客

posted @ 2021-06-09 16:14  一穷三白  阅读(379)  评论(0)    收藏  举报