算法背景
冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复地进行直到没有再需要交换,也就是该数列已经排序完成。这个算法的名字由来是因为越大的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序是稳定的排序算法,它的时间复杂度为O(n^2)。它是一种较慢的排序算法,在某些情况下不如其他排序算法高效,但它的实现简单,易于理解。在计算机科学中,冒泡排序被认为是一种教学算法,用于教授基本的排序算法思想。
算法流程
冒泡排序算法的流程如下:
从数组的第一个元素开始,比较相邻的两个元素,如果第一个比第二个大,就交换他们的位置。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素应该会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
注意,第一步只需要扫描一遍数组,第二步需要扫描n-1遍,第三步需要扫描n-2遍,以此类推。
时间和空间复杂度
冒泡排序的时间复杂度是 O(n^2),空间复杂度是 O(1)。
其中,时间复杂度说明了算法执行所需要的时间随数据规模增长而增长的速度。在冒泡排序中,通过两重循环,需要对每个元素都进行n-1次比较,所以总共需要进行n(n-1)/2次比较,所以时间复杂度为O(n^2)。
空间复杂度说明了算法所需要的存储空间随数据规模增长而增长的速度。冒泡排序是在原数组上进行排序的,不需要额外的存储空间,所以空间复杂度为 O(1)。
需要注意,在实际应用中,如果数组已经有序或者基本有序,冒泡排序会更快,因为会提前结束循环。
冒泡排序的优缺点
冒泡排序的优点:
算法简单易懂,容易实现。
稳定排序,不改变相同元素的相对顺序。
冒泡排序的缺点:
时间复杂度为O(n^2),不适合大规模数据的排序。
效率低下,如果数组已经有序或者基本有序,冒泡排序会更快,因为会提前结束循环。
因此,冒泡排序适用于小数据量或者对稳定性要求较高的场景,但不适用于大数据量或高效率要求的场景。
示例代码
python
#include <iostream>
using namespace std;
void merge(int arr[], int left, int mid, int right) {
// 计算两个子序列的长度
int n1 = mid - left + 1;
int n2 = right - mid;
// 创建两个辅助数组
int L[n1], R[n2];
// 拷贝数据到辅助数组
for (int i = 0; i < n1; i++) {
L[i] = arr[left + i];
}
for (int i = 0; i < n2; i++) {
R[i] = arr[mid + 1 + i];
}
// 合并两个子序列
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k++] = L[i++];
} else {
arr[k++] = R[j++];
}
}
// 拷贝剩余元素
while (i < n1) {
arr[k++] = L[i++];
}
while (j < n2) {
arr[k++] = R[j++];
}
}
void mergeSort(int arr[], int left, int right) {
if (left < right) {
// 找到中间位置
int mid = (left + right) / 2;
// 递归排序左半部分
mergeSort(arr, left, mid);
// 递归排序右半部分
mergeSort(arr, mid + 1, right);
// 合并两个子序列
merge(arr, left, mid, right);
}
}
int main() {
int arr[] = {5, 2, 9, 1, 7, 6, 8, 3, 4};
int n = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, n - 1);
for (int i = 0; i < n; i++) {
cout << arr[i] << " ";
}
return 0;
}
详细注释:
n = len(arr):获取数组长度。
for i in range(n):外层循环控制着冒泡排序的趟数。
for j in range(0, n-i-1):内层循环控制着每趟排序中相邻元素的比较和交换。
if arr[j] > arr[j+1]:如果相邻元素顺序不对,交换两元素。
return arr:返回排序后的数组。
适用场景
冒泡排序是一种简单易懂且稳定的排序算法,适用于数据规模不大的排序场景。由于冒泡排序的时间复杂度为 O(n^2),对于大数据集来说,会有明显的性能问题。因此,冒泡排序更适用于数据规模较小的排序场景。
另外,冒泡排序具有稳定性,即相同元素之间的相对位置不变,这在某些场景中非常重要。例如,如果要对一个学生成绩列表进行排序,并且学生成绩相同时需要保持学生姓名的顺序,那么冒泡排序就是一个很好的选择。
总之,冒泡排序适用于数据规模较小且需要稳定性的排序场景。
正面例子
对于一个学生成绩列表进行排序。需要按照学生的总分进行排序,并且如果总分相同,需要按照学生姓名的字母顺序进行排序。这个场景中,冒泡排序是一个很好的选择,因为冒泡排序具有稳定性,可以保证相同总分的学生姓名的顺序
反面例子
对于一个高性能期货交易系统,需要对亿级别的交易记录进行排序。在这个场景中,冒泡排序明显不能满足性能要求,因为冒泡排序的时间复杂度为O(n^2),对于大规模数据集来说会有明显的性能问题。应该使用其他算法如快速排序,归并排序等。