1.原理
比较两个相邻的元素,将值大的元素交换至右端。
2.思路
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,
将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,
直至比较最后两个数,将小数放前,大数放后。重复第一趟步骤,直至全部排序完成。
分析:N个数字要排序完成,总共进行N-1趟排序,每i趟的排序次数为(N-i)次,
所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
3.代码实现
/**
* 算法一
*/
public int[] bubbleSort(int[] arr){
for (int i = 0; i < arr.length - 1; i++) {
System.out.println("第"+(i+1)+"次排序");
for (int j = 0; j < arr.length - 1 - i; j++) {
System.out.println(arr[j] +" 和 "+arr[j+1]+" 比较");
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.print("第"+(i+1)+"次排序后:");
printArr(arr);
System.out.println();
}
return arr;
}
/**
* 冒泡排序优化算法1
* 设置一个标志,如果这一趟发生了交换,则为true,否则为false。
* 明显如果有一趟没有发生交换,说明排序已经完成。
* @param arr
* @return
*/
public int[] bubbleSort1(int[] arr){
int n = arr.length - 1;
boolean flag = true;
for (int i = 0; i < n; i++) {
System.out.println("第"+(i+1)+"次排序");
if(!flag){
continue;
}
flag = false;
for (int j = 0; j < n - i; j++) {
System.out.println(arr[j] +" 和 "+arr[j+1]+" 比较");
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = true;
}
}
System.out.print("第"+(i+1)+"次排序后: ");
printArr(arr);
System.out.println();
}
return arr;
}
/**
* 现在有一个包含1000个数的数组,仅前面100个无序,后面900个都已排好序且都大于前面100个数字
* 那么在第一趟遍历后,最后发生交换的位置必定小于100,且这个位置之后的数据必定已经有序了,也就是这个位置以后的数据
* 不需要再排序了,于是记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。如果是对于上面的冒泡排序算法2来说,
* 虽然也只排序100次,但是前面的100次排序每次都要对后面的900个数据进行比较,而对于现在的排序算法3,
* 只需要有一次比较后面的900个数据,之后就会设置尾边界,保证后面的900个数据不再被排序。
* 冒泡排序优化算法2
*/
public int[] bubbleSort2(int[] arr){
int flag = arr.length - 1;
int i = 0;
while (flag > 0){
int k = flag;
System.out.println("尾边界值: "+k);
System.out.println("第"+(i+1)+"次排序");
flag = 0;
for (int j = 0; j < k; j++) {
System.out.println(arr[j] +" 和 "+arr[j+1]+" 比较");
if(arr[j] > arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
flag = j + 1;
}
}
System.out.print("第"+(i+1)+"次排序后: ");
printArr(arr);
System.out.println();
i++;
}
return arr;
}
4.测试
@Test
public void test(){
int arr[] = {6,3,8,2,9,1};
System.out.println("排序前");
printArr(arr);
int[] data = bubbleSort2(arr);
System.out.println("排好序后");
printArr(data);
}
public void printArr(int[] arr){
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i]+" ");
}
System.out.println();
}
5.总结
冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。
如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较
除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,
第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,
每进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。
用时间复杂度来说:
1.如果我们的数据正序,只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值,
即:Cmin=n-1;Mmin=0;所以,冒泡排序最好的时间复杂度为O(n)。
2.如果很不幸我们的数据是反序的,则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),
且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
冒泡排序的最坏时间复杂度为:O(n2)。
综上所述:冒泡排序总的平均时间复杂度为:O(n2)。