"冒泡排序的实现与优化"
冒泡排序是一种简单的交换类排序算法,它的基本思想是通过不断地比较相邻元素并交换位置,使得每一轮循环后,最大(或最小)的元素“浮”到数组的一端。在这个过程中,就像水底下的气泡一样逐渐升至水面。冒泡排序的主要步骤包括以下两个方面:
1. 外层循环:控制整个排序过程的轮数。在最坏的情况下,需要进行n-1轮排序,其中n是数组的长度。因为每一轮排序都会确保当前未排序部分的最大值被放置到了正确的位置。
2. 内层循环:在每一轮排序中,从数组的第一个元素开始,逐个比较相邻元素,如果前一个元素大于后一个元素,则交换它们的位置。这个过程会持续到数组的末尾,确保在这一轮排序后,最大的元素被移到了数组的末尾。
在提供的代码中,`bubSort` 函数实现了冒泡排序的基本逻辑。它首先通过一个while循环来控制外层循环,然后通过一个for循环处理内层循环。`initArr` 函数用于初始化随机数组,而`showArr` 函数用于打印数组内容,便于观察排序过程。
然而,原始的冒泡排序在某些情况下效率较低,如当数组已经部分或完全排序时,仍然会进行不必要的比较和交换。为提高效率,可以进行以下优化:
1. 设置标志位:在内层循环中,如果在一次完整的遍历中没有发生任何交换,说明数组已经是有序的,可以提前结束排序。在上述代码中,可以添加一个布尔变量`swapped`,用来记录在内层循环中是否进行了交换。如果在一个循环中`swapped`始终为`false`,则说明数组已排序,无需再进行下一轮。
2. 减少比较次数:在冒泡排序中,每次比较都是从头到尾进行的。实际上,随着排序的进行,未排序部分的元素相对位置已经固定,可以适当调整比较范围。例如,如果在某一轮排序中,发现某个位置之后的元素都已排序,那么后续的比较就可以从这个位置开始,而不是从数组的开头。
以下是改进后的冒泡排序代码示例:
```c
#include "stdio.h"
#include "stdlib.h"
#include "time.h"
#define MAX 10
void initArr(int arr[], int length) {
for (int i = 0; i < length; ++i) {
arr[i] = rand() % 20;
}
}
void showArr(int arr[], int length) {
for (int i = 0; i < length; ++i) {
printf("%d", arr[i]);
}
printf("\n");
printf("------------------------------------\n");
}
void bubbleSort(int arr[], int length) {
bool swapped;
for (int i = 0; i < length - 1; ++i) {
swapped = false;
for (int j = 0; j < length - 1 - i; ++j) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
swapped = true;
}
}
// 如果没有发生交换,说明数组已经排序,提前结束
if (!swapped) break;
}
}
int main() {
srand((unsigned int)time(NULL));
int arr[MAX];
initArr(arr, MAX);
showArr(arr, MAX);
bubbleSort(arr, MAX);
showArr(arr, MAX);
return 0;
}
```
通过上述优化,冒泡排序在处理部分有序或已经有序的数组时,其时间复杂度可以从O(n^2)降低到接近O(n),显著提高了效率。虽然冒泡排序在实际应用中通常被更高效的算法(如快速排序、归并排序等)所替代,但在理解排序算法基本原理和进行教学演示时,冒泡排序仍具有重要的意义。