数据结构day04

一、双向循环链表(核心重点)

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)尾插数据(往链表最后加节点)

  1. 找到尾节点:从头节点开始,一直找next指向头节点的节点;
  2. 新建节点:给新节点赋值,初始化prev/next
  3. 调整指针:
    • 原尾节点的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. 关键注意点

  1. 指针调整顺序:先改 "前 / 后节点的指向",再释放节点,避免指针丢失;
  2. 循环终止条件:所有遍历都以p->next != head为结束(因为尾节点next指向头节点);
  3. 内存释放:删除 / 销毁节点时,必须用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"

三、核心总结

  1. 双向循环链表:记住 "双向(prev/next)+ 循环(头尾相连)",操作核心是调整指针指向,删除 / 销毁时必释放内存;
  2. 字符串操作:strtok 按分隔符切,sprintf 按格式拼,记住 "第一次传字符串,后续传 NULL"(strtok)、"格式符匹配数据类型"(sprintf);
  3. 调试技巧:画链表指针图!比如删除节点时,先画原指针关系,再画修改后的关系,代码就不容易错。
相关推荐
张张努力变强1 小时前
C++ STL string 类:常用接口 + auto + 范围 for全攻略,字符串操作效率拉满
开发语言·数据结构·c++·算法·stl
wWYy.1 小时前
数组快排 链表归并
数据结构·链表
李斯啦果2 小时前
【PTA】L1-019 谁先倒
数据结构·算法
Mr Xu_17 小时前
告别硬编码:前端项目中配置驱动的实战优化指南
前端·javascript·数据结构
czxyvX17 小时前
017-AVL树(C++实现)
开发语言·数据结构·c++
数智工坊17 小时前
【数据结构-队列】3.2 队列的顺序-链式实现-双端队列
数据结构
elseif12318 小时前
【C++】并查集&家谱树
开发语言·数据结构·c++·算法·图论
徐小夕@趣谈前端18 小时前
Web文档的“Office时刻“:jitword共建版2.0发布!让浏览器变成本地生产力
前端·数据结构·vue.js·算法·开源·编辑器·es6
Nebula_g19 小时前
线程进阶: 无人机自动防空平台开发教程(更新)
java·开发语言·数据结构·学习·算法·无人机
xuxie9920 小时前
day 23 树
数据结构