在编程的江湖中,排序算法就像是大侠们的基本功。无论是处理海量数据、优化搜索算法,还是开发游戏,排序算法都无处不在。今天,我们要探讨的是排序江湖中最基础的三种算法:插入排序、选择排序和冒泡排序。它们就像是江湖中的三位剑客,各有各的招式和心法。
插入排序的核心思想就像你在玩扑克牌时整理手牌的过程。每次拿到一张新牌,你都会将它插入到已排好序的牌中合适的位置。这种增量式排序的方法,让数组逐步变得有序。
类比江湖:这就像是一位武林新手,每学到一招新功夫,都会融入自己的招式体系中,让自己的武功越来越强。
让我们用一个例子来拆解插入排序的招式。假设我们有一个数组:[87, 35, 67, 33, 22]
,我们要将它按升序排列。
第 1 回合(处理 35
):
[87]
(只有一个元素,自然有序)35
35
vs 87
→ 87 > 35
→ 后移 87
→ 空位在索引 035
到索引 0[35, 87, 67, 33, 22]
第 2 回合(处理 67
):
[35, 87]
67
67
vs 87
→ 87 > 67
→ 后移 87
→ 空位在索引 167
vs 35
→ 35 < 67
→ 停止比较67
到索引 1[35, 67, 87, 33, 22]
第 3 回合(处理 33
):
[35, 67, 87]
33
33
vs 87
→ 后移 87
33
vs 67
→ 后移 67
33
vs 35
→ 后移 35
33
[33, 35, 67, 87, 22]
第 4 回合(处理 22
):
[33, 35, 67, 87]
22
22
vs 87
→ 后移 87
22
vs 67
→ 后移 67
22
vs 35
→ 后移 35
22
vs 33
→ 后移 33
22
[22, 33, 35, 67, 87]
#include
void main() {
int a[5] = {87, 35, 67, 33, 22}, j, i, t;
// 江湖侠客修炼心法
for (i = 1; i < 5; i++) {
t = a[i]; // 取出待插入的"新招式"
// 在已掌握的招式中寻找合适位置
for (j = i - 1; j >= 0 && a[j] > t; j--)
a[j + 1] = a[j]; // 招式后移,腾出位置
a[j + 1] = t; // 插入新招式,形成更强的招式链
}
// 展示修炼成果
for (i = 0; i < 5; i++)
printf("%4d", a[i]);
getch();
}
选择排序的核心思想就像你在水果店挑选水果。每次你都会从所有水果中选出最好的一个,然后放在一边,接着再从剩下的水果中选出最好的,直到挑完所有水果。
类比江湖:这就像是一位武林高手在众多弟子中挑选最优秀的,每次选出一个,培养成精英,逐步壮大自己的门派。
还是用数组 [87, 35, 67, 33, 22]
来演示选择排序的招式。
第 1 回合(i=0):
[87, 35, 67, 33, 22]
22
(索引 4)87
↔ 22
[22, 35, 67, 33, 87]
第 2 回合(i=1):
[35, 67, 33, 87]
33
(索引 3)35
↔ 33
[22, 33, 67, 35, 87]
第 3 回合(i=2):
[67, 35, 87]
35
(索引 3)67
↔ 35
[22, 33, 35, 67, 87]
第 4 回合(i=3):
[67, 87]
67
(索引 3)[22, 33, 35, 67, 87]
c
#include
void main() {
int a[5] = {87, 35, 67, 33, 22}, j, i, t, k;
// 江湖掌门挑选精英弟子
for (i = 0; i < 5; i++) {
t = i; // 记录当前认为的"精英弟子"下标
// 遍历所有弟子,寻找真正的精英
for (j = i + 1; j < 5; j++)
if (a[t] > a[j])
t = j; // 更新精英弟子下标
// 如果发现更优秀的弟子,进行位置调整
if (t != i) {
k = a[t];
a[t] = a[i];
a[i] = k; // 交换位置,让精英弟子站在前面
}
}
// 展示精英弟子阵容
for (i = 0; i < 5; i++)
printf("%4d", a[i]);
getch();
}
冒泡排序的核心思想就像水中的气泡。大的气泡会更快地浮到水面,而小的气泡则会慢慢上浮。通过不断比较相邻元素,将较大的元素逐步 "冒泡" 到数组末尾。
类比江湖:这就像是江湖中的比武大会,每次让相邻的两位侠客比试,胜者晋级,败者后退,最终最强的侠客会脱颖而出。
继续用数组 [87, 35, 67, 33, 22]
来演示冒泡排序的招式。
第 1 回合(i=0):
87
vs 35
→ 交换 → [35, 87, 67, 33, 22]
87
vs 67
→ 交换 → [35, 67, 87, 33, 22]
87
vs 33
→ 交换 → [35, 67, 33, 87, 22]
87
vs 22
→ 交换 → [35, 67, 33, 22, 87]
87
像气泡一样 "浮" 到了末尾第 2 回合(i=1):
35
vs 67
→ 不交换 → [35, 67, 33, 22, 87]
67
vs 33
→ 交换 → [35, 33, 67, 22, 87]
67
vs 22
→ 交换 → [35, 33, 22, 67, 87]
67
浮到了倒数第二位置第 3 回合(i=2):
35
vs 33
→ 交换 → [33, 35, 22, 67, 87]
35
vs 22
→ 交换 → [33, 22, 35, 67, 87]
35
浮到了倒数第三位置第 4 回合(i=3):
33
vs 22
→ 交换 → [22, 33, 35, 67, 87]
[22, 33, 35, 67, 87]
#include
void main() {
int a[5] = {87, 35, 67, 33, 22}, j, i, t, k;
// 江湖比武大会
for (i = 0; i < 5; i++) {
k = 0; // 记录本轮是否有侠客位置变动
// 相邻侠客两两比试
for (j = 0; j < 5 - i - 1; j++) {
if (a[j] > a[j + 1]) {
k = 1; // 标记有位置变动
t = a[j];
a[j] = a[j + 1];
a[j + 1] = t; // 胜者晋级,败者后退
}
}
if (!k) break; // 如果本轮无人变动,说明江湖已安定,提前结束
}
// 展示武林排行榜
for (i = 0; i < 5; i++)
printf("%4d", a[i]);
getch();
}
c
算法 | 最好情况 | 最坏情况 | 平均情况 |
---|---|---|---|
插入排序 | O(n) | O(n²) | O(n²) |
选择排序 | O(n²) | O(n²) | O(n²) |
冒泡排序 | O(n) | O(n²) | O(n²) |
江湖点评:插入排序和冒泡排序在数据基本有序时有惊喜表现,而选择排序则始终如一的 "稳定"(慢)。
三大算法均为 O (1),都是 "轻量级选手",无需额外空间,适合在内存有限的江湖环境中使用。
江湖点评:在需要保持原有顺序的场景中,选择排序会被直接淘汰。
江湖口诀:
插入排序像玩牌,步步为营最实在;
选择排序挑精英,精准选择效率平;
冒泡排序比相邻,气泡上浮见真章;
数据有序插冒强,数据乱序另寻良方。
通过学习这三种基础排序算法,你不仅掌握了排序的基本原理,还理解了算法设计的核心思想。这些知识是进一步学习高级排序算法(如快速排序、归并排序)的重要基础。建议你亲自编写代码,调试运行,并尝试不同的输入数据观察算法表现。 或者在评论区交流学习,这将帮助你更深入地理解排序算法的本质。