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

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

📚 目录

  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. 算法选择的实际应用指导
相关推荐
wearegogog12323 分钟前
时间分数阶微分方程数值求解
算法
CoderYanger1 小时前
A.每日一题——2536. 子矩阵元素加 1
java·线性代数·算法·leetcode·矩阵
sanggou1 小时前
【Python爬虫】手把手教你从零开始写爬虫,小白也能轻松学会!(附完整源码)
开发语言·爬虫·python
普通网友1 小时前
C++与Qt图形开发
开发语言·c++·算法
KG_LLM图谱增强大模型1 小时前
Vgent:基于图的多模态检索推理增强生成框架GraphRAG,突破长视频理解瓶颈
大数据·人工智能·算法·大模型·知识图谱·多模态
AA陈超2 小时前
UE5笔记:GetWorld()->SpawnActorDeferred()
c++·笔记·学习·ue5·虚幻引擎
yue0082 小时前
C# 更改窗体样式
开发语言·c#
普通网友2 小时前
C++中的适配器模式
开发语言·c++·算法
风闲12172 小时前
Qt源码编译记录
开发语言·qt
无敌最俊朗@2 小时前
力扣hot100-160-相交链表
c++