冒泡排序的优化

本文详细介绍了冒泡排序的基本原理及其实现方式,并进一步探讨了两种优化方案:一是通过增加有序标记来提前结束排序;二是记录最后一次元素交换的位置,减少不必要的比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在面试的时候我们经常会被问到排序,比如有插入排序,冒泡排序等等,我们今天就讲下冒泡排序以及优化。
一想到冒泡排序马上就会想起使用双循环来实现:
先定义一个数组 int[] array = {3,4,2,1,5,7,6};
然后定义方法
public static void sort1(int[] array){
int temp;
for(int i=0;i<array.length-1;i++){
for(int j=0;j<array.length-1-i;j++){
if(array[j]>array[j+1]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
}
}
System.out.println(Arrays.toString(array));
}
}
这样就是我们最常见的冒泡排序,但是通过每次排完需,我们会发现有点问题,比如上面这个方法的执行过程:
[3, 2, 1, 4, 5, 6, 7]
[2, 1, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]

我们会发现从第4次开始,后面每次打印的都是一样的结果,这显然效率不高,既然这样,那肯定可以优化的。
我们先观察下排序后的结果,第一次排序后的结果是:
[3, 2, 1, 4, 5, 6, 7]
在排序的过程中,第j 都会和第j+1位做比较,这其实是可以不用这样的,
我们可以加个标记,也就是在第一个for循环中加个标记,标记当前是否是有序数组,若是,则跳出循环;
我们在定义一个方法,对刚才的排序进行优化:
public static void Optimize1(int array[]){
int temp=0;
for(int i=0;i<array.length;i++){
//有序标记,每一轮的初始是true
boolean isSorted = true;
for(int j=0;j<array.length-i-1;j++){
if(array[j] > array[j+1]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
//有元素交换,所以不是有序,标记为false
isSorted = false;
}
}
if(isSorted){
break;
}
System.out.println(Arrays.toString(array));
}
}
排序的执行过程如下:
[3, 2, 1, 4, 5, 6, 7]
[2, 1, 3, 4, 5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
只执行了三次就排好了,这比第一种方法效率要高;
但是这还不是最高效的,我们再观察下,发现第一次排完序后
[3, 2, 1, 4, 5, 6, 7]
4,5,6,7 已经是一个有序数列了,那可不可以这样,每次排完序后,标记最后一次排序的位置,下次再对比的时候,只要对比到上次
最后的一个位置即可,因为上次排完序后的最后一个位置开始,到数组完,一定是一个有序数列。
所以冒泡排序最优版如下:
public static void sort(int array[]){
int temp =0;
//记录每次最后一次交换的位置
int lastExchangeIndex =0;
//无序数列边界,每次比较只需比到这里为止
int sortBorder = array.length-1;
for(int i=0;i<array.length;i++){
//有序标记,每一轮的初始是true
boolean isSorted = true;
for(int j=0;j<sortBorder;j++){
if(array[j]>array[j+1]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
//有元素交换,所以不是有序,标记为false
isSorted = false;
//把无序数列的边界更新为最后一次元素交换的位置
lastExchangeIndex = j;
}
}
//更新无序数列边界
sortBorder = lastExchangeIndex;
if(isSorted){
break;
}
System.out.println(Arrays.toString(array));
}
}
### 冒泡排序优化方法 #### 基本冒泡排序回顾 基本的冒泡排序是一种简单的排算法,它重复地遍历要排的列表,依次比较相邻元素并根据需要交换它们的位置。这个过程会持续进行直到没有再发生任何交换操作为止。 然而,在某些情况下,即使数组已经部分或完全有,传统的冒泡排序仍将继续不必要的迭代。为了提高效率,可以通过记录最后发生交换的位置来减少后续遍历范围[^1]。 #### 鸡尾酒排(双向冒泡) 一种常见的改进版本称为鸡尾酒排,也叫做双向冒泡排序。这种变体不仅从左向右扫描未排的部分,还会反过来从右往左再次扫描一次。这种方法可以在一定程度上加快接近中间位置较大数值移动的速度,从而可能更快达到稳定状态[^2]。 ```python def cocktail_sort(arr): n = len(arr) swapped = True start = 0 end = n - 1 while (swapped == True): # reset the swapped flag on entering the loop, # because it might be true from a previous iteration. swapped = False # loop from bottom to top same as bubble sort for i in range(start, end): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i] swapped = True # if nothing moved, then array is sorted. if not(swapped): break # otherwise, reset the swapped flag so that it can be used in the next stage swapped = False # move the end point back by one, because item at the end is in its rightful spot end -= 1 # from top to bottom, doing the same comparison as in the previous stage for i in range(end - 1, start - 1, -1): if arr[i] > arr[i + 1]: arr[i], arr[i + 1] = arr[i + 1], arr[i] swapped = True # increase the starting point, because last stage would have moved the next largest number to its rightful spot. start += 1 ``` #### 记录最后一次交换位置 另一种有效的策略是在每次内层循环结束后保存最后一个发生了交换的地方,并将其设为下次外层循环的最大边界。这样做的好处是可以显著缩短剩余处理的数据长度,尤其是在几乎已排情况下效果更佳[^3]。 ```python def optimized_bubble_sort(arr): n = len(arr) new_n = n while new_n > 0: last_swap_index = 0 for i in range(1, new_n): if arr[i - 1] > arr[i]: arr[i - 1], arr[i] = arr[i], arr[i - 1] last_swap_index = i new_n = last_swap_index ``` 通过这些技术的应用,可以使经典的冒泡排序变得更加高效,特别是在面对特定类型的输入数据集时能够表现出更好的性能特性[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值