冒泡排序概念
冒泡排序是一种计算机科学领域的较简单的排序算法。
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。走访元素的工作是重复地进行,直到没有相邻元素需要交换,也就是说该元素列已经排序完成。
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。
冒泡排序原理
1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。
2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。在这一点,最后的元素应该会是最大的数
3.针对所有的元素重复以上的步骤,除了最后一个。
4.持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
冒泡排序流程图
![](https://i-blog.csdnimg.cn/blog_migrate/e9d8665cfbe03b6a1529d148f5dff334.jpeg)
冒泡排序复杂度
时间复杂度(最优) | O(n) |
时间复杂度(最坏) | O(n^2) |
时间复杂度(平均) | O(n^2) |
空间复杂度 | O(1) |
稳定性 | 稳定 |
平均复杂度的计算
循环 | 比较次数 |
第一次 | (n-1) |
第二次 | (n-2) |
第三次 | (n-3) |
...... | ...... |
最后一次 | 1 |
比较次数为:
(n-1) + (n-2) + (n-3) +.....+ 1 = n(n-1)/2
冒泡排序伪代码
for(开始的索引i=0; i <数组的长度;i++) {
for(剩余未排序的索引j=0; j < 当前未排序的长度; j++) {
if(数组[j]>数组[j+1]) {
数组[j] 跟 数组[j+1] 调换位置
}
}
}
普通的冒泡排序
最简单的冒泡
数组:3,8,14,16,32,53
public static void bubbleSort(int[] array){
for(int i=0;i<array.length-1;i++){//控制比较轮次,一共 n-1 趟
int num = 0; //用来记录比每轮比较的次数
for(int j=0;j<array.length-1;j++){//控制两个挨着的元素进行比较
if(array[j] > array[j+1]){
//换位
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
//比较一次,加1
num =num+1;
}
//结果输出
System.out.print("第"+(i+1)+"轮:[");
for (int a=0;a<array.length; a++){
if(a!=array.length-1)
{
System.out.print(array[a]+",");
}else{
System.out.print(array[a]+"]");
}
}
System.out.println(",比较了:"+num+" 次");
}
}
结果
第1轮结果:[3,14,16,32,8,53],每轮比较了:5 次
第2轮结果:[3,14,16,8,32,53],每轮比较了:5 次
第3轮结果:[3,14,8,16,32,53],每轮比较了:5 次
第4轮结果:[3,8,14,16,32,53],每轮比较了:5 次
第5轮结果:[3,8,14,16,32,53],每轮比较了:5 次
每一轮都比较了五次,但是到后面的比较,有一部分已经是排好了,如果某个数比他的下一个位置还小, 就没有必要和后面已经排好的数据再做比较。 比如第四轮,8和14比较,换位之后,16,32,53都已经排好了,14再和16比较,不用换位,那16之后的数据已经在第三轮排好,就没必要再比较16和32,32和53了。
普通的冒泡
我们就在程序内层循环做一个限制,每轮比较之后,下一轮就比较到array.length-1-i的位置。就是第一轮6位数都比较完成,最大排在最后,第二轮就比较前五个数,把前五个数中最大的排在第五位。这样以此类推,就可以减少程序中无用的比较。
public static void bubbleSort(int[] array){
for(int i=0;i<array.length-1;i++){//控制比较轮次,一共 n-1 趟
int num = 0; //用来记录比每轮比较的次数
for(int j=0;j<array.length-1-i;j++){//控制两个挨着的元素进行比较
if(array[j] > array[j+1]){
//换位
int temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
//比较一次,加1
num =num+1;
}
//结果输出
System.out.print("第"+(i+1)+"轮:[");
for (int a=0;a<array.length; a++){
if(a!=array.length-1)
{
System.out.print(array[a]+",");
}else{
System.out.print(array[a]+"]");
}
}
System.out.println(",比较了:"+num+" 次");
}
}
冒泡排序1.0
优化轮次。
在经历过几轮比较交换后,剩下的数据不用在比较。我们可以用一个标志位来判断比较的结束。
for (int i = 0; i <arr.length-1; i++) { //i 轮数
System.out.println("目前是第"+(i+1)+"轮比较");
//标志位
boolean flag = true;
for (int j = 0; j <arr.length-1-i ; j++) { //j 次数
System.out.println("第"+(i+1)+"轮,第"+(j+1)+"次比较");
//交换的条件
if(arr[j] > arr[j+1]){
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
flag = false;
}
}
//输出当前轮次比较的结果
System.out.println(Arrays.toString(arr));
//当不再发生交换时,则结束比较
if(flag){
break;
}
}
//输出
System.out.println("排序后:"+Arrays.toString(arr));
冒泡排序2.0
假如数组为int[] arr = {4,6,3,7,8,9,10};
有一半的数据都不用再排序,应该
//定义一个作为比较的边界
int position = arr.length-1;
for (int i = 0; i <arr.length-1; i++) { //i 轮数
System.out.println("目前是第"+(i+1)+"轮比较");
//标志位
boolean flag = true;
//记录最后交换位置的值
int limit = 0;
for (int j = 0; j <position ; j++) { //j 次数
System.out.println("第"+(i+1)+"轮,第"+(j+1)+"次比较");
//交换的条件
if(arr[j] > arr[j+1]){
int temp = arr[j+1];
arr[j+1] = arr[j];
arr[j] = temp;
flag = false;
limit = j;
}
}
position = limit;
//输出当前轮次比较的结果
System.out.println(Arrays.toString(arr));
//当不再发生交换时,则结束比较
if(flag){
break;
}
}
//输出
System.out.println("排序后:"+Arrays.toString(arr));
}