1、基本思想
冒泡排序的基本思想是通过反复比较相邻的元素并交换它们的位置,将最大(或最小)的元素逐步 “冒泡” (移动)到数组的一端。就好像水中的气泡,较轻的气泡会逐渐往上浮,在排序中,较大(或较小)的值会逐渐移到数组的合适位置。
2、算法步骤
2.1、算法步骤描述:
排序前:
假设有一个包含 n 个元素的数组 arr,需要对其进行排序(这里以升序排序为例,若要实现降序排序,只需将比较条件反转即可)。
第一轮排序:
1、从数组的第一个元素 arr [0] 开始,比较相邻的两个元素,即比较 arr [0] 和 arr [1]。如果 arr [0] 大于 arr [1],那么就交换这两个元素的位置,使得较小的元素在前,较大的元素在后。如果 arr [0] 小于或等于 arr [1],则不进行交换,继续比较下一对相邻元素。
2、接着比较 arr [1] 和 arr [2],按照上述比较和交换的规则进行操作。
3、以此类推,依次比较 arr [2] 和 arr [3]、arr [3] 和 arr [4]…… 直到比较完 arr [n - 2] 和 arr [n - 1]。
4、经过这一轮对数组中所有相邻元素的比较和交换操作后,数组中最大的元素就会 “冒泡” 到数组的末尾,即 arr [n - 1] 的位置。
第二轮排序:
1、由于第一轮排序已经确定了数组中的最大元素在末尾位置,所以在第二轮排序时,只需对数组中除了最后一个元素(也就是已经排好序的最大元素)之外的剩余 n - 1 个元素进行操作。
2、同样从第一个元素开始,即比较 arr [0] 和 arr [1],根据比较结果决定是否交换。
3、以此类推,依次比较 arr [1] 和 arr [2]、arr [2] 和 arr [3]…… 直到比较完 arr [n - 3] 和 arr [n - 2]。
4、经过这一轮排序后,剩余元素中的最大元素会被移动到当前剩余元素的末尾,也就是 arr [n - 2] 的位置。
重复操作:
…… 以此类推,进行多轮排序
每一轮排序都会将当前剩余元素中的最大元素移动到当前剩余元素的末尾,并且每一轮排序所针对的剩余元素数量会比上一轮少 1 个。
最后一轮排序:
当进行到第 n - 1 轮排序时(因为总共 n 个元素,经过 n - 1 轮排序就能确定所有元素的位置,最后只剩一个元素没有排,一定有序),此时只需对数组中的前两个元素 arr [0] 和 arr [1] 进行比较和交换操作(如果需要的话)。
排序后:
经过上述 n - 1 轮的排序操作后,整个数组就完成了排序,所有元素按照升序排列在数组中。总结来说,冒泡排序就是通过不断地比较相邻元素并根据需要进行交换,逐轮将数组中的最大元素移动到数组的末尾,直到整个数组排序完成。
2.2、冒泡排序算法动态演示图:
动态演示图来源网站URL:https://visualgo.net
3、代码实现
C语言代码实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define N 10
int main(int argc, char *argv[])
{
srand(time(NULL));
int a[N];
int i, j, t, flag = 1;
puts("排序前数组为:");
for(i = 0; i < N; i++)
{
a[i] = rand()%100;//为数组随机赋值
printf("%d ",a[i]);//显示排序之前数组的值
}
puts("");
for(int i = 0; i < N - 1; i++)//排序的轮数
{
flag = 1;//重置n
for(int j = 0; j < N - i -1; j++)//每次排序的次数
{
if(a[j] > a[j+1])//交换条件
{
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
flag = 0;//如果发生了交换,就证明本轮还没有完成排序
}
}
if(flag == 1)//此时,n = 1证明这一轮中都没有发生过交换,那么可知此时数组是有序的
{
puts("排序后的数组为:");
for(int i = 0; i < N; i++)//提前输出
{
printf("%d ",a[i]);
}
puts("");
return 0;
}
}
puts("排序后的数组为:");
for(int i = 0; i < N; i++)
{
printf("%d ",a[i]);
}
puts("");
return 0;
}
4、时间复杂度和空间复杂度
平均时间复杂度:O(n^2)
空间复杂度:O(1)
稳定性:稳定
5、适用情况
适用于数据量较小且对排序速度要求不高的情况下。