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

目录

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;iarr[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 ; i0 ; j--) {
				//以升序为例
				if(arr[j]

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 ; iarr[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 ; iarr[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)

 

你可能感兴趣的:(算法,java)