冒泡排序

简述

原理是相邻的两两元素做比较并往后移动,每轮可以选出一个最值

故最多n-1轮排完

每轮最多比较n-1-已完成轮数次

总共最多比较n*(n-1)/2次

比较并交换可以通过中间变量暂存交换值来处理

基本冒泡排序

/**
 * 冒泡排序
 * 时间复杂度On2,空间复杂度O1
 * 执行n-1轮
 * 每轮比较n-1-i次,总共比较n*(n-1)/2次
 * 最大交换n*(n-1)/2次——最坏情况:倒序
 * @author 夜神
 */
public class BubSort {

    /**
     * 向前比较 int j=arr.length-1;j>i;j--
     * @param arr
     */
    public static void forwardSort(int[] arr){
        int tmp=0;
        int count=0;
//        总共比较次数,也是最大交换次数(最坏情况:倒序)
        int compare=0;
//        n-1轮排完序,i控制轮数,隐含已经排好序的个数
        for(int i=0;i<arr.length-1;i++){
//            每轮比较n-1-i次    前序排列写法,往前面比较
            for (int j=arr.length-1;j>i;j--){
                compare++;
//             这里比较关系用的<,选取的是小值   小的向前移,拍好的在左边
                if (arr[j]<arr[j-1]){
                    tmp=arr[j];
                    arr[j]=arr[j-1];
                    arr[j-1]=tmp;
                    count++;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
        System.out.println("交换"+count+"次");
        System.out.println(compare+"次比较");
    }

    /**
     * 向后比较
     * 次数那里的另外一种写法 j<arr.length-1-i j从0开始,后续排列
     * @param arr
     */
    public static void backwardsSort(int[] arr){
//        交换次数
        int count=0;
//        总共比较次数,也是最大交换次数(最坏情况:倒序)
        int compare=0;
        int tmp;
//        n-1轮 i 属于[0,n-1),即[0,n-2]
        for (int i=0;i<arr.length-1;i++){
//            每轮比较n-1-i次 总共(n-1)-0+(n-1)-1+(n-1)-2+....=(n-1)*(n-1)-(0+1+2+...+n-1-1)=(n-1)*(n-1)-(n-2)*(n-1)/2=n*(n-1)/2
            for(int j=0;j<arr.length-1-i;j++){
                compare++;
                if (arr[j]>arr[j+1]){
                    tmp=arr[j+1];
                    arr[j+1]=arr[j];
                    arr[j]=tmp;
                    count++;
                }
            }
        }
        System.out.println(Arrays.toString(arr));
        System.out.println("交换"+count+"次");
        System.out.println(compare+"次比较");

    }
}

 

优化:添加退出点

遍历一遍如果没有发生交换表示序列已经有序,可以直接退出
 /**
     * 优化;遍历一遍如果没有发生交换表示序列已经有序,可以退出
     * @param arr
     * @author 夜神
     */
    public static void setBreakPointSort(int[] arr) {
        //        交换次数
        int count=0;
//        总共比较次数,也是最大交换次数(最坏情况:倒序)
        int compare=0;
        int tmp;
//        n-1轮 i 属于[0,n-1),即[0,n-2]
        for (int i=0;i<arr.length-1;i++){
            //每轮遍历前,设置有序标识
            boolean isSorted = true;
//            每轮比较n-1-i次 总共(n-1)-0+(n-1)-1+(n-1)-2+....=(n-1)*(n-1)-(0+1+2+...+n-1-1)=(n-1)*(n-1)-(n-2)*(n-1)/2=n*(n-1)/2
            for(int j=0;j<arr.length-1-i;j++){
                compare++;
                if (arr[j]>arr[j+1]){
                    tmp=arr[j+1];
                    arr[j+1]=arr[j];
                    arr[j]=tmp;
                    count++;
                    isSorted = false;
                }
            }
            // 如果遍历一轮没有发生交换表示序列已经有序
            if (isSorted) {
                break;
            }
        }
        System.out.println(Arrays.toString(arr));
        System.out.println("交换"+count+"次");
        System.out.println(compare+"次比较");
    }

 

 优化:有序区间界定

数组中可能有已经有序的区域,有序区域不需要再重新比较交换

每比较一轮,有序区域+1,但是实际有序区域可能更长(本身就有部分是有序的)

可以在每一轮排序后,记录下来最后一次元素交换的位置,该位置即为边界点,前面的是无序区域,后面的是有序区域

内层for循环比较完,通过中间值记录最后发生交换的位置(边界点),在外层for循环中更新边界点

 /**
     * 区域优化法
     * @param array
     */
    public static void areaOptimizeSort(int[] array) {
        int tmp  = 0;
        //记录最后一次交换的位置
        int lastExchangeIndex = 0;
        //无序数列的边界,每次比较只需要比到这里为止 初始为数组末尾
        int sortBorder = array.length - 1;
        //控制轮数 n-1轮
        for(int i = 0; i < array.length-1; i++)
        {
            //有序标记,每一轮的初始是true 遍历一遍不发生变化说明已经有序
            boolean isSorted = true;
            // 直接在无序区域内进行比较
            for(int j = 0; j < sortBorder; j++)
            {
                // 发生交换
                if(array[j] > array[j+1])
                {
                    tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                    //有元素交换,所以不是有序,标记变为false
                    isSorted = false;
                    //把无序数列的边界更新为最后一次交换元素的位置
                    lastExchangeIndex = j;
                }
            }
            // 更新边界点位置:最后发生交换的位置
            sortBorder = lastExchangeIndex;
            if(isSorted){
                break;
            }
        }
    }

 

升级:鸡尾酒排序

 

posted on 2023-03-12 19:49  or追梦者  阅读(4)  评论(0编辑  收藏  举报