排序算法-02冒泡排序

冒泡排序

1. 算法概述

冒泡排序是一种简单的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。

2. 算法原理

  1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个(将大的那一个元素往后移动,小的元素往前移动)。
  2. 从开始第一对,到最后一对,依次比对每一次相邻元素,重复1的操作,这样执行完成后,最后的元素应该是最大的数。
  3. 重复上述步骤,除了前几次已经排序好的大数。即前几次每次排序的最大数
  4. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。

3. 动图演示

image

4. 代码实现

@Test
public void dubbleSort() {
    int[] arr = new int[]{18, 34, 33, 30, 20};
    log.info("sort before:{}", JSON.toJSON(arr));
    //外循环,为什么length-1?因为:内循环会遍历每一个元素,进行两两比较,内循环每循环结束一次,会有一个最大值排在末尾索引
    //所以外循环可以-1,减少一次空循环
    for (int i = 0; i < arr.length - 1; i++) {
        //内循环,为什么length-i-1,因为:内循环每循环结束一次(即外循环次数:i),就会产生一个最大值排在末尾索引
        //所以,内循环不再判断本次之前选举的最大值,这就是length-i
        //又因为:内循环会判断本次循环索引j和之后一个索引位置j+1的元素进行对比,外循环第一次轮训,内循环会全部执行
        //则当内循环在对比最后一位元素时,会出现索引越界异常ArrayIndexOutOfBoundsException
        //所以内循环判断条件为length-i-1,同时也防止上一次最大值重复比对。
        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;
            }
        }
    }
    log.info("sort after:{}", JSON.toJSON(arr));
}

5. 算法优化

5.1 减少非必要的比较

在某些时候,循环还未终止,整个数组已经排好序,此时应及时终止循环。(冒泡每次都会比较相邻两个数并交换次序不对的组,若一次循环后,都没进行交换,则已经完成排序)。

代码实现如下:

@Test
public void bubbleSort1() {
    int[] arr = new int[]{18, 20, 30, 34, 33};
    log.info("sort before:{}", JSON.toJSON(arr));
    for (int i = 0; i < arr.length - 1; i++) {
        //内循环执行完后,未发生交换,则证明顺序已经排序完成
        boolean bool = true;
        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;
                bool = false;
            }
        }
        //如未发生交换,则退出循环
        if (bool) {
            break;
        }
    }
    log.info("sort after:{}", JSON.toJSON(arr));
}

5.2 鸡尾酒排序(双向冒泡排序)

鸡尾酒是冒泡排序的升级版,该排序从左往右找出最大值后。再从右往左,找出最小值,类似鸡尾酒搅拌左右循环。在某些情况下,优于冒泡排序。

以序列(2,3,4,5,1)为例,鸡尾酒排序只需要访问两次(升序降序各一次 )次序列就可以完成排序,但如果使用冒泡排序则需要四次。

初始数组:{8,2,3,1,9}
第一次排序:
	从头到尾,将大数排在数组尾部
		第 1 次比较:8>2 交换位置:{8,2,3,1,9} -> {2,8,3,1,9}
		第 2 次比较:8>3 交换位置:{2,8,3,1,9} -> {2,3,8,1,9}
		第 3 次比较:8>1 交换位置:{2,3,8,1,9} -> {2,3,1,8,9}
		第 4 次比较:8<9 不做处理:{2,3,1,8,9}
	从尾到头,因9的排序位置已经确认,所以忽略9,从8开始,将小数排在数组头部
		第 1 次比较:8>1 不做处理:{2,3,1,8,9}
		第 2 次比较:1<3 交换位置:{2,3,1,8,9} -> {2,1,3,8,9}
		第 3 次比较:1<2 交换位置:{2,1,3,8,9} -> {1,2,3,8,9}
		此时:最小的数值已经排序出来
第二次排序:
	从头到尾,将大数排在数组尾部,因1的排序位置已经确认,所以忽略1,从2开始,将大数排在数组尾部
		第 1 次比较:2<3 不做处理:{1,2,3,8,9}
		第 2 次比较:3<8 不做处理:{1,2,3,8,9}
至此,排序完成

代码实现如下:

 public void bubbleSort3() {
     int[] arr = new int[]{2, 3, 4, 5, 1};
     log.info("sort before:{}", JSON.toJSON(arr));

     //从头到尾,再从尾到头,为一次完整回合,所以,做多遍历 arr.length / 2 次
     for (int i = 0; i < arr.length >>> 1; i++) {
         boolean bool = true;
         //每一回合,都会选举出来两个值,一个是相对最小,一个相对最大。为了进行浪费操作,所以要减去外层循环的次数 -i
         for (int l2h = i; l2h < arr.length - i - 1; l2h++) {
             if (arr[l2h] > arr[l2h + 1]) {
                 swap(arr, l2h, l2h + 1);
                 bool = false;
             }
         }
         if (bool) {
             break;
         } else {
             bool = true;
         }

         //arr.length - 2 - i = arr.length - 1 - (i + 1)
         //同上,arr.length-1-i 为上面循环选定的最大值,需要向前推一位 即 -(i+1)
         for (int h2l = arr.length - 2 - i; h2l > i; h2l--) {
             swap(arr, h2l, h2l - 1);
             bool = false;
         }
         if (bool) {
             break;
         }
     }
     log.info("sort after:{}", JSON.toJSON(arr));
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值