冒泡排序的实际应用场景有:1、数据库查询;2、数字图像处理;3、传感器数据采集;4、小规模数据排序;5、从高到低列队。数据库查询是指冒泡排序可用于对数据库中的数据进行排序。
一、冒泡排序有什么实际应用场景
1、数据库查询
冒泡排序可用于对数据库中的数据进行排序,对于小规模数据集,冒泡排序的速度也足够快。
2、数字图像处理
冒泡排序可用于处理数字图像中的像素点,比如对像素点的灰度值进行排序,从而得到更清晰、更准确的图像。
3、传感器数据采集
在传感器采集的数据中,可能会出现一些异常点或者噪声,使用冒泡排序可以将这些异常值筛选出来,并快速进行处理。
4、小规模数据排序
如,4个数进行排序时,通常手动写6次比较的冒泡排序。
void cs(int &a, int &b) { // 对a和b进行比较、交换
if(a > b) {
int t = a;
a = b;
b = t;
}
}
// 调用
cs(a, b);
cs(b, c);
cs(c, d);
cs(a, b);
cs(b, c);
cs(a, b);
5、从高到低列队
生活中,我们在集体活动中站队时,名列前茅次站队由于没有固定的位置,往往是大家先随便站成一排,然后再通过换位置的方式逐步形成高矮顺序,这里主要是冒泡的思想。
二、冒泡排序(Bubble Sort)
1、基本思想
冒泡排序是一种交换排序,核心是冒泡,把数组中最小的那个往上冒,冒的过程就是和他相邻的元素交换。
重复走访要排序的数列,通过两两比较相邻记录的排序码。排序过程中每次从后往前冒一个最小值,且每次能确定一个数在序列中的最终位置。若发生逆序,则交换;有俩种方式进行冒泡,一种是先把小的冒泡到前边去,另一种是把大的元素冒泡到后边。
趣味解释:
有一群泡泡,其中一个泡泡跑到一个泡小妹说,小妹小妹你过来咱俩比比谁大,小妹说哇你好大,于是他跑到了泡小妹前面,又跟前面的一个泡大哥说,大哥,咱俩比比谁大呗。泡大哥看了他一眼他就老实了。这就是内层的for,那个泡泡跟每个人都比一次。
话说那个泡泡刚老实下来,另一个泡泡又开始跟别人比谁大了,这就是外层的for,每个泡泡都会做一次跟其他泡泡比个没完的事。
2、实现逻辑
- 比较相邻的元素。如果名列前茅个比第二个大,就交换他们两个。
- 对每一对相邻元素作同样的工作,从开始名列前茅对到结尾的最后一对。在这一点,最后的元素应该会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
通过两层循环控制:
- 名列前茅个循环(外循环),负责把需要冒泡的那个数字排除在外;
- 第二个循环(内循环),负责两两比较交换。
3、性能分析
- 平均时间复杂度:O(N^2)
- 优异时间复杂度:O(N)
- 最差时间复杂度:O(N^2)
- 空间复杂度:O(1)
- 排序方式:In-place
- 稳定性:稳定
5、代码实现
// 冒泡排序(C++)
void bubble_sort(int arr[], int len)
{
int i, j;
for (i = 0; i < len; i++)
for (j = 1; j < len - i; j++)
if (arr[j - 1] > arr[j])
swap(arr[j - 1], arr[j]);
}
6、优化改进
场景一:
在某次遍历中如果没有数据交换,说明整个数组已经有序。若初始序列就是排序好的,如果用基础的冒泡排序方法,仍然还要比较O(N^2)次,但无交换次数。
改进思路:
通过设置标志位来记录此次遍历有无数据交换,进而可以判断是否要继续循环,设置一个flag标记,当在一趟序列中没有发生交换,则该序列已排序好,但优化后排序的时间复杂度没有发生量级的改变。
改进代码:
// 冒泡排序改进(C++)
void bubble_sort(int arr[], int len)
{
for (int i = 0; i < len-1; i++){ //比较n-1次
bool exchange = true; //冒泡的改进,若在一趟中没有发生逆序,则该序列已有序
for (int j = len-1; j >i; j--){ //每次从后边冒出一个最小值
if (arr[j] < arr[j - 1]){ //发生逆序,则交换
swap(arr[j], arr[j - 1]);
exchange = false;
}
}
if (exchange){
return;
}
}
}
场景二:
如果有100个数的数组,仅前面10个无序,后面90个都已排好序且都大于前面10个数字,那么在名列前茅趟遍历后,最后发生交换的位置必定小于10,且这个位置之后的数据必定已经有序了。
改进思路:
记录某次遍历时最后发生数据交换的位置pos,这个位置之后的数据显然已经有序了。因此通过记录最后发生数据交换的位置就可以确定下次循环的范围了。由于pos位置之后的记录均已交换到位,故在进行下一趟排序时只要扫描到pos位置即可。
改进代码:
// 冒泡排序改进
void bubble_sort(int arr[], int len)
{
int j, k;
int flag;
flag = len;
while (flag > 0)
{
k = flag;
flag = 0;
for (j = 1; j < k; j++)
if (arr[j - 1] > arr[j])
{
swap(arr[j - 1], arr[j]);
flag = j;
}
}
}
延伸阅读1:常用排序算法
- 直接插入排序
- 折半插入排序(二分插入排序)
- 希尔排序
- 冒泡排序
- 快速排序
- 直接选择排序
- 堆排序
- 归并排序
- 基数排序