基础算法-堆排序

堆:任意节点的值大于(小于)左右子节点的值,子节点也为堆。
如果对于存储在数组里的堆的话, 节点下标为 j, 它左子节点下标为 2*j+1, 右子节点下标为 2*j+2;

堆排序(升序):

调整堆:如果节点的左子节点与右子节点都已经是大根堆,调节该节点也为大根堆.

如果该节点的左右子节点的值都小于该节点,结束。(已经是大根堆)

选定一个最大的子节点 j,将当前根节点的值与最大子节点 p 的值交换,这样,a[p]>a[j],a[p]>a[j+1], 这里符合堆

但是将之前 a[p] 的值往下移动后,这个节点不一定是堆(但是它原来的左右节点已经是堆),因此继续调整 a[p] 为堆。

选择:

从 j=n*2-1 开始调整(从第二层最右边的节点开始),这样一层一层的调整,最后,最根节点的值为最大的值。

每次将最大的值与堆后面的值交换,然后减小堆的大小,重新调整最根节点为堆,重复这个步骤

public class HeapSort {

    public static void adjust(int a[],int n,int p){

        for(int j=2*p+1;j<n;j=2*p+1){
            if(j+1<n&&a[j]<a[j+1])
                j=j+1;//j 为大的子节点下标
            if(a[j]<a[p])// 如果大的子节点比父节点小,结束(父节点已经为堆)
                break;
            int t=a[p];//根节点比子节点小,交换位置,导致新的子节点不为堆,继续调整子节点
            a[p]=a[j];
            a[j]=t;
            p=j;//需要继续调整的子节点
        }
    }

    public static void adjust2(int a[],int n,int p){
        int t=a[p];//相比于上面,因为每次 t 都是保存最开始要调节的那个节点的值,只是不断往下移动位置
        //可以省略步骤
        for(int j=2*p+1;j<n;j=2*p+1){
            if(j+1<n&&a[j]<a[j+1])
                j++;
            if(a[j]<t)
                break;
            a[p]=a[j];
            p=j;
        }
        a[p]=t;
    }

    public static void heapSort(int a[],int n){

        for(int i=n/2-1;i>=0;i--)
            adjust(a,n,i);
        for(int i=n-1;i>0;i--){
            int t=a[0];
            a[0]=a[i];
            a[i]=t;
            adjust2(a,i,0);
        }
    }

    public static void main(String[]args){

        int a[]=new int[100];
        SortUtil.randomArray(a);
        SortUtil.print(a);
        heapSort(a,a.length);
        SortUtil.print(a);
    }

}

猜你喜欢

转载自blog.csdn.net/yzr1183739890/article/details/56677653