Java十大经典排序(上)

前言:

近期在准备面试的时候,在准备算法的排序的过程中,查看了许多网上许多博客,发现很多博客总结的不是很全面,而且有部分博客中也存在着一些误差,于是我就花费了几天的时间,研究了一下排序算法,对排序算法做了一个比较全面的总结。包含了我们常使用的十大排序算法。

排序的定义

****对一组对象,按照某一规格进行有序排列

排序常见术语

  • 稳定:排序要求必须正确,不能出现任何差错,比如两个数相同,则排序后两个数的顺序不能够改变
  • 不稳定:相对于稳定而言,就是两个相同的数,排序后两个数的位置有可能发生改变。
  • 内排序:所有的排序操作都在内存中完成(这个就要对操作系统内存概念有所了解)
  • 外排序:由于数据太大,内存放不下,数据放在磁盘中,排序通过磁盘和内存的数据传输才能进行。
  • **时间复杂度:**一个算法执行所需要的系统时间
  • **空间复杂度:**一个算法执行所需要的内存空间大小

算法时间空间复杂度总结

图片

一,冒泡排序

冒泡排序是排序算法中比较简单的排序算法,也是大多数人都会的算法,但是冒泡排序算法的时间性能较低,每一次比较相邻的两个元素,一次循环找到一个最大值放到最后。

1.1 算法描述

  • 每一次比较相邻的两个元素,相邻的两个元素中较大的放到后面,遍历一次找到最大值放到最后
  • 循环遍历剩余数

1.2 动图演示

图片

1.3 代码实现

这是最基础版本的冒泡排序。

