算法 经典的八大排序算法详解和代码实现

排序算法的介绍

排序也称排序算法,排序时将一组数据,依指定的顺序进行排列的过程

排序的分类

内部排序,指将需要处理的所有数据都加载到内部内存中进行排序

外部排序,数据量很大,无法全部加载到内存中,需要借助外部存储进行排序,内存和外存结合

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaQctHNp-1640004020313)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214192058667.png)]

算法的时间复杂度

时间频度

时间频度:一个算法花费的时间与算法中语句的执行次数成正比,哪个算法中语句执行次数多,它花费时间就多。一个算法中的语句执行次数称为语句频度或时间频度。即为T(n).

示例

比如计算1-100所有数字之和,我们设计两种算法:

1.使用for循环计算

int total=0;
int end=100;
for(int i=1;i <=end;i++){
	total+=i;
}

使用for循环的时间频度:T(n)=n+1

2.直接计算

total=(1+end)*end/2;

直接计算的时间频度:T(n)=1

图表理解时间复杂度的特点

1.常数项可以忽略

2.低次项可以忽略

3.系数可以忽略

随着n增大的结果如下图:
在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4kx7J1YY-1640004020315)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214194532021.png)]

结论:

2n+20和2n随着n变大,执行曲线无限接近,20可以忽略

3n+10和3n随着n变大,执行曲线无限接近,10可以忽略

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLwN7wol-1640004020316)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214195018766.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XIjkn33o-1640004020317)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214195034627.png)]

结论:

算式随着n变大,同次方项执行曲线无限接近,低次项可以忽略

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VTSCmHLk-1640004020318)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214195414334.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2csaypls-1640004020319)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214195431121.png)]

结论:

随着n变大,同次方项曲线近似重合,系数可以忽略

时间复杂度

1)一般情况下,算法中的基本操作语句的重复执行次数是问题规模n的某个函数,用T(n)表示,若有个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度,简称时间复杂度。

2)T(n)不同,但时间复杂度可能相同。如:T(n)=n2+7n+6与T(n)=3n2+2n+2它们的T(n)不同,但是时间复杂度相同都为O(n^2)

3)计算时间复杂度的方法:

  • 用常数1代替运行时间中的所有加法常熟
  • 修改后的运行次数函数中,只保留最高阶项
  • 去除最高阶项的系数

常见的时间复杂度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u7B0XdkN-1640004020320)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214202037079.png)]

空间复杂度

空间复杂度该算法所耗费的存储空间

在做算法分析时,主要讨论的是时间复杂度。

排序算法的时间复杂度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ZGrxts9-1640004020321)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211214203024599.png)]

冒泡排序

基本思想

基本思想:通过对待排序序列从前向后,依次比较元素相邻元素的值,若发现逆序则变换,使值较大的元素逐渐从前移向后部,就像水底的气泡一样逐渐向上冒;

图解

img

img

小结:

  • 一共进行数组长度的减1次循环
  • 每一趟排序的次数在逐渐减少
  • 如果相邻的逆序就交换

代码示例

public class BubbleSort {
    public static void main(String[] args) {
        int arr[] = {11, 3, 17, 5, 9, 20,-1};
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        System.out.println("过程展示:");
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
            System.out.println(Arrays.toString(arr));
        }
        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));
    }
}

结果展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RBwgYgrc-1640004020324)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211215172612051.png)]

代码优化

public class BubbleSort {
    public static void main(String[] args) {
        int[] arr = {11, 3, 17, 5, 9, 20,21};
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        System.out.println("过程展示:");
        boolean flag=false;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j + 1]) {
                    flag=true;
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        if (!flag) {//在一趟排序中,一次交换都没有发生过
            break;
        }else{
            flag=false;
        }
            System.out.println(Arrays.toString(arr));
        }
        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));
    }
}

结果展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9M8Y9xKI-1640004020325)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211215184638252.png)]

选择排序

基本思想

每次找到最大值(最小值),从最后一位(最前一位)进行交换,依次向前(向后)交换,得到一个从小到大排列的有序序列

图解

img

结论:

  • 选择排序一共有数组的长度减1轮排序
  • 每一轮排序又是一个循环
  • 假定第一个数是最小数,然后和后面依次进行比较,从而确定最小数,并得到下标,然后进行交换

代码实现

