堆排序详解

堆排序的实现原理是二叉树,实现堆排序可以使用大根堆,也可以使用小根堆。大根堆为根节点大于左右子节点,且左右子节点大小不用在意谁大谁小。小根堆的根节点小于左右子节点。一般升序使用大根堆,降序使用小根堆。

话不多说,直接使用案例来进行分析:

将数组arr[12,9,54,3,5,87,25,14]使用堆排序实现升序排列。

我们这里使用大根堆。解题思路为:

  1. 构建大根堆,且堆结构顶端为数组最大值。
  2. 将顶端值与数组最后一位的值进行交换,末尾的数为最大值,而此时未排序的个数为n-1。
  3. 将剩下的值再次构建大根堆,再将堆排序顶端值与n-1的值进行交换,如此反复即可。

第一个非叶子节点为n/2即节点14,将其与左右子节点进行判断,如果大于根节点,则进行交换:

图中14大于3,于是14和3进行交换:

堆排序详解_第1张图片

 第二个非叶子节点为54,左节点87大于54,于是进行交换:堆排序详解_第2张图片

 第三个非叶子节点为9,左节点14 大于9,于是进行交换:

堆排序详解_第3张图片 第四个非叶子节点12,右节点87大于12,于是进行交换:堆排序详解_第4张图片

交换后右边剩余元素可以重构大根堆,其中12小于左节点54,于是进行交换:

堆排序详解_第5张图片

由此找到了最大值且放在了堆顶端。再将顶端值与末尾交换,并再次构建大根堆。

import java.util.Scanner;

public class Main {

    static int N = 100010;
    static int h[] = new int[N];
    static int size = 0;
    
    //交换顶端和尾部位置的值
    public static void swap(int a,int b) {
        int temp = h[a];
        h[a] = h[b];
        h[b] = temp;
    }
    
    //判断左右子节点值是否大于根节点,如果大则进行交换
    public static void down(int u,int size) {
        int t = u;
        if(u * 2 <= size && h[u*2] > h[t])  t = u * 2;
        if(u * 2 + 1 <= size && h[u*2+1] > h[t])    t = u * 2 + 1;
        if(u != t) {
            swap(u,t);
            down(t,size);
        }
    }
    
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        
        for(int i = 1; i <= n; i++) {
            h[i] = sc.nextInt();
        }
        
        size = n;
        //建立大根堆
        for(int i = n/2; i >= 1; i--)   down(i,size);
        
        //排序操作
        for(int i = n; i >= 1; i--) {
            swap(i,1);
            down(1,i-1);
        }
        //输出数组
        for(int i = 1; i <= n; i++) {
            System.out.print(h[i]+" ");
        }
    }
}
    

你可能感兴趣的:(java,算法,数据结构)