文章目录

  • 堆排序原理
  • Java实现堆排序


堆排序原理

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的平均时间复杂度均为O(nlogn)

堆排序的基本思路是:

  1. 将待排序的序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。
  2. 将根节点与末尾元素进行交换,此时末尾就为最大值。
  3. 然后将剩余N-1个元素重新构成一个堆,这样根节点就是这n个元素的次大值。
  4. 将根节点与倒数第二个元素交换。
  5. 如此反复执行,最后得到一个从小到大的序列。

java堆数据结构的使用 java中的堆数据结构_数组


简化的思路:

  1. 将无序数组构建成一个堆,根据升序降序需求选择大顶堆或小顶堆;
  2. 将堆顶元素与末尾元素交换,将最大元素“沉”到数组末端;
  3. .其余元素重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素;
  4. 反复执行调整+交换步骤,直到整个序列有序。

以下面的数组排序为例:

首先构造初始堆

java堆数据结构的使用 java中的堆数据结构_堆排序_02


从最后一个非叶子几点开始(叶子节点自然不用调整,最后一个非叶子节点索引为arr.length/2-1),从右至左,从下至上进行向下调整,使其满足堆的定义。

java堆数据结构的使用 java中的堆数据结构_子节点_03

java堆数据结构的使用 java中的堆数据结构_堆排序_04


步骤二:将堆顶元素与末尾元素进行交换,使末尾元素最大。

java堆数据结构的使用 java中的堆数据结构_java堆数据结构的使用_05


其余元素恢复大顶堆

java堆数据结构的使用 java中的堆数据结构_java堆数据结构的使用_06

再把堆顶元素下移至倒数第二个位置

java堆数据结构的使用 java中的堆数据结构_java堆数据结构的使用_07


如此反复进行,最终使得整个序列有序

java堆数据结构的使用 java中的堆数据结构_子节点_08

Java实现堆排序

package heap;

import java.util.Arrays;

public class HeapSort {
    /**
     * 测试方法
     */
    public static void main(String[] args) {
        int[] arr = {1,4,2,6,3,44,62,31,8,7,5};
        sort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 堆排序的实现方法
     */
    public static void sort(int[] arr){
        //首先把arr调整为一个合法的堆
        for (int i= arr.length/2-1;i>=0;i--){
            //从最后一个非叶子节点开始调整,直到根节点
            //具体的调整封装为一个方法
            adjustHeap(arr,i,arr.length);
        }

        //
        for (int j=arr.length-1;j>0;j--){
            //交换堆顶元素和堆尾元素的位置
            swap(arr,0,j);
            //把除了我们刻意后置的元素外的剩余元素,调整为合法的堆
            adjustHeap(arr,0,j);//由于我们只移动了第一个元素,所以只需要调整第一个元素
        }
    }

    /**
     * 调整的方法
     * @param arr 数组
     * @param i 调整元素的索引
     * @param length 调整数组的前length个元素
     */
    public static void adjustHeap(int[] arr, int i, int length){
        int temp = arr[i];
        for (int k=i*2+1;k<length;k=k*2+1){
            if (k+1<length && arr[k]<arr[k+1]){
                //存在右子节点
                k++; //让k指向两个子节点中大的那个
            }
            if (temp>=arr[k]){
                //父节点大于子节点中最大的那个值
                break;
            }else {
                //调整
                arr[i] = arr[k];
                i=k;
            }
        }
        //现在i的位置就是被调整的节点应该放的正确位置
        arr[i] = temp;
    }

    /**
     * 交换a,b两个元素的方法
     * @param arr 数组
     * @param a 元素a的索引
     * @param b 元素b的索引
     */
    public static void swap(int[] arr, int a, int b){
        int temp = arr[a];
        arr[a] = arr[b];
        arr[b] = temp;
    }
}