八大基本排序--堆排序

预备知识:顺序存储的二叉树

一.顺序存储二叉树的性质

1. 第n个元素的左子节点:2*n+1

2. 第n个元素的右子节点:2*n+2

3. 第n个元素的父节点:(n-1)/2

clip_image002

二.顺序存储二叉树的遍历

clip_image004

堆排序:利用堆这种数据结构

堆分为:大顶堆、小顶堆

大顶堆:父节点永远都大于它的任何一个子节点(不论是左子节点还是右子节点)

升序排列使用:大顶堆

降序排列使用:小顶堆

把数组画成一颗完全二叉树:

clip_image006

clip_image008

已经可以把一个数组写成一个树了

假设我们可以把一个树转换成大顶堆

clip_image010

把最大的数字和最后一个数字交换

clip_image012

然后把最大的数字挪出来放到最后

clip_image014

此时堆已经不是一个大顶堆了,重新将其排列成一个大顶堆

这样可以每次都取出最大的那个堆顶元素(父节点)

如何将一个堆转化为大顶堆:从最后一个非叶子节点开始调整

【叶子节点:没有子节点的节点】

拿着这个节点跟它的子节点比较,如果不是最大的,那么就交换

clip_image016

7处理完毕后,处理8【顺序是从后往前处理下一个非叶子节点】

clip_image018

第一次将数组调整为大顶堆的结果:

clip_image020

import java.util.Arrays;

//堆排序
public class HeapSort {
    public static void main(String[] args) {
        int[] arr = {9,6,8,7,0,1,10,4,2};
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
    /**
     * 把数组调整为一个大顶堆
     * @param arr
     * @param size 第一次是把所有的数字都调整,调整后把最大的数字放到最后,
     *             第二次就不用调整那个最大的数字了
     * @param index  调整哪一个数字:从最后一个非叶子节点开始调整(最后一个节点的父节点)
     */
    public static void maxHeap(int[] arr,int size,int index) {
        //左子节点的下标
        int left = index*2+1;
        //右子节点的下标
        int right = index*2+2;
        //最大的节点的下标
        int max = index;
        
        //父节点和两个子节点分别对比,找出最大的值(子节点存在)
        if(left<size && arr[left]>arr[max]) {//坑:left<size不是left<arr.length
            max = left;                      //就是:已经排好序的堆就不要再比较了
        }
        if(right<size && arr[right]>arr[max]) {
            max = right; 
        }
        
        //如果index就是最大的那么不需要交换位置,否则交换位置
        if (max != index) {
            int temp = arr[max];
            arr[max]=arr[index];
            arr[index] = temp;
            //交换位置后可能会破坏之前排好的堆,所以之前排好的堆需要重新调整
            //max是调整之后的位置
            maxHeap(arr, size, max);
        }
    }
    
    public static void heapSort(int[] arr) {
        //1.将数组调整为大顶堆
        //想全部节点都调整,不能只调整一个
        //从最后一个非叶子节点开始调整(最后一个节点的父节点)
        int start = (arr.length-1-1)/2;
//        int start = (arr.length-1)/2;
        for(int i=start;i>=0;i--) {
            maxHeap(arr, arr.length, i);
        }
        
        //2.把数组中的第0个元素和堆中的最后一个数交换,再把前面处理为大顶堆
        for (int j = arr.length-1;j>0;j--) {
            int temp = arr[j];
            arr[j]=arr[0];
            arr[0] = temp;
            //交换顺序后,把前面处理为大顶堆
            maxHeap(arr, j, 0);
        }
    }
}
原文地址:https://www.cnblogs.com/yuange678/p/10728657.html