排序算法(二):冒泡排序算法及其优化分析

8 篇文章 0 订阅

目录

1.冒泡排序算法:

2.算法优化分析:

2.1优化外层循环

2.2优化内层循环

2.3同时优化内层和外层循环

3.时间复杂度分析:

3.1优化前

3.2优化后

4.空间复杂度分析:


1.冒泡排序算法:

原理:以N个元素数组的升序为例。相邻元素两两比较,大的往后放,第一轮完毕,最大值出现在了最大索引处,即数组最右侧。每一轮都从头开始执行,总共执行 N-1 轮。

代码书写分析:需要两层循环。第一层表示轮次,从第一个元素开始,相邻元素两两比较,大的往后放。每遍历一轮,进入第二层循环,在此从头开始,确定最大值后放在最大索引处,每遍历一轮最大索引值 -1。直到排序完成。

public class BubbleSort {
	public static void swap(int[] arr,int i,int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	/**
	 * 冒泡排序:
	 * isAsc:true 升序    ;false  降序
	 * @param arr
	 * @param isAsc
	 */
	public static void bubbleSort(int[] arr,boolean isAsc) {
		for(int i=0;i<arr.length-1;i++) {  //轮次:数组长度减一
			for(int j=0;j<arr.length-i-1;j++) {  //遍历数组索引(第一次遍历到倒数第二个元素,之后每轮减一)
				if(isAsc == true) {
					if(arr[j]<arr[j+1]) {   //相邻元素对比,符合规则交换位置
						swap(arr,j,j+1);
					}
				}else {
					if(arr[j]>arr[j+1]) {
						swap(arr,j,j+1);
					}
				}
			}
		}
	}
}

2.算法优化分析:

2.1优化外层循环

正常情况下,冒泡排序算法的外层循环需要进行N-1轮,但如果在某一轮结束后数组排序完成,这个时候就可以提前退出外层循环,这就是冒泡排序外层循环优化的基本思路,如下所示:

原始数组      2   1   3   5   6   4

一轮循环      1   2   3   5   4   6

二轮循环      1   2   3   4   5   6

正常情况下,数组需要进行5轮外层循环,但两轮就已经排序完成。因此可以在第三轮未发生交换的情况下,设置一个标志。作为结束外层循环的标志。

public class BubbleSort_Opt {
	
	public static void swap(int[] arr,int i,int j) {
		int temp = 0;
		temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	public static void bubbleSort(int[] arr) {
				
		for(int i=0 ; i<arr.length-1 ; i++) {

            int flag = 0;  //设置循环结束标志
			for(int j=arr.length-1 ; j>0 ; j--) {
				//以升序为例
				if(arr[j]<arr[j-1]) {
					swap(arr,j,j-1);
					flag = 1;  //发生交换则对标志变量重新赋值
				}
			}
			//内层循环完成后,判断上一轮是否发生元素交换。未交换元素,则表示排序完成,提前退出。
			if(flag == 0) {
				return;
			}
		}
	}
}

2.2优化内层循环

冒泡排序算法是相邻元素两两比较,经过一轮就可以将最大的元素防止数组尾部。但是如果相邻元素有序的话则不发生交换。因此在最后交换位置前面为无序区,需要继续循环比较;而最后交换位置后面则为有序区,下一轮可以只遍历无序区即可。因此可以将最后交换位置的索引值赋给一个变量,作为内层循环结束的标志,这样可以提前结束内层循环。具体原理如下所示:

原始数组   3   2   1   4   6   7

一轮交换   2   1   3   4   6   7

二轮交换   1   2   3   4   6   7

public class BubbleSort_Opt {
	
	public static void swap(int[] arr,int i,int j) {
		int temp = 0;
		temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	public static void bubbleSort(int[] arr) {
		
		int pos = 0;
		int temp = arr.length-1;
		
		for(int i=0 ; i<arr.length-1 ; i++) {
			for(int j=0 ; j<temp ; j++) {
				//以升序为例
				if(arr[j]>arr[j+1]) {
					swap(arr,j,j+1);
					
					pos = j ;  //记录最后的交换位置,换分有序区与无序区
				}
			}
			temp = pos;   //将最后的交换位置作为内层循环结束标志
		}
	}
}

2.3同时优化内层和外层循环

public class BubbleSort_Opt {
	
	public static void swap(int[] arr,int i,int j) {
		int temp = 0;
		temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
	
	public static void bubbleSort(int[] arr) {
		
		int pos = 0;
		int temp = arr.length-1;
		
		for(int i=0 ; i<arr.length-1 ; i++) {
            int flag = 0;  //设置外层循环结束标志
			for(int j=0 ; j<temp ; j++) {
				//以升序为例
				if(arr[j]>arr[j+1]) {
					swap(arr,j,j+1);
					
					flag = 1;  //发生交换则对标志变量重新赋值
					pos = j ;
				}
			}
			//将最后交换位置作为内层循环结束的标志
			temp = pos;
			//内层循环完成后,判断上一轮是否发生元素交换。未交换元素,则表示排序完成,提前退出外层循环。
			if(flag == 0) {
				return;
			}
		}
	}
}

3.时间复杂度分析:

3.1优化前

对于元素个数为N的数组:

1.第一轮从第一个元素开始,相邻元素进行对比,需要比较 (N-1) 次,考虑均交换的情况是 3(N-1),之后最值放在最大索引处,同时维护最大索引值(最大索引值-1);

2.第二轮从也第一个元素开始,相邻元素进行对比,需要比较 (N-2) 次,考虑均交换的情况是 3(N-2),之后最值放在最大索引处,同时维护最大索引值(最大索引值-1);

......

3.总共循环 (N-1)轮

注:复杂度与数组是否有序无关,每轮都需要遍历才能找到最大/最小值,最好,最坏或平均时间复杂度均为O(N^2)

3.2优化后

对于近乎有序的数组,优化后的冒泡排序会提前结束循环。因此它的时间复杂度会降低很多。

1.对于有序数组,它在进行一轮遍历后就会提前结束,最佳的时间复杂度为O(N);

2.对于逆序数组,它需要进行N-1轮的遍历,因此最差的时间复杂度为O(N^2);

3.平均的时间复杂度为O(N^2);

4.空间复杂度分析:

冒泡排序属于原位排序,无论是否进行优化,其需要的临时变量都在个位数以内。因此冒泡排序算法的空间复杂度为 O(1)

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值