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

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

📚 目录

  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. 算法选择的实际应用指导
相关推荐
派大星爱吃猫3 小时前
快速排序和交换排序详解(含三路划分)
算法·排序算法·快速排序·三路划分
froginwe113 小时前
HTML5 Audio(音频)
开发语言
焜昱错眩..3 小时前
代码随想录第四十八天|1143.最长公共子序列 1035.不相交的线 53. 最大子序和 392.判断子序列
算法·动态规划
程序员皮皮林3 小时前
Java 25 正式发布:更简洁、更高效、更现代!
java·开发语言·python
程序猿编码3 小时前
Linux 文件变动监控工具:原理、设计与实用指南(C/C++代码实现)
linux·c语言·c++·深度学习·inotify
AI妈妈手把手3 小时前
YOLO V2全面解析:更快、更准、更强大的目标检测算法
人工智能·算法·yolo·目标检测·计算机视觉·yolo v2
极客智造3 小时前
编程世界的内在逻辑:深入探索数据结构、算法复杂度与抽象数据类型
数据结构·算法·数学建模
ArabySide3 小时前
【Java】理解Java内存中堆栈机制与装箱拆箱的底层逻辑
java·开发语言