写点什么

七日算法先导(六)——堆排序,桶排序

作者:秋名山码民
  • 2022 年 8 月 09 日
    陕西
  • 本文字数:2798 字

    阅读完需:约 9 分钟

前言所学

前面我们学习了归并,希尔俩个排序,下面由这张图来总结一下八大排序



可能有的小伙伴会说,学这些排序有什么用,平时开发也用不到,但是我的理解是这样的:


  1. 锻炼思维,排序中蕴含的思维很多,双指针,递归,分治等等

  2. 普及常识性问题

  3. 面试,区分人才

堆排序

堆的结构可以分为大根堆和小根堆,是一个完全二叉树,而堆排序是根据堆的这种数据结构设计的一种排序,下面先来看看什么是大根堆和小根堆

大顶堆,小顶堆

当所有根节点的值,都大于它子节点的值,我们称为大顶(根)堆


当所有根节点的值,都小于它子节点的值,我们称为小顶(根)堆

思路及动画演示



    代码实现

    public class HeapSort extends BaseSort {     public static void main(String[] args) {        HeapSort sort = new HeapSort();        sort.printNums();    }     @Override    protected void sort(int[] nums) {        if (nums == null || nums.length < 2) {            return;        }        heapSort(nums);    }     private void heapSort(int[] nums) {        if (nums == null || nums.length < 2) {            return;        }        //构建大根堆        createTopHeap(nums);        int size = nums.length;        while (size > 1) {            //大根堆的交换头尾值,固定最大值在末尾            swap(nums, 0, size - 1);            //末尾的索引值往左减1            size--;            //重新构建大根堆            updateHeap(nums, size);        }    }     private void createTopHeap(int[] nums) {        for (int i = 0; i < nums.length; i++) {            //当前插入的索引            int currIndex = i;            //父节点的索引            int parentIndex = (currIndex - 1) / 2;            //如果当前遍历的值比父节点大的话,就交换值。然后继续往上层比较            while (nums[currIndex] > nums[parentIndex]) {                //交换当前遍历的值与父节点的值                swap(nums, currIndex, parentIndex);                //把父节点的索引指向当前遍历的索引                currIndex = parentIndex;                //往上计算父节点索引                parentIndex = (currIndex - 1) / 2;            }        }    }     private void updateHeap(int[] nums, int size) {        int index = 0;        //左节点索引        int left = 2 * index + 1;        //右节点索引        int right = 2 * index + 2;        while (left < size) {            //最大值的索引            int largestIndex;            //如果右节点大于左节点,则最大值索引指向右子节点索引            if (right < size && nums[left] < nums[right]) {                largestIndex = right;            } else {                largestIndex = left;            }            //如果父节点大于最大值,则把父节点索引指向最大值索引            if (nums[index] > nums[largestIndex]) {                largestIndex = index;            }            //如果父节点索引指向最大值索引,证明已经是大根堆,退出循环            if (largestIndex == index) {                break;            }            //如果不是大根堆,则交换父节点的值            swap(nums, largestIndex, index);            //把最大值的索引变成父节点索引            index = largestIndex;            //重新计算左节点索引            left = 2 * index + 1;            //重新计算右节点索引            right = 2 * index + 2;        }    }     private void swap(int[] nums, int i, int j) {        int temp = nums[i];        nums[i] = nums[j];        nums[j] = temp;    }}
    复制代码

    桶排序

    过程

    排序过程:(1)设置一个定量的数组当作空桶子;(2)寻访序列,并且把记录一个一个放到对应的桶子去;(3)对每个不是空的桶子进行排序。(4)从不是空的桶子里把项目再放回原来的序列中。


    代码实现

    public class BucketSort extends BaseSort {     public static void main(String[] args) {        BucketSort sort = new BucketSort();        sort.printNums();    }     @Override    protected void sort(int[] nums) {        if (nums == null || nums.length < 2) {            return;        }        bucketSort(nums);    }     public void bucketSort(int[] nums) {        if (nums == null || nums.length < 2) {            return;        }        //找出最大值,最小值        int max = Integer.MIN_VALUE;        int min = Integer.MAX_VALUE;        for (int num : nums) {            min = Math.min(min, num);            max = Math.max(max, num);        }        int length = nums.length;        //桶的数量        int bucketCount = (max - min) / length + 1;        int[][] bucketArrays = new int[bucketCount][];        //遍历数组,放入桶内        for (int i = 0; i < length; i++) {            //找到桶的下标            int index = (nums[i] - min) / length;            //添加到指定下标的桶里,并且使用插入排序排序            bucketArrays[index] = insertSortArrays(bucketArrays[index], nums[i]);        }        int k = 0;        //合并全部桶的        for (int[] bucketArray : bucketArrays) {            if (bucketArray == null || bucketArray.length == 0) {                continue;            }            for (int i : bucketArray) {                //把值放回到nums数组中                nums[k++] = i;            }        }    }     //每个桶使用插入排序进行排序    private int[] insertSortArrays(int[] arr, int num) {        if (arr == null || arr.length == 0) {            return new int[]{num};        }        //创建一个temp数组,长度是arr数组的长度+1        int[] temp = new int[arr.length + 1];        //把传进来的arr数组,复制到temp数组        for (int i = 0; i < arr.length; i++) {            temp[i] = arr[i];        }        //找到一个位置,插入,形成新的有序的数组        int i;        for (i = temp.length - 2; i >= 0 && temp[i] > num; i--) {            temp[i + 1] = temp[i];        }        //插入需要添加的值        temp[i + 1] = num;        //返回        return temp;    }}
    复制代码


    用户头像

    卷不死,就往…… 2021.10.19 加入

    2019NOIP退役成员,华为云享专家,阿里云专家博主,csdn博主,努力进行算法分享,有问题欢迎私聊

    评论

    发布
    暂无评论
    七日算法先导(六)——堆排序,桶排序_8月月更_秋名山码民_InfoQ写作社区