【数据结构】从线性表到排序算法详解

数据结构与算法基础:从线性表到排序算法详解

📚 目录

  1. 线性表的两种存储方式
  2. 三大基础排序算法详解
  3. 归并排序:分治思想的经典应用
  4. 算法对比与实际应用

线性表的两种存储方式

顺序存储结构

特点:逻辑上相邻的元素在物理位置上也相邻

c 复制代码
// 顺序表的定义
#define MAXSIZE 100
typedef struct {
    int data[MAXSIZE];  // 存储数组
    int length;         // 当前长度
} SeqList;

优点

  • 随机访问速度快:O(1)
  • 存储密度高
    缺点
  • 插入删除操作需要移动大量元素:O(n)
  • 必须预先分配连续空间

链式存储结构

特点:用指针来表示元素之间的逻辑关系

c 复制代码
// 单链表的定义
typedef struct LNode {
    int data;           // 数据域
    struct LNode *next; // 指针域
} LNode, *LinkList;

优点

  • 插入删除操作方便:O(1)
  • 动态分配内存,空间利用率高
    缺点
  • 访问第i个元素需要遍历:O(n)
  • 额外空间存储指针

三大基础排序算法详解

1. 直接插入排序

核心思想:将待排序的元素插入到已排序序列的合适位置

c 复制代码
void InsertSort(int A[], int n) {
    for (int i = 2; i <= n; i++) {  // 从第二个元素开始
        if (A[i] < A[i-1]) {         // 需要插入
            A[0] = A[i];             // 哨兵暂存
            int j;
            for (j = i-1; A[0] < A[j]; j--) {
                A[j+1] = A[j];        // 元素后移
            }
            A[j+1] = A[0];            // 插入到正确位置
        }
    }
}

特点

  • ✅ 稳定排序
  • 📊 时间复杂度:O(n²)
  • 🎯 适用于小规模数据或基本有序的数据

2. 简单选择排序

核心思想:每次从未排序部分选择最小元素放到已排序部分末尾

c 复制代码
void SelectSort(int A[], int n) {
    for (int i = 0; i < n-1; i++) {  // n-1趟选择
        int min = i;                  // 记录最小元素下标
        for (int j = i+1; j < n; j++) {
            if (A[j] < A[min]) min = j;  // 找到更小元素
        }
        if (min != i) {              // 交换到正确位置
            int temp = A[i];
            A[i] = A[min];
            A[min] = temp;
        }
    }
}

特点

  • ❌ 不稳定排序
  • 📊 时间复杂度:O(n²)
  • 🔄 交换次数少,适合交换成本高的场景

3. 冒泡排序

核心思想:相邻元素两两比较,逆序则交换,每轮将最大元素"冒泡"到末尾

c 复制代码
void BubbleSort(int A[], int n) {
    for (int i = 0; i < n-1; i++) {  // n-1趟
        bool flag = false;            // 优化标记
        for (int j = n-1; j > i; j--) {  // 从后往前
            if (A[j] < A[j-1]) {     // 逆序则交换
                int temp = A[j];
                A[j] = A[j-1];
                A[j-1] = temp;
                flag = true;          // 标记有交换
            }
        }
        if (!flag) break;             // 无交换则提前结束
    }
}

特点

  • ✅ 稳定排序
  • 📊 时间复杂度:O(n²)
  • ⚡ 有优化空间,最好情况可达O(n)

归并排序:分治思想的经典应用

核心思想

归并排序采用分治策略:

  1. 分解:将序列分成两半
  2. 解决:递归排序两个子序列
  3. 合并:将两个有序子序列合并

递归实现

c 复制代码
// 归并排序主函数
void mergeSort(ListNode* p, int n) {
    if (n < 2) return;  // 递归终止条件
    int m = n >> 1;     // 中间位置
    ListNode* q = p;    // 后半段起点
    // 寻找中间节点
    for (int i = 0; i < m; i++) {
        q = q->next;
    }
    // 递归排序前后两段
    mergeSort(p, m);
    mergeSort(q, n - m);
    // 合并两个有序子序列
    merge(p, m, q, n - m);
}

合并操作

c 复制代码
// 合并两个有序链表
ListNode* merge(ListNode* p, int m, ListNode* q, int n) {
    ListNode dummy;     // 哨兵节点
    ListNode* tail = &dummy;
    while (m > 0 && n > 0) {
        if (p->data <= q->data) {  // 选择较小元素
            tail->next = p;
            p = p->next;
            m--;
        } else {
            tail->next = q;
            q = q->next;
            n--;
        }
        tail = tail->next;
    }
    // 处理剩余元素
    if (m > 0) tail->next = p;
    if (n > 0) tail->next = q;
    return dummy.next;
}

特点

  • ✅ 稳定排序
  • 📊 时间复杂度:O(n log n)
  • 💾 空间复杂度:O(n)
  • 🎯 适用于大规模数据排序

算法对比与实际应用

性能对比表

算法 时间复杂度 空间复杂度 稳定性 适用场景
插入排序 O(n²) O(1) ✅ 稳定 小规模、基本有序数据
选择排序 O(n²) O(1) ❌ 不稳定 交换成本高的场景
冒泡排序 O(n²) O(1) ✅ 稳定 教学演示、简单场景
归并排序 O(n log n) O(n) ✅ 稳定 大规模数据、外部排序

实际应用建议

  1. 小规模数据(n < 50):使用插入排序
  2. 中等规模数据:考虑快速排序或堆排序
  3. 大规模数据且要求稳定:使用归并排序
  4. 内存受限环境:选择堆排序

优化技巧

c 复制代码
// 混合排序:小数组用插入排序,大数组用归并排序
void hybridSort(int A[], int n) {
    if (n < 16) {
        InsertSort(A, n);  // 小数组用插入排序
    } else {
        // 大数组用归并排序
        int mid = n / 2;
        hybridSort(A, mid);
        hybridSort(A + mid, n - mid);
        merge(A, mid, A + mid, n - mid);
    }
}

总结

通过今天的学习,我们掌握了:

  1. 线性表的两种存储方式及其优缺点
  2. 三大基础排序算法的实现和特点
  3. 归并排序的分治思想和实现
  4. 算法选择的实际应用指导
相关推荐
周末也要写八哥12 小时前
经典算法实例:游戏中弱角色的数量(二)
算法
是Yu欸13 小时前
鸿蒙PC移植:2048 从网页小游戏到 AI 桌面应用
大数据·人工智能·算法·数据挖掘·openharmony·codex
鹿角片ljp13 小时前
KV Cache 解析
java·算法
liliangcsdn13 小时前
IVOL与偏度因子的对比测量分析
算法
qq_1998868714 小时前
第6板块·第4节:构建系统与多文件项目
c++·人工智能·gpu算力
2601_9669496514 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
m0_7345717614 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
threerocks15 小时前
Jev 入门第一课
算法
汉克老师15 小时前
GESP2026年9月认证C++三级( 第三部分编程题(2、分割字符串))精讲
c++·gesp·小学生·学c++编程
估值探索者15 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