zoukankan      html  css  js  c++  java
  • (纯白话算法系列)堆排序,时间复杂度分析、代码演示,堆是什么?堆的数据结构底层

    堆排序(英语:Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

    想要了解堆排序,那么必须要明白堆这种数据结构,先介绍一下堆结构,如果已经明白了可以直接跳过。

    什么是堆

    堆是一种非常重要的数据结构,其本身是由完全二叉树构成的,二叉树想必大家都明白是什么,如果不明白请百度…堆需要分两种,一种叫大根堆,一种叫小根堆,先介绍这几个名词:

    名词介绍

    满二叉树:除了叶子节点,每个根节点都有完整的两个孩子:
    完全二叉树:除了叶子节点,其他根节点必须都是满的,叶子节点可以不满,但是必须都在左边。如图:
    满二叉树和完全二叉树的区别
    大根堆:大根堆是以完全二叉树为基础的,每个根节点一定比它的左右两个孩子的值要大,看图:
    在这里插入图片描述
    小根堆:跟大根堆相反,每个根节点一定比左右两个孩子的值要小,如图:在这里插入图片描述
    了解了这几个名词和定义之后,就可以看堆排序了!!

    堆排序怎么实现

    为什么堆排序这么重要呢??因为其复杂度是O(logN)的,要知道O(logN)比O(n²)要好太多太多了,比如要排序10亿个数据,log10亿只有28.9,而十亿的平方是多少就不用说了吧,性能差距太多了!!!所以面试堆排序必问,一定要完全地弄熟练这个排序!

    堆排序其实是一种抽象的数据结构,它存储在一维数组中,画成树的样子只是便于理解,可是树怎么能存在一位数组当中呢?

    堆有一种存放的原则,根节点的左孩子一定是(n * 2)+ 1,右孩子一定是(n * 2)+ 2,一个孩子的父节点一定是(n - 1) / 2.有一个特殊的根节点是0这个根节点,0的根节点套用公式是(0 - 1)/ 2,-1÷2其实还是0,所以大家不必担心。

    所以首先需要将数组中无序的元素变成堆的这种结构,举个栗子:
    比如1,2,3,4,5,6这六个元素已经依次排列在数组中了,这个例子是最不好的情况,也就是已经排好序的数组,看看他的时间复杂度会不会很高。
    在这里插入图片描述
    很显然如果用堆的结构排它是这样的
    在这里插入图片描述
    这很明显是一个小根堆,但是堆排序需要用大根堆,我们怎么把这个小根堆变成大根堆呢?

    首先定义一个index,这个index从第1个元素开始,因为是从第0个元素默认它已经是一个大根堆结构了,走到2这个数字,进行判断,如果这个元素大于它的根节点(怎么找到它的父节点呢?(index - 1)/2),那么就进行交换,也就是1和2交换,堆中现在是2,1,数组中是(2,1),3,4,5,6
    在这里插入图片描述
    index++,往堆中新增一个3,然后判断它跟父节点的关系,很明显3>2,所以就交换位置,堆中元素如下:数组中元素为(3,1,2),4,5,6
    在这里插入图片描述
    index++,往堆中新增一个4在这里插入图片描述
    很明显4比它的父节点1要大,那么就跟1交换位置
    在这里插入图片描述
    再进行判断,4比父节点3还要大,继续换,堆中位置如下,数组中:(4,3,2,1),5,6
    在这里插入图片描述
    同理5,6也是这样排,最后堆中位置如下:
    在这里插入图片描述
    数组中为:6,4,5,1,3,2,那么怎么进行排序呢??
    先把第0位置的元素和第5位置的元素进行交换,也就是(2,4,5,1,3),6,size = 6,size-1,也就是堆中有效位置变成了从第0位置到第4位置,6就被排除了,堆中现在是:
    在这里插入图片描述
    所以需要一步操作叫heapify,就是把不是堆的结构变成堆结构,把index变量指向2,先找他的两个孩子哪个最大,然后让index和两个孩子的最大值进行比较,如果相等,则不需要交换位置,如果index小于最大值,则和这个最大值进行交换,也就是先找2的两个孩子哪个最大,显然是5,然后2和5比较,显然5大,所以交换位置,由于交换位置后2没有子节点了,所以停止比较,堆中位置如下:
    在这里插入图片描述
    在数组中的位置:5,4,2,1,3,6,虽然6还在,可是在堆的范围内它已经被排除在外了,所以是一个越界的元素,取到它也没用,实际上堆中的元素是5,4,2,1,3,然后还是弹出第0个元素,和–size进行交换,也就是5和3交换,变成(3,4,2,1),5,6,堆中元素只剩下了3,4,2,1,再执行heapify方法,把其变成大根堆结构,也就是3和两个孩子节点中较大的那个元素比较,如果根节点小于孩子节点较大的那个元素,则和较大的元素进行交换,也就是3和4进行交换,堆变成了4,3,2,1,再执行交换,4,1交换,数组中变成(1,3,2),4,5,6,堆中元素只有1,3,2,1小于3,所以变成3,1,2,再执行交换,2,1,数组中元素变成(2,1),3,4,5,6,然后堆中元素只剩下2,1了,所以2>1,然后进行交换,变成1,2,3,4,5,6,排序到此也就结束了。

    看一下代码实现:

    package com.bean.com.bean.sortAlg;
    
    import java.util.Arrays;
    
    public class HeapSort {
        public static void HeapSort(int[] arr) {
            if(arr == null || arr.length < 2) {
                return;
            }
            for(int i = 0; i < arr.length; i++) {
                HeapInsert(arr, i);//把数组变成堆结构
            }
            int size = arr.length;
            swap(arr, 0, --size);0位置元素和第--size元素进行交换
            while(size > 0) {//只要堆空间还有元素
                heapify(arr, 0, size);//把堆空间heap化
                swap(arr, 0, --size);//再交换第0个元素和堆空间的最后一个元素
            }
        }
    
        //把index之前的元素全部变成大根堆
        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;
            }
        }
    
        //从index到size变成大根堆
        public static void heapify(int[] arr, int index, int size) {
            int left = index*2 + 1;//左孩子
            while(left < size) {
                int largest = arr[left + 1] > arr[left] && left + 1 < size ? left + 1 : left;
                largest = arr[largest] > arr[index] ? largest : index;
                if(largest == index) break;
                swap(arr, largest, index);
                index = largest;
                left = index * 2 + 1;
            }
        }
    
        public static void swap(int[] arr, int left, int right) {
            int temp = arr[left];
            arr[left] = arr[right];
            arr[right] = temp;
        }
    
        public static int[] generateRandomArray(int maxSize, int maxNum) {
            if(maxSize == 0) {
                return null;
            }
            int[] randomArray = new int[(int) (Math.random() * (maxSize+1) )];
            for(int i = 0; i < randomArray.length; i++) {
                randomArray[i] = (int)(Math.random() * (maxNum+1) - (int)(Math.random() * (maxNum)));
            }
            return randomArray;
        }
    
        public static int[] arrayCopy(int[] arr) {
            if(arr == null) {
                return null;
            }
            int[] copyArray = new int[arr.length];
            for(int i = 0; i < arr.length; i++){
                copyArray[i] = arr[i];
            }
            return copyArray;
        }
    
        public static void printArray(int[] arr) {
            if(arr == null) {
                return;
            }
            for(int i = 0; i < arr.length; i++) {
                System.out.print(arr[i]+" ");
            }
            System.out.println();
        }
    
        public static void ArrSort(int[] arr) {
            Arrays.sort(arr);
        }
    
        public static boolean isEqual(int[] arr1, int[] arr2) {
            if(arr1 == null && arr2 != null || arr1 != null && arr2 == null) {
                return false;
            }else if(arr1 == null || arr2 == null) {
                return true;
            }else if(arr1.length != arr2.length) {
                return false;
            }
            for(int i = 0; i < arr1.length; i++) {
                if(arr1[i] != arr2[i])
                    return false;
            }
            return true;
        }
    
        public static void main(String[] args) {
            int maxSize = 20;
            int maxNum = 50;
            int testTimes = 50000;
            boolean flag = true;
            for(int i = 0; i < testTimes; i++) {
                int[] arr1 = generateRandomArray(maxSize, maxNum);
                int[] arr2 = arrayCopy(arr1);
                ArrSort(arr1);
                HeapSort(arr2);
                flag = isEqual(arr1, arr2);
                if (!flag) {
                    break;
                }
            }
            System.out.println(flag ? "Congraduation! Everything is ok!" : "Damn.. the wrong " +
                    "method has been found..");
            int[] arr1 = generateRandomArray(maxSize, maxNum);
            printArray(arr1);
            HeapSort(arr1);
            printArray(arr1);
        }
    }
    
    
  • 相关阅读:
    04 SecurityContextHolder与SecurityContext说明
    03 spring security执行流程分析
    02 spring security 自定义用户认证流程
    01 spring security入门篇
    第三周进度
    第二周进度
    一维整数组所有子数组和的最大值
    初入园子,自我介绍
    密码登录源码(jsp+java+数据库)
    第一周总结
  • 原文地址:https://www.cnblogs.com/taobean/p/12364265.html
Copyright © 2011-2022 走看看