一、双向循环链表(核心重点)
1. 基本结构
双向循环链表的每个节点包含数据域 和两个指针域:
c
运行
struct doublelist {
int data; // 数据域:存放有效数据
struct doublelist *next;// 后继指针:指向后一个节点
struct doublelist *prev;// 前驱指针:指向前一个节点
};
- 头节点:不存有效数据,仅作为链表入口;
- 循环特性:头节点的
prev指向尾节点,尾节点的next指向头节点; - 双向特性:任意节点可通过
prev/next向前 / 向后遍历。
2. 核心操作(通俗解释)
(1)初始化头节点
c
运行
struct doublelist *list_init() {
struct doublelist *head = malloc(sizeof(struct doublelist));
head->next = head; // 头节点next指向自己
head->prev = head; // 头节点prev指向自己
return head;
}
- 作用:创建链表的 "入口",初始时链表只有头节点,自己指向自己。
(2)尾插数据(往链表最后加节点)
- 找到尾节点:从头节点开始,一直找
next指向头节点的节点; - 新建节点:给新节点赋值,初始化
prev/next; - 调整指针:
- 原尾节点的
next指向新节点; - 新节点的
prev指向原尾节点; - 新节点的
next指向头节点; - 头节点的
prev指向新节点。
- 原尾节点的
(3)删除节点(按数据删)
- 核心逻辑:找到要删的节点后,让它的 "前一个节点" 指向 "后一个节点","后一个节点" 指向 "前一个节点",最后释放节点内存;
- 简化点:双向循环链表删除中间节点 和尾节点 的逻辑可统一(尾节点的
next是头节点,无需额外判空)。
c
运行
// 简化版删除逻辑(核心)
p->prev->next = p->next; // 前节点跳过当前节点
p->next->prev = p->prev; // 后节点跳过当前节点
free(p); // 释放内存
(4)修改数据
遍历链表,找到目标数据的节点,直接修改节点的data值即可:
c
运行
void list_update(int newdata, int olddata, struct doublelist *head) {
struct doublelist *p = head;
while (p->next != head) {
p = p->next;
if (p->data == olddata) {
p->data = newdata; // 直接替换数据
}
}
}
(5)销毁链表(清空所有节点)
- 思路:每次删头节点的下一个节点,直到头节点的
next指向自己; - 最后一定要释放头节点内存,避免内存泄漏。
c
运行
void list_destory(struct doublelist *head) {
struct doublelist *p = NULL;
while (head->next != head) {
p = head->next; // 取头节点的下一个节点
head->next = p->next; // 头节点跳过当前节点
p->next->prev = head; // 后节点指向头节点
free(p); // 释放当前节点
}
free(head); // 释放头节点
}
3. 关键注意点
- 指针调整顺序:先改 "前 / 后节点的指向",再释放节点,避免指针丢失;
- 循环终止条件:所有遍历都以
p->next != head为结束(因为尾节点next指向头节点); - 内存释放:删除 / 销毁节点时,必须用
free()释放,否则会内存泄漏。
二、字符串处理(辅助知识点)
1. strtok(切割字符串)
- 作用:按指定分隔符拆分字符串;
- 用法:
- 第一次调用:传要切割的字符串 + 分隔符;
- 后续调用:第一个参数传
NULL,继续切割剩余部分。
c
运行
char date[20] = "2026-1-6";
char *p = strtok(date, "-"); // 第一次切:p = "2026"
p = strtok(NULL, "-"); // 第二次切:p = "1"
p = strtok(NULL, "-"); // 第三次切:p = "6"
2. sprintf(拼接字符串)
- 作用:把不同类型数据(int、double、字符串)按格式拼接到一个字符串里;
- 用法:
sprintf(目标数组, 格式字符串, 待拼接数据...)
c
运行
int n1=666;
char n2[20]="新年快乐";
double n3=99.9;
char buf[200]={0};
sprintf(buf,"祝大家2026%s,考试成绩%lf,一路%d",n2,n3,n1);
// buf最终内容:"祝大家2026新年快乐,考试成绩99.900000,一路666"
三、核心总结
- 双向循环链表:记住 "双向(prev/next)+ 循环(头尾相连)",操作核心是调整指针指向,删除 / 销毁时必释放内存;
- 字符串操作:strtok 按分隔符切,sprintf 按格式拼,记住 "第一次传字符串,后续传 NULL"(strtok)、"格式符匹配数据类型"(sprintf);
- 调试技巧:画链表指针图!比如删除节点时,先画原指针关系,再画修改后的关系,代码就不容易错。