1、常见的排序算法
1.1 交换排序基本思想
冒泡排序属于交换排序之一,我们先来了解以下冒泡排序思想。
基本思想:所谓交换,就是根据序列中两个记录键值的比较结果来对换这两个记录在序列中的位置,交换排序的特点是:将键值较大的记录向序列的尾部移动,键值较小的记录向序列的前部移动。
2、冒泡排序的实现
2.1 基本思想
我们本篇讲冒泡排序以排升序来举例。
基本思想:对比数组前一个数字与后一个数组的大小,当前一个数大于后一个数,我们就交换两个数字,遍历整个数组,不断判断,进行交换。
2.2 单趟排序
2.2.1 单趟排序分析
单趟排序时,第一趟排序就将最大数排到了数组尾。
2.2.2 单趟排序实现代码
for (int j = 1; j < n; j++) { if (a[j - 1] > a[j]) { int tmp = a[j - 1]; a[j - 1] = a[j]; a[j] = tmp; } }
3、冒泡排序完整代码实现
3.1 思路分析
我们看到单趟排序第一趟时,就将最大值排到了数组尾部,按照这样的分析,我们排n-1趟就可以实现将整个数组完全排序。
这里为什么是 n-1 趟,当倒数第二小的数字排好序后,倒数第一小的数字自然就排好。
3.2 代码实现
void bubble_sort(int* a, int n) { for (int i = 0; i < n - 1; i++) { for (int j = 1; j < n - i; j++) { if (a[j - 1] > a[j]) { int tmp = a[j - 1]; a[j - 1] = a[j]; a[j] = tmp; } } } }
4、时间复杂度
冒泡排序时间复杂度:O(N^2)。
无论是数组有序或者无序都是O(N^2),因为无论是否有序我们都需要比大小,而比大小正好是在内层循环里面,所以时间复杂度是与数组是否有序无关。
5、优化算法
5.1 优化算法思路
其实我们不难想到,如果数组是有序的,那么就不用循环那么多次了。
Q:那我们如何才能判断出数组是有序的呢?
A:其实不难,当我们数组是有序的时候就不发生交换,这就是优化算法的关键。
那么我们如何写呢?我们在内层循环外定义一个 flag = 1,假设是有序,在交换语句里我们将 flag 改为 0,当内层循环完后我们判断flag是否为1,为1就说明数组是有序的,此时就break,跳出了整个循环。
5.2 优化算法代码实现
void bubble_sort(int* a, int n) { for (int i = 0; i < n - 1; i++) { int flag = 1; for (int j = 1; j < n - i; j++) { if (a[j - 1] > a[j]) { flag = 0; int tmp = a[j - 1]; a[j - 1] = a[j]; a[j] = tmp; } } if (1 == flag) break; } }
优化后最优的时间复杂度:O(N)。此时只是第一趟循环,判断是否有序。
6、冒泡排序的特性总结
1. 冒泡排序是一种非常容易理解的排序
2. 时间复杂度:O(N^2)
3. 空间复杂度:O(1)
4. 稳定性:稳定