算法初步——冒泡排序
通过观察桶排序,我们很容易发现一个致命问题:当我们需要排序的最大数为1000000时,我们需要一个大小为1000001的数组,这就会导致数组占用的内存很大,浪费很多空间。于是,我们有了一种新的排序方法——冒泡排序。
冒泡排序的基本思想是:每次比较相邻的两个元素,如果他们的顺序错误,则把他们的位置进行调换。
例如将3 10 6 27 82 17 22进行从大到小排序,我们的目标就是将较小的数字放到后面。所以比较第一位和第二位数字的大小,我们发现3<10,所以要将3和10进行调换,调换后变成10 3 6 27 82 17 22;紧接着将第二个数和第三个数进行比较发现3<6,我们依旧将3和6进行调换,变成10 6 3 27 82 17 22,以此类推,到此次循环结束时我们成功将这串数字变成了10 6 27 82 17 22 3,这样我们就确定了最后一位数字为3,在进行下一次循环时我们就需要再遍历到最后一位的3了;随后进行第二次遍历,遍历规则同上。每次遍历我们将确定一个相对小的位置,当我们确定到最后一个数字时,循环结束,我们就得到了排序后的数组。
#include<iostream> using namespace std; int main() { int a[100], t, n;//n表示你需要排序的数字的个数 cin >> n; for (int i = 0; i < n; i++)//我们遍历进行输入 { cin >> a[i]; } for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i; j++)//此处仅需要遍历到n-i,可以思考一下为什么 { if (a[j] < a[j + 1]) { //交换过程,不必多说 t = a[j]; a[j] = a[j + 1]; a[j + 1] = t; } } } for (int i = 0; i < n; i++) { cout << a[i] << " "; } cout << endl; return 0; }
利用冒泡排序我们就可以解决桶排序遗留下来的一个问题——不能对结构体数组进行排序。
#include<iostream> using namespace std; typedef struct Student//我们创建了一个结构体数组,用来存放一个学生的姓名和成绩 { char name[21]; int score; }; int main() { Student stu[100], t; int n; cin >> n;//输入学生人数 for (int i = 0; i < n; i++) { printf("请输入第%d个学生的姓名:", i + 1); cin >> stu[i].name; printf("请输入第%d个学生的成绩:", i + 1); cin >> stu[i].score; cout << endl; } //我们按成绩从高到低进行排序 for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i; j++) { if (stu[j].score < stu[j + 1].score) { t = stu[j]; stu[j] = stu[j + 1]; stu[j + 1] = t; } } } for (int i = 0; i < n; i++) { cout << stu[i].name << " " << stu[i].score << endl; } cout << endl; return 0; }
这样我们就完成了一个学生管理系统中的一个重要函数:对学生成绩进行排序。
冒泡排序的核心部分是双重嵌套循环。我们很容易可以看出,冒泡排序的时间复杂度为O(N^2),这是一个非常高的时间复杂度。你以为我们的排序到此就结束了吗?不可能!在下一节我们将会介绍另一种常用的排序算法——快速排序。