八大基本排序---堆排序堆结构

Posted yuange678

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了八大基本排序---堆排序堆结构相关的知识,希望对你有一定的参考价值。

堆排序很重要,但是更重要的是堆这个结构

堆结构:实际上是一棵完全二叉树

技术图片

一个数组可以根据父结点、左子结点、右子结点的关系,脑补出一棵完全二叉树

 

算法1:一个数组变为大顶堆 heapInsert()

数组:2、1、3、6、0、4

(1)只有2的时候

技术图片

(2) 2、1【认为完全二叉树的范围是0~1的,超过1就越界】

技术图片

(3)2、1、3

技术图片

3(下标2)找到自己的父结点:(2-1)/2=0

此时不满足大顶堆了,将2跟3交换

技术图片

(4)2、1、3、6

技术图片

6(下标3)找到它的父结点:(3-1)/2=1,发现6>1,将3位置上的数和1位置上的数交换

技术图片

然后继续比较6所在的位置和它的父结点的大小

技术图片

(5) 再看4位置:2、1、3、6、0

技术图片

4位置的父结点是(4-1)/2=1,0(4位置)<3(1位置),继续往下

(6)再看5位置:2、1、3、6、0、4

技术图片

这样每一步都会形成一个0~i的大顶堆,遍历完整个数组就形成了0~N-1的大顶堆

//一个数据插入已经是一个大顶堆的数组中,并且调整为新的大顶堆
    public static void heapInsert(int[] arr,int index) {
        while (arr[index]>arr[(index-1)/2]) {
            swap(arr, index, (index-1)/2);
            index = (index-1)/2;
        }
    }

    public static void main(String[] args) {
        int[] arr = {5,8,9,1,2} ;
        System.out.println(Arrays.toString(arr));
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        System.out.println(Arrays.toString(arr));
        
    }

二叉树如果结点个数为N,树的高度logN,所以每加入一个结点、调整形成一个大顶堆的时间复杂度O(logN)【只需要比较自己的那个分支】

技术图片

那么一个数组中一共N个结点,一个一个加入并且形成大顶堆的时间复杂度如下:

技术图片

 

算法2:已经形成的大顶堆里有一个数字突然变小了,重新调整这个数组形成大顶堆 heapify()

技术图片

6变为1了

找到这个结点的左子结点、右子结点

左右两个结点之间先PK一下找到最大值

看左右两个结点之间的最大值比不比1大

技术图片

1和5交换

技术图片

再找1位置的左右孩子,找到一个最大值;如果没有左右孩子那就停住

技术图片

 

//已经形成的大顶堆里,某一个数字(index位置的值)突然变小了,重新调整为一个大顶堆
    public static void heapify(int[] arr,int index, int heapSize){
        int left = 2*index+1;
        int largest;
        //如果当前结点的左子结点越界了,证明当前结点已经是叶结点了
        while (left<heapSize) {
            //找出左右孩子中的最大值的下标---largest
            //如果右子结点存在,那么取左右结点中的最大值;
            //如果右子结点不存在,那么取左结点就是唯一的最大值
            if (left+1<heapSize && arr[left]<arr[left+1]) {
                largest = left+1;
            }else {
                largest = left;
            }
            //父结点大于等于左右子结点中的最大值,不用动  
            if (arr[index]>=arr[largest]) {
                break;
            }else {
                swap(arr, largest, index);
                index = largest;
                left = 2*index+1;
            }
        }
    }

堆排序:

(1)先把数组调整为大顶堆

技术图片 技术图片

(2)把堆顶元素和最后一个位置的元素做交换

技术图片 技术图片

这事最大的数字换到了最后,然后让堆的大小-1(heapSize--),6就相当于永远不动了

技术图片

然后从0位置开始做heapify()的调整;重新调整为大根堆

技术图片-----------------à技术图片

然后再把这个堆顶元素与堆中最后一个元素交换

import java.util.Arrays;

public class HeapSort {

    public static void main(String[] args) {
        int[] arr = {5,8,9,1,2} ;
        System.out.println(Arrays.toString(arr));
        heapSort(arr);
        System.out.println(Arrays.toString(arr));
        
    }
    
    public static void heapSort(int[] arr) {
        //1.形成大顶堆
        for (int i=0; i<arr.length; i++) {
            heapInsert(arr, i);
        }
        //2.堆顶元素跟最后一个数据交换位置,堆的大小-1
        int heapSize = arr.length;
        while (heapSize>0) {
            //恢复成大顶堆
            swap(arr, 0, --heapSize);
            heapify(arr, 0, heapSize);
        }
    }

    //之前已经是一个大顶堆了,将arr[index]加入后,调整为新的大顶堆
    public static void heapInsert(int[] arr,int index){
        //找到父结点,与父结点的值比较
        while (arr[index] > arr[(index-1)/2]) {
            swap(arr, (index-1)/2, index);
            index = (index-1)/2;
        }
    }
    
    //已经形成的大顶堆里,某一个数字(index位置的值)突然变小了,重新调整为一个大顶堆
    public static void heapify(int[] arr,int index, int heapSize){
        int left = 2*index+1;
        int largest;
        //如果当前结点的左子结点越界了,证明当前结点已经是叶结点了
        while (left<heapSize) {
            //找出左右孩子中的最大值的下标---largest
            //如果右子结点存在,那么取左右结点中的最大值;如果右子结点不存在,那么取左结点就是唯一的最大值
            if (left+1<heapSize && arr[left]<arr[left+1]) {
                largest = left+1;
            }else {
                largest = left;
            }
            //父结点大于等于左右子结点中的最大值,不用动  
            if (arr[index]>=arr[largest]) {
                break;
            }else {
                swap(arr, largest, index);
                index = largest;
                left = 2*index+1;
            }
        }
    }
    
    public static void swap(int[] arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

以上是关于八大基本排序---堆排序堆结构的主要内容,如果未能解决你的问题,请参考以下文章

数据结构c语言版八大算法(上)图文详解带你快速掌握——希尔排序,堆排序,插入排序,选择排序,冒泡排序!

八大排序算法——堆排序(动图演示 思路分析 实例代码java 复杂度分析)

Java八大基本排序之堆排序

八大内部排序算法之希尔堆排序插入排序算法

八大排序之堆排序

八大排序算法之四选择排序—堆排序(Heap Sort)