public class SelectSort {
    public static void main(String[] args) {
        int[] arr={1,4,2,76,34,12};
        System.out.println("原数据:");
        System.out.println(Arrays.toString(arr));
        selectSort(arr);
        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));
    }

    //选择排序
    public static void selectSort(int arr[]) {
        for (int i = 0; i < arr.length - 1; i++) {
            int min = arr[i];
            int minIndex = i;
            for (int j = i+1; j < arr.length; j++) {
                if (min > arr[j]) {
                    min = arr[j];
                    minIndex = j;
                }
                }
                if (minIndex!=i) {
                    arr[minIndex]=arr[i];
                    arr[i]=min;
            }
                System.out.println("第"+(i+1)+"轮后~~");
                System.out.println(Arrays.toString(arr));
        }
    }
}

结果展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9PKRtJYz-1640004020326)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211215195434436.png)]

插入排序

基本思想

把n个待排序的元素看成为一个有序表和一个无序表,开始时有序表只包含一个元素,无序表中包含有n-1个元素,排序过程中每次从无序表中取出第一个元素,把它的排序码依次与有序表元素的排序码进行比较,将它插入到有序表中的适当位置,使之成为新的有序表

图解

img

代码实现

public class InsertSort {
    public static void main(String[] args) {
        int[] arr = {2, 4, 32, 12, 45, 2, 1, 4};
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        System.out.println("排序过程:");
        insetSort(arr);
        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));
    }

    public static void insetSort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int value = arr[i];//假设是插入的数
            int index = i-1;//插入的数的前面一个数
            while (index >= 0 && value < arr[index]) {
                arr[index + 1] = arr[index];
                index--;
            }
            arr[index + 1] = value;
            System.out.println(Arrays.toString(arr));
        }
    }
}

结果展示

希尔排序

基本思想

希尔也是一种插入排序,它是简单插入排序经过改进之后的一个更高效的版本,也称为缩小增量排序

希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键字越来越多,当增量减至1时,整个文件恰被分成一组,算法并终止

图解

在这里插入图片描述

img

代码实现

交换法:

public class ShellSort {
    public static void main(String[] args) {
        int[] arr={1,4,2,3,8,5,9,6,7};
        System.out.println("排序前:");
        System.out.println(Arrays.toString(arr));
        shellSort(arr);
        System.out.println("排序后:");
        System.out.println(Arrays.toString(arr));

    }
    private static void shellSort(int[] arr){
        int temp = 0;
        int count = 0;
        //一共gap组
        for(int gap=arr.length/2;gap>0;gap/=2){
            //遍历各组中的所有元素
            for(int i=gap;i < arr.length;i++){
                //如果当前元素大于加上步长后的那个元素,说明交换
                for(int j = i -gap;j>=0;j-=gap){
                    if(arr[j]>arr[j+gap]){
                        temp=arr[j];
                        arr[j]=arr[j+gap];
                        arr[j+gap]=temp;
                    }
                }
            }
            System.out.println("希尔排序第"+(++count)+"轮");
            System.out.println(Arrays.toString(arr));
        }

    }
}

移位法:

  public static void shellSort2(int[] arr) {
        for (int gap = arr.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arr.length; i++) {
                int j = i;
                int temp = arr[j];
                if (arr[j] < arr[j - gap]) {
                    while (j - gap >= 0 && temp < arr[j - gap]) {
                        arr[j] = arr[j - gap];
                        j -= gap;
                    }
                    arr[j] = temp;
                }
            }
            System.out.println(Arrays.toString(arr));
        }
    }
}

结果展示

1.交换法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E6BjSH0C-1640004020329)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211217155009204.png)]

2.移动法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7s0m15Pl-1640004020330)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211217161200934.png)]

快速排序

基本思想

快速排序是对冒泡排序的一种改进;通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有的数据都要小,然后再按此方法对者两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列

图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uLauNG0m-1640004020332)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211217191056707.png)]

img

代码实现