public class bubbleSort{
    public static void main(String[] args) {
        int[] arr={3,4,2,1,5,7,0,1,2};
        maoSort(arr);
    }
    public static  void maoSort(int[] arr){
        int count=0;
        //对数组arr采用冒泡排序进行排序
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        int temp=0;
        for(int i=0;i<arr.length-1;i++){
            for(int j=0;j<arr.length-i-1;j++){
                if(arr[j]<=arr[j+1]){}
                else {
                    temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;}}
            System.out.println("------------------第"+i+"轮-------------------------------");
            printArr(arr);
        }
        System.out.println("------------------------排序后-------------------------");
        printArr(arr);
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

运行结果:
图片

算法分析:

从这个我们可以看出我们一共有9个元素,需要进行八轮排序,而且我们发现第六轮后我们就已经排序完成,后面就属于浪费资源。

冒泡排序算法升级

升级其实很简单就是设置一个标志位flag,因为我们一旦排序完成后就不需要在交换数据,所以我们只要判断该次循环是否交换数据,如果有数据交换则没有排序完,如果没有数据交换就表示交换完成。这样会省很多时间。

图片

public class MaoPao {
    public static void main(String[] args) {
        int[] arr={3,4,2,1,5,7,0,1,2};
        maoSort(arr);
    }
    public static  void maoSort(int[] arr){
        int count=0;
        //对数组arr采用冒泡排序进行排序
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        int temp=0;
        for(int i=0;i<arr.length-1;i++){
            boolean flag=true;
            for(int j=0;j<arr.length-i-1;j++){
                if(arr[j]<=arr[j+1]){}
                else {
                    temp = arr[j + 1];
                    arr[j + 1] = arr[j];
                    arr[j] = temp;
                    flag=false;
                }
            }
            if(flag==true) break;
            System.out.println("------------------第"+(i+1)+"轮-------------------------------");
            printArr(arr);
        }
        System.out.println("------------------------排序后-------------------------");
        printArr(arr);
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

运行结果:这样会省去大量时间性能浪费。
图片

算法性能分析

最佳情况:T(n) = O(n)   最差情况:T(n) = O(n2)   平均情况:T(n) = O(n2),所以说无论怎么升级,时间性能还是比较低。

二:选择排序

选择排序(Selection-sort)也是一种简单直观的排序算法,也是大家比较容易想得到的排序算法,他的工作原理是:首先在未排序的里面找到最小或最大的的元素,存放到数组的起始位置或末尾位置,然后再从剩余的元素里面找到最小的元素放到已排序的数组后面。

算法描述

  • 有一组数,遍历其中的数找到最小的放大其实位置。
  • 然后从去掉排序的剩余数里面找到最小的放到已经排序的后面

动图演示

图片

代码

基础版本

public class Selection{
    public static void main(String[] args) {
        int[] arr={3,4,2,1,5,7,0,1,2};
        xzSort(arr);
    }
    public static  void xzSort(int[] arr){
        //对数组arr采用冒泡排序进行排序
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        for(int i=0;i<arr.length-1;i++){
            int min=arr[i];
            int temp;
            int index=i;
            for(int j=i;j<arr.length;j++){
                if(min>arr[j]){
                    min=arr[j];
                    index=j;
                }
            }
            //遍历一遍后我们可以得到最小元素的下标,然后交换
            temp=arr[i];
            arr[i]=arr[index];
            arr[index]=temp;
            System.out.println("------------------第"+(i+1)+"轮-------------------------------");
            printArr(arr);
        }
        System.out.println("------------------------排序后-------------------------");
        printArr(arr);
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

运行结果
图片

升级后,防止排序后继续排序浪费多余时间性能。和冒泡排序一样添加一个标志位。比如如果是排序数组,为[1,2,3,4,5,6,7],这样就浪费时间性能。

图片

代码升级

public class Selection{
    public static void main(String[] args) {
        int[] arr={1,2,3,4,5,6,7};
        xzSort(arr);
    }
    public static  void xzSort(int[] arr){
        //对数组arr采用冒泡排序进行排序
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        for(int i=0;i<arr.length-1;i++){
            int min=arr[i];
            int temp;
            int index=i;
            boolean flag=true;
            for(int j=i;j<arr.length;j++){
                if(min>arr[j]){
                    min=arr[j];
                    index=j;
                flag=false;}}
            //遍历一遍后我们可以得到最小元素的下标,然后交换
            if(flag==true)break;
            temp=arr[i];
            arr[i]=arr[index];
            arr[index]=temp;
            System.out.println("------------------第"+(i+1)+"轮-------------------------------");
            printArr(arr);
        }
        System.out.println("------------------------排序后-------------------------");
        printArr(arr);
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

图片

运行截图

图片

算法分析

最佳情况:T(n) = O(n2)  最差情况:T(n) = O(n2)  平均情况:T(n) = O(n2)

三:插入排序

****插入排序(Insertion-Sort)的算法是一种简单的排序算法。他的工作原理是通过构建有序序列,选择未排序的数列第一项,插入到已排序数列中的合适位置中。

算法描述

  • 从第一个元素开始,该元素可以认为已经被排序
  • 取出下一个元素,在已经排序的元素列表中从后向前扫描
  • 如果该元素(已经排序)大于新元素,将该元素移到下一位
  • 重复步骤

动图演示

图片

代码实现

public class InsertSort {
    public static void main(String[] args) {
        int[] arr={3,4,2,1,5,7,0,1,2};
        ISort(arr);
    }
    public static void ISort(int[] arr){
        //对数组arr采用插入排序进行排序
        //排序的思想是,选择未排序的第一个元素
        //将这个元素插入到前面已经排序的合适位置中
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        int current;
        for(int i=0;i<arr.length-1;i++){
            current=arr[i+1];
            int preIndex=i;
            while(preIndex>=0&&current<arr[preIndex]){
                arr[preIndex+1]=arr[preIndex];
                preIndex--;
            }
            arr[preIndex+1]=current;
            System.out.println("------------------------第"+(i+1)+"轮-------------------------");
            printArr(arr);
        }
        System.out.println("------------------------排序后-------------------------");
        printArr(arr);
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

运行结果
图片

算法分析

最佳情况:T(n) = O(n)   最坏情况:T(n) = O(n2)   平均情况:T(n) = O(n2)

四:希尔排序

****希尔排序(Shell)是希尔提出的一种排序算法。希尔排序也是一种插入排序,他是简单插入排序经过改进之后的一个更加高效的版本,也称为缩小量排序,同时该算法是冲突最大时间O(n^2)限制的第一批算法。他与插入排序不同的是,他会优先比较距离较远的元素。所以希尔排序又叫缩小量排序。

图片

算法描述

****我们从图上可以看出,希尔排序的基本步骤,我们就是先对数组进行分组,然后分别进行组内排序,首先我们选择的分组间隔为数组长度的一半,然后依次减半直到间隔减为0为止。这里的每个组内排序采用的都是插入排序。对插入排序不了解的可以参考上面的插入排序算法。

详细设计思想

图解虽然很详细了,但是具体的设计还是需要结合代码来进行讲解,这样才能是大家更加清晰明了的熟悉希尔排序的原理。

图片

组内排序算法讲解,这个是一次分组后的排序过程。

图片

图片

依次直到间距为1.

代码实现

public class ShellSort {
    public static void main(String[] args) {
        int[] arr={3,4,2,1,5,7,0,1,2};
        sSort(arr);
    }
    public static void sSort(int[] arr){
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        //希尔排序算法
        int len=arr.length;
        int temp,grap=len/2;
        //间隔最后到间隔为1截止
        while (grap>0){
            for(int i=grap;i<len;i++){
                temp=arr[i];
                int preIndex=i-grap;
                while(preIndex>=0&&temp<arr[preIndex]){
                    arr[preIndex + grap] = arr[preIndex];
                    preIndex -= grap;
                }
             arr[preIndex+grap]=temp;
            }
            grap/=2;
        }
        System.out.println("------------------------排序后-------------------------");
        printArr(arr);
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

运行结果
****图片

五:归并排序

归并排序和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,因为始终都是O(nlogn)的时间复杂度。代价是需要额外的内存空间。

归并排序是建立在归并的操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。

算法描述

  • 帮长度为n的输入序列分成两个长度为n/2的子序列
  • 对这两个子序列分别采用归并排序;
  • 将两个排序好的子序列合并成一个最终的排序序列。

动图显示

图片

public class MergeSort {
    public static void main(String[] args) {
        int[] arr={3,4,2,1,5,7,0,1,2};
        System.out.println("------------------------排序前-------------------------");
        printArr(arr);
        System.out.println("------------------------排序后-------------------------");
        printArr(mSort(arr));
    }
    public static int[] mSort(int[] arr){
        if (arr.length < 2) return arr;
        int mid=arr.length/2;
        int[] left = Arrays.copyOfRange(arr, 0, mid);
        int[] right = Arrays.copyOfRange(arr, mid, arr.length);
        return merge(mSort(left),mSort(right));
    }
    public static int[] merge(int[] left, int[] right) {
        //需要开辟一个新的数组用于保存归并后的数组
        int[] result=new int[left.length+right.length];
        for(int index=0,i=0,j=0;index<result.length;index++){
            if(i>=left.length){
                result[index]=right[j++];
            }
            else if(j>=right.length){
                result[index]=left[i++];
            }else if(left[i]>right[j]){
                result[index]=right[j++];
            }else
                result[index]=left[i++];
        }
        return result;
    }
    //打印数组元素
    public static void printArr(int[] arr){
        for(int a:arr){
            System.out.print(a+" ");
        }
        System.out.println();
    }
}

运行结果
图片

总结

这是对十大经典排序的前五种排序进行了总结,分析下期会继续分享剩余的5种排序算法。以上代码我都已经进行了调试没有错误,希望可以对小伙伴有所帮助。

猜你喜欢

转载自blog.csdn.net/qq_44762290/article/details/113519640