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


    前言所学

    前面我们学习了归并,希尔俩个排序,下面由这张图来总结一下八大排序
    在这里插入图片描述可能有的小伙伴会说,学这些排序有什么用,平时开发也用不到,但是我的理解是这样的:

    1. 锻炼思维,排序中蕴含的思维很多,双指针,递归,分治等等
    2. 普及常识性问题
    3. 面试,区分人才

    堆排序

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

    大顶堆,小顶堆

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

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

    思路及动画演示

    1. 对原数组构建成大顶堆。
      
      • 1
    2. 交换头尾值,尾指针索引减一,固定最大值。 
      
      • 1
    3.  重新构建大顶堆。
      
      • 1
    4.  重复步骤2,3直到最后一个元素排序完成。
      
      • 1

    请添加图片描述

    在这里插入图片描述

    代码实现

    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
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    桶排序

    过程

    排序过程:
    (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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
  • 相关阅读:
    员工犯错,就应该受惩罚吗?
    设计模式之单例设计模式
    爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会
    pgsql执行脚本并传参
    [附源码]计算机毕业设计JAVA疫情防控下高校教职工健康信息管理系统
    vite+react 使用 react-activation 实现缓存页面
    【开源】SpringBoot框架开发创意工坊双创管理系统
    RSA加密解密算法复习
    快应用开发初体验
    语义化标签
  • 原文地址:https://blog.csdn.net/weixin_45920495/article/details/126192865