排序算法江湖:从菜鸟到高手的进阶之路(选择带下标,插入,冒泡排序详解)

一、江湖风云起:为什么要学排序算法?

在编程的江湖中,排序算法就像是大侠们的基本功。无论是处理海量数据、优化搜索算法,还是开发游戏,排序算法都无处不在。今天,我们要探讨的是排序江湖中最基础的三种算法:插入排序选择排序冒泡排序。它们就像是江湖中的三位剑客,各有各的招式和心法。

二、插入排序:像玩扑克牌一样排序

1. 核心心法:步步为营

插入排序的核心思想就像你在玩扑克牌时整理手牌的过程。每次拿到一张新牌,你都会将它插入到已排好序的牌中合适的位置。这种增量式排序的方法,让数组逐步变得有序。

类比江湖:这就像是一位武林新手,每学到一招新功夫,都会融入自己的招式体系中,让自己的武功越来越强。

2. 招式拆解

让我们用一个例子来拆解插入排序的招式。假设我们有一个数组:[87, 35, 67, 33, 22],我们要将它按升序排列。

第 1 回合(处理 35):

  • 已排序区间:[87](只有一个元素,自然有序)
  • 待插入元素:35
  • 比较过程:
    • 35 vs 87 → 87 > 35 → 后移 87 → 空位在索引 0
    • 插入 35 到索引 0
  • 结果:[35, 87, 67, 33, 22]

第 2 回合(处理 67):

  • 已排序区间:[35, 87]
  • 待插入元素:67
  • 比较过程:
    • 67 vs 87 → 87 > 67 → 后移 87 → 空位在索引 1
    • 67 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
    • 空位在索引 0,插入 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
    • 空位在索引 0,插入 22
  • 最终结果[22, 33, 35, 67, 87]

3. 代码实现(江湖秘籍)

#include <stdio.h>
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();
}

三、选择排序:像挑水果一样找最小值

1. 核心心法:精准选择

选择排序的核心思想就像你在水果店挑选水果。每次你都会从所有水果中选出最好的一个,然后放在一边,接着再从剩下的水果中选出最好的,直到挑完所有水果。

类比江湖:这就像是一位武林高手在众多弟子中挑选最优秀的,每次选出一个,培养成精英,逐步壮大自己的门派。

2. 招式拆解

还是用数组 [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]

3. 代码实现(江湖秘籍)

c

#include <stdio.h>
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();
}

四、冒泡排序:像气泡上浮一样排序

1. 核心心法:两两比较

冒泡排序的核心思想就像水中的气泡。大的气泡会更快地浮到水面,而小的气泡则会慢慢上浮。通过不断比较相邻元素,将较大的元素逐步 "冒泡" 到数组末尾。

类比江湖:这就像是江湖中的比武大会,每次让相邻的两位侠客比试,胜者晋级,败者后退,最终最强的侠客会脱颖而出。

2. 招式拆解

继续用数组 [87, 35, 67, 33, 22] 来演示冒泡排序的招式。

第 1 回合(i=0):

  • 比较次数:4 次
  • 过程:
    1. 87 vs 35 → 交换 → [35, 87, 67, 33, 22]
    2. 87 vs 67 → 交换 → [35, 67, 87, 33, 22]
    3. 87 vs 33 → 交换 → [35, 67, 33, 87, 22]
    4. 87 vs 22 → 交换 → [35, 67, 33, 22, 87]
  • 结果:最大元素 87 像气泡一样 "浮" 到了末尾

第 2 回合(i=1):

  • 比较次数:3 次
  • 过程:
    1. 35 vs 67 → 不交换 → [35, 67, 33, 22, 87]
    2. 67 vs 33 → 交换 → [35, 33, 67, 22, 87]
    3. 67 vs 22 → 交换 → [35, 33, 22, 67, 87]
  • 结果:第二大元素 67 浮到了倒数第二位置

第 3 回合(i=2):

  • 比较次数:2 次
  • 过程:
    1. 35 vs 33 → 交换 → [33, 35, 22, 67, 87]
    2. 35 vs 22 → 交换 → [33, 22, 35, 67, 87]
  • 结果:第三大元素 35 浮到了倒数第三位置

第 4 回合(i=3):

  • 比较次数:1 次
  • 过程:
    1. 33 vs 22 → 交换 → [22, 33, 35, 67, 87]
  • 最终结果[22, 33, 35, 67, 87]

3. 优化版代码实现(江湖秘籍)

#include <stdio.h>
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

五、三大算法江湖对决

1. 时间复杂度比拼

算法最好情况最坏情况平均情况
插入排序O(n)O(n²)O(n²)
选择排序O(n²)O(n²)O(n²)
冒泡排序O(n)O(n²)O(n²)

江湖点评:插入排序和冒泡排序在数据基本有序时有惊喜表现,而选择排序则始终如一的 "稳定"(慢)。

2. 空间复杂度比拼

三大算法均为 O (1),都是 "轻量级选手",无需额外空间,适合在内存有限的江湖环境中使用。

3. 稳定性对决

  • 插入排序:稳定(相同元素不交换)
  • 选择排序:不稳定(可能改变相同元素顺序)
  • 冒泡排序:稳定(相同元素不交换)

江湖点评:在需要保持原有顺序的场景中,选择排序会被直接淘汰。

六、江湖实战:如何选择合适的算法?

  1. 数据规模较小:三种算法均可,但插入排序通常表现更好。
  2. 数据基本有序:插入排序和优化后的冒泡排序是首选。
  3. 交换成本较高:选择排序(交换次数最少)。
  4. 需要稳定性:插入排序或冒泡排序。

江湖口诀
插入排序像玩牌,步步为营最实在;
选择排序挑精英,精准选择效率平;
冒泡排序比相邻,气泡上浮见真章;
数据有序插冒强,数据乱序另寻良方。

七,总结

通过学习这三种基础排序算法,你不仅掌握了排序的基本原理,还理解了算法设计的核心思想。这些知识是进一步学习高级排序算法(如快速排序、归并排序)的重要基础。建议你亲自编写代码,调试运行,并尝试不同的输入数据观察算法表现。 或者在评论区交流学习,这将帮助你更深入地理解排序算法的本质。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值