• 数据结构与算法:排序算法(2)


    目录

    堆排序

    使用步骤

    代码实现

    计数排序

    适用范围

    过程

    代码实现

    排序优化

    桶排序

    工作原理

    代码实现


    堆排序

    二叉堆的特性:

            1. 最大堆的堆顶是整个堆中的最大元素

            2. 最小堆的堆顶是整个堆中的最小元素

            以最大堆为例,如果删除一个最大堆的堆顶(并不是完全删除,而是跟末尾的节点交换位置),经过自我调整,第2大的元素就会被交换上来,成为最大堆的新堆顶

            在删除值为10的堆顶节点后,经过调整,值为9的新节点就会顶替上来;由于二叉堆的这个特性,每一次删除旧堆顶,调整后的新堆顶都是大小仅次于旧堆顶的节点。那么只要反复删除堆顶,反复调整二叉堆,所得到的集合就会成为一个有序集合。

    使用步骤

    1. 把无序数组构建成二叉堆。需要从小到大排序,则构建成最大堆;需要从大到小排序,则构建成最小堆

    2. 循环删除堆顶元素,替换到二叉堆的末尾,调整堆产生新的堆顶

    代码实现

    1. public static void main(String[] args){
    2. int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};
    3. heapSort(array);
    4. System.out.println(Arrays.toString(array));
    5. }
    6. public static void downAdjust(int[] array, int parentIndex, int length) {
    7. int temp = array[parentIndex];
    8. int childIndex = 2 * parentIndex + 1;
    9. while (childIndex < length){
    10. if (childIndex + 1 < length && array[childIndex + 1] > array[childIndex]) {
    11. childIndex++;
    12. }
    13. if (temp >= array[childIndex]){
    14. break;
    15. }
    16. array[parentIndex] = array[childIndex];
    17. parentIndex = childIndex;
    18. childIndex = 2 * childIndex + 1;
    19. }
    20. array[parentIndex] = temp;
    21. }
    22. public static void heapSort(int[] array) {
    23. //1.无序数组构建成最大堆
    24. for (int i = (array.length-2)/2; i >= 0; i--) {
    25. downAdjust(array, i, array.length);
    26. }
    27. System.out.println(Arrays.toString(array));
    28. //2.环删除堆顶元素,移到集合尾部,调整堆产生新的堆顶
    29. for (int i = array.length - 1; i > 0; i--) {
    30. int temp = array[i];
    31. array[i] = array[0];
    32. array[0] = temp;
    33. downAdjust(array, 0, i);
    34. }
    35. }

    计数排序

    有一些特殊的排序并不基于元素比较,而是利用数组下标来确定元素的正确位置的。

    适用范围

    它适用于一定范围内的整数排序。在取值范围不是很大的情况下,它的性能甚至快过那些时间复杂度为O(nlogn)的排序

    过程

    假设数组中有20个随机整数,取值范围为0~10,要求用最快的速度把这20个整数从小到大进行排序,可以根据这有限的范围,建立一个长度为11的数组。数组下标从0到10,元素初始值全为0

    随机值:9,3,5,4,9,1,2,7,8,1,3,6,5,3,4,0,10,9 ,7,9

    这个无序的随机数列,每一个整数按照其值对号入座,同时,对应数组下标的元素进行加1操作

    该数组中每一个下标位置的值代表数列中对应整数出现的次数;直接遍历数组,输出数组元素的下标值,元素的值是几,就输出几次,输出的数列已经是有序的了

    代码实现

    1. public static void main(String[] args){
    2. int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};
    3. int[] sortedArray = countSort(array);
    4. System.out.println(Arrays.toString(sortedArray));
    5. }
    6. public static int[] countSort(int[] array) {
    7. //1.得到数列的最大值
    8. int max = array[0];
    9. for(int i=1; i
    10. if(array[i] > max){
    11. max = array[i];
    12. }
    13. }
    14. //2.根据数列最大值确定统计数组的长度
    15. int[] countArray = new int[max+1];
    16. //3.遍历数列,填充统计数组
    17. for(int i=0; i
    18. countArray[array[i]]++;
    19. }
    20. //4.遍历统计数组,输出结果
    21. int index = 0;
    22. int[] sortedArray = new int[array.length];
    23. for(int i=0; i
    24. for(int j=0; j
    25. sortedArray[index++] = i;
    26. }
    27. }
    28. return sortedArray;
    29. }

    排序优化

    只以数列的最大值来决定统计数组的长度,其实并不严谨;如:数列的最大值是99,但最小的整数是90。如果创建长度为100的数组,那么前面从0到89的空间位置就都浪费了

    解决:

            以数列最大值-最小值+1作为统计数组的长度

    同时,数列的最小值作为一个偏移量,用于计算整数在统计数组中的下标

    1. public static void main(String[] args){
    2. int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10};
    3. int[] sortedArray = countSort(array);
    4. System.out.println(Arrays.toString(sortedArray));
    5. }
    6. public static int[] countSort(int[] array) {
    7. //1.得到数列的最大值和最小值,并算出差值d
    8. int max = array[0];
    9. int min = array[0];
    10. for(int i=1; i
    11. if(array[i] > max){
    12. max = array[i];
    13. }
    14. if(array[i] < min){
    15. min = array[i];
    16. }
    17. }
    18. int d = max - min;
    19. //2.创建统计数组并统计对应元素的个数
    20. int[] countArray = new int[d+1];
    21. for(int i=0; i
    22. countArray[array[i]-min]++;
    23. }
    24. //3.统计数组做变形,后面的元素等于前面的元素之和
    25. for(int i=1;i
    26. countArray[i] += countArray[i-1];
    27. }
    28. //4.遍历统计数组,输出结果
    29. int[] sortedArray = new int[array.length];
    30. for(int i=array.length-1;i>=0;i--) {
    31. sortedArray[countArray[array[i]-min]-1]=array[i];
    32. countArray[array[i]-min]--;
    33. }
    34. return sortedArray;
    35. }

    桶排序

    桶排序是一种线性时间的排序算法。类似于计数排序所创建的统计数组,桶排序需要创建若干个桶来协助排序。

    桶:每一个桶(bucket)代表一个区间范围,里面可以承载一个或多个元素。

    工作原理

    1.创建桶,并确定每一个桶的区间范围

            创建的桶数量等于原始数列的元素数量

            区间跨度 = (最大值-最小值)/ (桶的数量 - 1)

    2.遍历原始数列,把元素对号入座放入各个桶中

    3.对每个桶内部的元素分别进行排序

    4.遍历所有的桶,输出所有元素

    代码实现

    1. public static void main(String[] args){
    2. double[] array = new double[]{4.12,6.421,0.0023,3.0,2.123,8.122,4.12, 10.09};
    3. double[] sortedArray = bucketSort(array);
    4. System.out.println(Arrays.toString(sortedArray));
    5. }
    6. public static double[] bucketSort(double[] array){
    7. //1.得到数列的最大值和最小值,并算出差值d
    8. double max = array[0];
    9. double min = array[0];
    10. for(int i=1; i
    11. if(array[i] > max){
    12. max = array[i];
    13. }
    14. if(array[i] < min){
    15. min = array[i];
    16. }
    17. }
    18. double d = max - min;
    19. //2.初始化桶
    20. int bucketNum = array.length;
    21. ArrayList> bucketList = new ArrayList>(bucketNum);
    22. for(int i=0;i
    23. bucketList.add(new LinkedList());
    24. }
    25. //3.遍历原始数组,将每个元素放入桶中
    26. for(int i = 0; i < array.length; i++){
    27. int num = (int)((array[i] - min) * (bucketNum-1) / d);
    28. bucketList.get(num).add(array[i]);
    29. }
    30. //4.对每个桶内部进行排序
    31. for(int i = 0; i < bucketList.size(); i++){
    32. Collections.sort(bucketList.get(i));
    33. }
    34. //5.输出全部元素
    35. double[] sortedArray = new double[array.length];
    36. int index = 0;
    37. for(LinkedList list : bucketList){
    38. for(double element : list){
    39. sortedArray[index] = element;
    40. index++;
    41. }
    42. }
    43. return sortedArray;
    44. }

            所有的桶都保存在ArrayList集合中,每一个桶都被定义成一个链表(LinkedList),这样便于在尾部插入元素

  • 相关阅读:
    ChatGPT、New Bing、文心一言、通义千问等 AI 工具到底哪个更AI? - 第二期
    申银万国期货通过ZStack Cube信创超融合一体机打造金融信创平台
    Python进阶系列 - 20讲 with ... as:
    Android Studio中配置jdk版本无效问题
    P1394 山上的国度 题解
    什么蓝牙耳机久戴不痛?久戴不累耳的蓝牙耳机推荐
    【python爬虫】10.指挥浏览器自动工作(selenium)
    非root用户,没有root权限,安装nginx
    以太坊合并后,区块链生态将发生什么改变?
    秋招面试之MySQL:面试常考题(附答案)+MySQL性能调优经验,秋招必胜!
  • 原文地址:https://blog.csdn.net/qq_35056891/article/details/133127815