数据结构最常用的排序算法一(冒泡、插入、选择)-Java实现

冒泡排序

核心思想:冒泡排序只会比较相邻的两个数,相邻的两个数满足大小条件时不移动,不满足大小条件时交换位置,然后指针后移一位,直到指针到达未排序的序列的倒数第二个位置,再进行下一轮排序。冒泡排序每一轮至少会使一个数到达指定的位置。

以C,D,A,F,B,E为例,下面图解为从小到大排序,且只展示了F回到自己位置,后面的数据思想相同。
冒泡排序
第一轮结束后,F回到了自己的位置。

时间复杂度:每一次循环都有至少一个数字回到自己的位置上,那么循环数组长度那么多次就会使所有的数字回到自己的位置,因此时间复杂度为O(n^2),但冒泡排序还可以进行优化。如下图所示,实际在第三轮已经将所有的数字排序完成,第四、五、六次是不必要的操作,因为我们可以加一个标志位,当一轮中没有任何数字交换,说明已经全部排序成功,提前跳出循环,祥见代码。
冒泡排序提前结束
所以优化后的冒泡排序的时间复杂度可以准确描述为,最好情况下,只需经过一个冒泡,时间复杂度为O(n),最坏情况下,需要n次冒泡,时间复杂度为O(n2)。平均情况下的时间复杂度也为O(n2)

空间复杂度:O(1),像这种空间复杂度为O(1)的排序算法也称为原地排序,即没有借助多余的内存空间。

Java实现

	/**
     *@author 苞谷洁子
     *@param arr 待排序的数组 
     */
    public static int[] sort(int[] arr){
        if(arr == null){
            return null;
        }
        if(arr.length == 1 || arr.length == 0){
            return arr;
        }
        boolean flag;
        for(int i = 0;i<arr.length;i++){
            flag = true;
            //从后往前排序的,下标为arr.length-i的已经排好序了
            for(int j = 0;j<arr.length-i-1;j++){
                //当前一个数字比后一个数字大,就将相邻的两个数字交换
                if(arr[j]>arr[j+1]){
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    flag = false;
                }
            }
            //flag标志记录当前次是否进行的修改,为true表示已经排序完成了,可以直接返回了
            if(flag){
                break;
            }
        }
        return arr;
    }

插入排序

核心思想:插入排序是从数组的插入演变而来的,其主要思想是将数组分为两个区域,一个是已经排序的区域,一个是未排序的区域。每一轮都是将未排序的第一个数字与排序的数字从后往前比较,边比较边将比较过的数字后移,直到找到插入的位置,将其插入。每一轮有且只有一个数字回到自己的位置,如下图所示。

插入排序
时间复杂度:插入排序也分最好情况和最坏情况,在最好的情况下,数组完全为有序的,因此在无序序列第一个数字和有序序列最后数字比较时,可以直接得到要插入的位置就是当前位置,所以只需要n次操作,就能完成排序,时间复杂度为O(n);最坏情况下数组是完全逆序的,因此每一轮都要将前i个数字后移才能挪出插入的位置,时间复杂度为O(n2),平均时间复杂度为O(n2)。

空间复杂度:插入排序也是一个原地排序,没有使用多余的内存空间,空间复杂度为O(1)

Java实现:

	/**
     * @author 苞谷洁子
     * @param arr 待排序的数据
     */
    public static int[] sort(int[] arr){
        if(arr == null){
            return null;
        }
        if(arr.length == 1 || arr.length == 0){
            return arr;
        }
        for(int i = 0;i<arr.length;i++){
            int temp = arr[i];
            int j = i-1;
            for(;j>=0;j--){
                if(temp < arr[j]){
                    arr[j+1] = arr[j];
                }else{
                    break;
                }
            }
            arr[j+1] = temp;
        }
        return arr;
    }

选择排序

核心思想:选择排序也是将数组分为两个区域,已排序和未排序区域。它是从未排序数组中,按照要排序的大小顺序(如从大到小排序),选择出最小的数字,和未排序的第一个数字交换位置,并为已排序的数组中,依次这样,直到整个数组排序完成。如下图所示:
选择排序
时间复杂度:选择排序部分最好情况和最坏情况,因为即使数组是有序的,但是每一轮仍要遍历无序的部分找出最小的数字,因此选择排序的时间复杂度为O(n^2)。

空间复杂度:选择排序也是一个原地排序算法,空间复杂度为O(1)。

Java实现:

	/**
     *@author 苞谷洁子
     * @param arr 待排序的数组
     */
    public static int[] sort(int[] arr){
        if(arr == null){
            return null;
        }
        if(arr.length == 1 || arr.length == 0){
            return arr;
        }
        for(int i = 0;i<arr.length-1;i++){
            int min = arr[i];
            int n = i;
            for(int j = i;j<arr.length;j++){
                //选择出最小的数
                if(arr[j]<min){
                    min = arr[j];
                    n = j;
                }
            }
            if(n != i){
                int temp = arr[i];
                arr[i] = arr[n];
                arr[n] = temp;
            }
        }
        return arr;
    }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值