排序(一):冒泡排序

排序算法系列文章

排序(一):冒泡排序
排序(二):选择排序
排序(三):堆排序
排序(四):插入排序
排序(五):二分搜索

前言----十大经典排序算法

在这里插入图片描述

  • 以上表格是基于数组进行排序的一般结论
  • 冒泡、选择、插入、归并、快速、希尔、堆排序,属于比较排序(Comparison Sorting)

冒泡排序(Bubble Sort)

冒泡排序(Bubble Sort)的基本思想是:通过对待排序数组从头到尾遍历(从索引较小的元素开始),依次比较相邻元素的值,若发现逆序则交换,使值较大的元素逐渐从数组头部移向尾部,就象水底下的气泡一样逐渐向上冒。

算法步骤

① 从头开始比较每一对相邻元素,如果第一个比第二个大,就交换它们的位置
② 执行完一轮后,最末尾那个元素就是最大元素
③ 忽略上一步中曾经找到的最大元素,重复执行步骤一,直到全部元素有序

代码实现

	 public static void main(String[] args) {
    
    
        int[] array = {
    
    10,9,19,28,37,34,5};
        
        //end > 0为终止条件,只有end > 0,也即是说,end为1的时候,它还可以和它前面的进行比较
        //end为0时,它前面就没有元素了
        for (int end = array.length - 1; end > 0; end--){
    
    //一共比较多少趟
            for (int begin = 1; begin <= end; begin++){
    
    //每一趟中的最大元素
                if (array[begin] < array[begin - 1]){
    
    
                    int tmp = array[begin];
                    array[begin] = array[begin - 1];
                    array[begin - 1] = tmp;
                }
            }
        }
        //输出打印
        for (int i = 0; i < array.length; i++){
    
    
            System.out.println(array[i] + "_");
        }
    }

代码优化①

  • 如果序列已经完全有序,可以提前终止冒泡排序
  • 增加一个boolean值,用于判断每一个循环后是否有数据交换,如果没有,则退出排序。说明数组元素是有序的。
  • 如果数据不是完全有序,此优化会因添加成员变量而导致计算时间更长
public class BubbleSort2 {
    
    
    public static void main(String[] args) {
    
    
        int[] array = {
    
    1,9,19,28,31,34,35};
        //end > 0为终止条件,只有end > 0,也即是说,end为1的时候,它还可以和它前面的进行比较
        //end为0时,它前面就没有元素了
        for (int end = array.length - 1; end > 0; end--){
    
    //一共比较多少趟
            // 这个变量写在这里,是为了判断每一趟排序操作是否将序列变为完全有序.
            // 因为有可能在某一趟之后, 数组的元素就变为完全有序了
            boolean sorted = false; // 是否排过序
            for (int begin = 1; begin <= end; begin++){
    
    //每一趟中的最大元素
                if (array[begin] < array[begin - 1]){
    
    
                    int tmp = array[begin];
                    array[begin] = array[begin - 1];
                    array[begin - 1] = tmp;
                    sorted = true;  // 排过序
                }
            }
            if (!sorted) break;
        }
        for (int i = 0; i < array.length; i++){
    
    
            System.out.println(array[i] + "_");
        }
    }
}

代码优化②

  • 如果序列尾部已经局部有序,可以记录最后一次交换的位置,减少比较次数。
  • 记录上一次循环最后一次交换的位置,将其作为下一次循环的截止位置。
public class BubbleSort3 {
    
    
    public static void main(String[] args) {
    
    
        int[] array = {
    
    10,9,19,28,37,34,5};
        //end > 0为终止条件,只有end > 0,也即是说,end为1的时候,它还可以和它前面的进行比较
        //end为0时,它前面就没有元素了
        for (int end = array.length - 1; end > 0; end--){
    
    //一共比较多少趟
            // sortedIndex=1,是针对完全有序的情况: 因为完全有序下,就不会走到下面的if判断. 所以初始值给1. 最后end=1,一轮扫描就结束了
            int sortedIndex = 1; // 从哪个索引开始,后面的都已经排好序了
            for (int begin = 1; begin <= end; begin++){
    
    //每一趟中的最大元素
                // 如果不进入下面的判断,表示本轮循环肯定是有序的
                if (array[begin] < array[begin - 1]){
    
    
                    int tmp = array[begin];
                    array[begin] = array[begin - 1];
                    array[begin - 1] = tmp;
                    // 记录最后一次交换的位置
                    sortedIndex = begin;
                }
            }
            // 将最后一次交换的位置,给end, 作为下次循环的终点
            end = sortedIndex;
        }

        for (int i = 0; i < array.length; i++){
    
    
            System.out.println(array[i] + "_");
        }
    }
}

复杂度

最坏时间复杂度O(n^2)

最好时间复杂度O(n)

平均时间复杂度O(n^2)

空间复杂度O(1)

排序算法的稳定性(Stability)

  • 如果相等的2个元素,在排序前后的相对位置保持不变,那么这是稳定的排序算法。
  • 排序前:5,1,3a,4,7,3b
  • 稳定的排序:1,3a,3b,4,5,7
  • 不稳定的排序:1,3b,3a,4,5,7
  • 对自定义对象进行排序时,稳定性会影响最终的排序效果。
  • 冒泡排序属于稳定的排序算法。
  • 因为冒泡排序过程中, 两个相同的元素根本就不会比较, 只有左边的元素 > 右边的元素才会进行交换排序。所以冒泡排序是稳定的排序。
  • 但是在比较大小时,如果加了等于“=”,那这样的冒泡排序代码就是不稳定的

原地算法(In-place Algorithm)

  • 不依赖额外的资源或依赖少数的额外资源,仅依靠输出来覆盖输入。
  • 空间复杂度为O(1)的都可以认为是原地算法。
  • 非原地算法,称为Not-in-place或者Out-of-place。
  • 冒泡排序属于In-place。

猜你喜欢

转载自blog.csdn.net/weixin_42871468/article/details/114265725