java - 数据结构,算法,排序

本文详细介绍了排序的概念,包括排序的稳定性以及在实际中的应用。接着讲解了七大基于比较的排序算法,如插入排序、希尔排序、选择排序、堆排序、冒泡排序、快速排序和归并排序,重点探讨了快速排序和归并排序的原理、实现以及性能分析。快速排序在大量数据排序时可能导致栈溢出,而归并排序适用于海量数据的外部排序问题。
摘要由CSDN通过智能技术生成

一、概念

1.1、排序

排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。
平时的上下文中,如果提到排序,通常指的是排升序(非降序)。 通常意义上的排序,都是指的原地排序(in place sort)
原地排序:就是指在排序过程中不申请多余的存储空间,只利用原来存储待排数据的存储空间进行比较和交换的数据排序。

1.2、稳定性(重要)

两个相等的数据,如果经过排序后,排序算法能保证其相对位置不发生变化,则我们称该算法是具备稳定性的排序算法
在这里插入图片描述

1.3、应用

1. 各大商城的价格从低到高等
在这里插入图片描述
2. 中国大学排名
在这里插入图片描述

二、七大基于比较的排序-总览

在这里插入图片描述

三、插入排序

3.1、直接插入排序-原理

整个区间被分为

  1. 有序区间
  2. 无序区间
    每次选择无序区间的第一个元素,在有序区间内选择合适的位置插入

插入排序非常简单,就像打扑克牌一样,假设我们拿到第一张牌,那第一场牌肯定是有序的,然后那第二张牌和第一张牌比较,如果第二张牌比第一张小,那就将第一张牌放在前面,以此类推
在这里插入图片描述

根据这个思维:第一个数据是有序的,也就是说:在我们遍历的时候,是从下标1 开始的。
具体的操作见下图:

在这里插入图片描述

3.2、实现直接插入排序

/**
     * 直接插入排序,按照从小到达的循序
     * @param array
     */
    public static void insertSortUp(int[] array){
   
        for (int i = 1; i < array.length; i++) {
   
            int tmp = array[i];
            int j = i-1;
            for ( ;j >= 0; j--) {
   
                if(array[j] > tmp){
   
                    array[j+1] = array[j];
                }else {
   
                    break;
                }
            }
            array[j+1] = tmp;
        }
    }

3.3、插入排序的性能分析

插入排序的稳定性:
在这里插入图片描述

结论

一个稳定的排序,可以实现为 不稳定的排序。 但是,一个本身就不稳定的排序是 无法变成 稳定的排序。
直接插入排序 是 有序的。 它的时间复杂度是 O(N^2);最好情况:O(N【数组有序】 也就是说:对于直接插入排序,数据越有序越快!
由此,不难联想到:直接插入排序有时候 会用于 优化 排序。
【假设:假设我们有一百万个数据需要排序,在排序的过程中,区间越来越小,数据越来越有序。直接插入排序的时间复杂度为 O(N),N
越来越小,那么,使用 直接插入排序是不是越来越快!也就是说:直接插入排序 有时候会 用于 排序优化】 直接插入排序经常使用在
数据量不多,且整体数据趋于有序的。

四、希尔排序

4.1、原理

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数n,把待排序文件中所有记录分成n个组,所有距离为 (数据量/n) 的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达只有一个组时,所有记录在统一组内排好序。

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1(gap就是要分成的组数)时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很
    快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比

正常情况下我们进行分组的时候都是按照顺序进行分组的
比如说:
在这里插入图片描述
那么,问题来了!我们怎去确定分多少组,而且越分越少。
【取自清华大学出版的一本书《数据结构》】
在这里插入图片描述

但是科学家的思维不同,他们分组的时候是跳着分组的
比如说:
在这里插入图片描述
在这里插入图片描述

上图转载于:https://blog.csdn.net/DarkAndGrey/article/details/122792097

4.2、模拟实现 - 希尔排序

/*
     * 时间复杂度和增量有关系,所以无法得出准确的时间复杂度
     * 但只需要记住:在一定的范围里,希尔排序的时间复杂度为 O(N^1.3 ~ N^1.5)
     * 空间复杂度为 O(1)
     * 稳定性:不稳定
     * 判断稳定性的技巧:如果在比较的过程中 发生了 跳跃式交换。那么,就是不稳定的排序。
     * */
    public static void shell(int[] array,int group){
   
        for (int i = group; i < array.length; i++) {
   
            int j = i - group;
            int tmp = array[i];
            for( ; j >=0; j = j-group){
   
                if(tmp < array[j]){
   
                    //交换元素
                    array[j+group] = array[j];
                    array[j] = tmp;
                }else {
   
                    break;
                }
            }
            array[j+group] = tmp;
        }
    }

    public static void shellSort(int[] array){
   
        //将整个数组分为5组
        int gap = 5;
        while(gap > 1){
   
            //将分好组的数进行插入排序
            shell(array, gap);
            //循环得到分多少组,将分的组数按照 group / 2 来分组
            gap = gap / 2;
        }
        //循环结束,那就说明前面分好组的数都排序好了,只剩下最后的一组 就是 gap = 1的组
        shell(array, 1);
    }

五、选择排序

5.1、原理

这里是引用
上图转载于:https://blog.csdn.net/DarkAndGrey/article/details/122792097

优化
定义 一个 变量, 用来记录 此时的 i 后面最小值的下标。等 j 遍历完了,最小值的下标也就拿到了。此时,再进行交换。
这样就不必让上面那样,遇到比 i下标元素 小的,就交换。

5.2、模拟实现- 选择排序

/*
     * 选择排序
     * 稳定性: 不稳定 见附图
     * 时间复杂度:O(N^2) 》》 外层循环 n -1,内层循环 n -1
     * 空间复杂度:O(1)
     * */
    public static void selectSort(int[] array){
   
        for (int i = 0; i < array.length; i++) {
   

            for (int j = i+1; j < array.length; j++) {
   
                if(array[i] > array[j]){
   
                    int tmp = array[i];
                    array[i] = array[j];
                    array[j] = tmp;
                }
            }
        }
    }

5.3、双向选择排序 (了解)

每一次从无序区间选出最小 + 最大的元素,存放在无序区间的最前和最后,直到全部待排序的数据元素排完 。
在这里插入图片描述
上图转载于:https://blog.csdn.net/DarkAndGrey/article/details/122792097

public static void selectSortOP(int[] array){
   
        int low = 0;
        int high = array.length - 1;
        // [low,high] 表示整个无序区间
        while(low < high){
   
            int min = low;
            int max = low;
            for (int i = low+1; i <= high; i++) {
   
                if(array[i] < array[min]){
   
                    min 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Später321

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值