public class QuickSort {
    public static void main(String[] args) {
        int[] arr={1,5,3,-1,544,3,45,6,23,22,15};
        quickSort(arr,0,arr.length-1);
        System.out.println("arr"+ Arrays.toString(arr));
    }
    public static void quickSort(int[] arr,int left,int right){
        int temp=0;
        int l=left;//左下标
        int r=right;//右下标
        int pivot=arr[(left+right)/2];//中轴值
        while (l < r) {
            while (arr[l] < pivot) {
                l+=1;
            }
            while (arr[r] > pivot) {
                r-=1;
            }
            if (l >= r) {
                break;
            }
            temp=arr[l];
            arr[l]=arr[r];
            arr[r]=temp;
            if (arr[l]==pivot) {
                r-=1;
            }
            if (arr[r]==pivot) {
                l+=1;
            }
        }
        if(l==r){
            l+=1;
            r-=1;
        }
        //向左递归
        if (left < r) {
            quickSort(arr,left,r);
        }
        //向右递归
        if (right > l) {
            quickSort(arr,l,right);
        }
    }
}

结果展示

在这里插入图片描述

归并排序

基本思想

本文的归并排序我们采用递归去实现(也可采用迭代的方式去实现)。分阶段可以理解位就是递归拆分子序列的过程

图解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JHTe7ARE-1640004020333)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211217191559497.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CoxuuEfK-1640004020334)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211217192323728.png)]

代码实现

public class MergeSort {
    public static void main(String[] args) {
        int[] arr={8,4,5,7,1,3,6,2};
        System.out.println("排序前:"+Arrays.toString(arr));
        int temp[]=new int[arr.length];
        mergeSort(arr,0,arr.length-1,temp);
        System.out.println("归并排序后:"+ Arrays.toString(arr));
    }
    //分+和方法
    public static void mergeSort(int[] arr,int left,int right,int[] temp){
        if(left<right){
            int mid=(left+right)/2;
            mergeSort(arr,left,mid,temp);
            mergeSort(arr,mid+1,right,temp);
            merge(arr,left,mid,right,temp);
        }
    }
    /**
     *
     * @param arr 排序的原始数组
     * @param left 左边有序序列的初始索引
     * @param mid 中间索引
     * @param right 右边索引
     * @param temp 做中转的数组
     */
    public static void merge(int[] arr,int left,int mid,int right ,int[] temp){
        int i= left;
        int j=mid+1;
        int t=0;//指向temp数组的当前索引
        while(i<=mid && j<=right){
            if (arr[i]<=arr[j]) {
                temp[t]=arr[i];
                t+=1;
                i+=1;
            }else{
                temp[t]=arr[j];
                t+=1;
                j+=1;
            }
        }
        while (i <= mid) {
            temp[t]=arr[i];
            t+=1;
            i+=1;
        }
        while (j <= right) {
            temp[t]=arr[j];
              t+=1;
              j+=1;
        }
        t=0;
        int tempLeft=left;
        while (tempLeft <= right) {
            arr[tempLeft]=temp[t];
            t +=1;
            tempLeft+=1;
        }
    }

结果展示

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e47XKM5S-1640004020334)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20211220192324138.png)]

基数排序

基本思想

基数排序属于‘’分配式排序‘’,又称‘’桶子法‘’或bin sort,它是通过键值的各个位的值,将要排序的元素分配至某些‘’桶‘’中,达到排序的作用

是桶排序的扩展,属于稳定性的排序

将所有带比较数值统一为同样的数位长度,数位较短的数前面补零。然后从最低位开始,依次进行依次排序。这样从最低为排序一直到最高位排序完成以后,数列就变成一个有序序列。

图解

img

代码实现

public class RadixSort {
    public static void main(String[] args) {
        int arr[]={53,3,542,748,14,214};
        radixSort(arr);
    }
    public static void radixSort(int[] arr){
        int max=arr[0];
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > max) {
                max=arr[i];
            }
        }
        int maxLength=(max+"").length();
        int[][] bucket=new int[10][arr.length];
        int[] bucketElementCounts=new int[10];
        for(int j=0,n=1;j<maxLength;j++,n*=10) {
            for (int i = 0; i < arr.length; i++) {
                int digitOfElement = arr[i]/n % 10;
                bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[i];
                bucketElementCounts[digitOfElement]++;
            }
            int index = 0;
            for (int k = 0; k < bucket.length; k++) {
                if (bucketElementCounts[k] != 0) {
                    for (int l = 0; l < bucketElementCounts[k]; l++) {
                        arr[index] = bucket[k][l];
                    }
                }
                bucketElementCounts[k]=0;
            }
            System.out.println(Arrays.toString(arr));
        }
    }
}

  • 15
    点赞
  • 140
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

抹泪的知更鸟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值