高考数学97分,我的“数学直觉“比140分更好用:链表指针操作的代数思维:从离散数学看单链表

张开发
2026/4/7 10:48:25 15 分钟阅读

分享文章

高考数学97分,我的“数学直觉“比140分更好用:链表指针操作的代数思维:从离散数学看单链表
目录一序言二数学思维三核心概念1. 节点Node2. 头指针Head Pointer3. 链式存储4. 链表类型5. 核心操作6. 内存管理7. 与顺序表的对比数学思维8. 应用场景四代码实现1结构定义2. 初始化链表3. 插入操作增4. 删除操作删5. 查找操作查6. 修改操作改7. 遍历输出8. 测试代码五最后总结一序言大家好我是小洛上节内容我们讲了由顺序存储的线性结构---顺序表今天要讲的是关于链式存储的线性结构----链表看看数据存储的方式到底有什么变化二数学思维链表就像是一列火车头结点就像是一个火车头来统领全局并且连接后面。而节点就像是火车的每个车间每个车间有自己数据。从数学结构上来看链表是一种离散线性结构链表的操作依赖指针接力来访问元素顺序表的操作依赖数组下标来访问元素。三核心概念1. 节点Node定义 链表的基本组成单元包含 数据域 存储实际数据和 指针域 存储指向下一个节点的地址。作用 通过指针域将分散的节点串联成一个整体。示例 单链表节点结构C语言2. 头指针Head Pointer定义 指向链表第一个节点的指针是访问整个链表的入口点。作用 作为链表的“门把手”通过它可以遍历或操作整个链表。状态 空链表时头指针为 NULL 。3. 链式存储特性 节点在内存中 非连续存储 通过指针连接形成逻辑上的线性结构。优势 无需预先分配连续内存适合动态数据场景。劣势 无法像数组那样随机访问需从头遍历。4. 链表类型单链表 每个节点只有一个指针域指向后继节点只能单向遍历。双向链表 每个节点有两个指针域分别指向前驱和后继节点支持双向遍历。循环链表 尾节点的指针指向头节点形成环形结构适合循环处理场景约瑟夫环。5. 核心操作插入 若已知插入位置的前驱节点则操作时间为 O(1)若按位置插入需先查找总时间为 O(n)。删除 若已知插入位置的前驱节点则操作时间为 O(1)若按位置插入需先查找总时间为 O(n)。遍历 O(n) 时间复杂度需从头开始依次访问。查找 O(n) 时间复杂度需遍历节点比较数据。6. 内存管理动态分配 节点通过 malloc 等函数动态分配内存。内存释放 删除节点时需通过 free 释放内存避免内存泄漏。碎片化 频繁的插入/删除可能导致内存碎片化。7. 与顺序表的对比特性链表顺序表存储方式非连续内存指针连接连续内存插入/删除O(1)修改指针O(n)移动元素随机访问O(n)需遍历O(1)直接下标访问空间开销额外存储指针无额外开销适用场景频繁插入/删除频繁随机访问数学思维如果我把顺序表比喻成食堂打饭排队一个一个有序的排队那么链表就是医院叫号每个人不用站在一起坐在任何位置都行只要记住 “下一个人的号码”就能形成队伍。号码指针把分散的人节点按顺序“叫”起来即使他们坐在不同位置。8. 应用场景队列 FIFO先进先出操作适合链表实现。栈 LIFO后进先出操作可通过链表实现。哈希表 解决冲突时的链地址法。LRU缓存 需要频繁删除最久未使用的元素。树形结构/图 作为其底层存储结构如邻接表。四代码实现1结构定义#include stdio.h #include stdlib.h typedef struct Node { int data; // 数据域 struct Node *next; // 指针域 } Node;2. 初始化链表Node* initList() { Node *head (Node*)malloc(sizeof(Node)); head-next NULL; // 初始为空链表 return head; }3. 插入操作增void insert(Node *head, int pos, int value) { Node *p head; // 找到插入位置的前一个节点 for (int i 0; i pos p-next ! NULL; i) { p p-next; } // 创建新节点 Node *newNode (Node*)malloc(sizeof(Node)); newNode-data value; // 插入节点 newNode-next p-next; p-next newNode; }4. 删除操作删void delete(Node *head, int pos) { Node *p head; // 找到删除位置的前一个节点 for (int i 0; i pos p-next ! NULL; i) { p p-next; } // 检查位置是否合法 if (p-next NULL) { printf(删除位置不合法\n); return; } // 删除节点 Node *delNode p-next; p-next delNode-next; free(delNode); }5. 查找操作查int find(Node *head, int value) { Node *p head-next; int pos 0; while (p ! NULL) { if (p-data value) { return pos; } p p-next; pos; } return -1; }6. 修改操作改void modify(Node *head, int pos, int newValue) { Node *p head-next; // 找到指定位置的节点 for (int i 0; i pos p ! NULL; i) { p p-next; } // 检查位置是否合法 if (p NULL) { printf(修改位置不合法\n); return; } // 修改数据 p-data newValue; }7. 遍历输出void printList(Node *head) { Node *p head-next; printf(链表元素); while (p ! NULL) { printf(%d , p-data); p p-next; } printf(\n); }8. 测试代码int main() { Node *head initList(); // 插入测试增 insert(head, 0, 10); insert(head, 1, 20); insert(head, 2, 30); printList(head); // 输出10 20 30 // 查找测试查 int pos find(head, 20); printf(元素20的位置%d\n, pos); // 输出1 // 修改测试改 modify(head, 1, 25); printList(head); // 输出10 25 30 // 删除测试删 delete(head, 1); printList(head); // 输出10 30 // 释放内存 Node *p head; while (p ! NULL) { Node *temp p; p p-next; free(temp); } return 0; }五最后总结不论是顺序表还是链表他们都是存储数据的方式。都是由变量数组结构体指针这四种基本存储数据的方式相互组合人为创造出来的。他们的优点都有所不同比如说顺序表侧重于随机访问而链表侧重于插入和删除。

更多文章