数据结构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. 调试技巧:画链表指针图!比如删除节点时,先画原指针关系,再画修改后的关系,代码就不容易错。
相关推荐
Lips6112 小时前
2026.1.16力扣刷题
数据结构·算法·leetcode
曹仙逸2 小时前
数据结构day05
数据结构
睡一觉就好了。2 小时前
树的基本结构
数据结构
kaikaile19953 小时前
A星算法避开障碍物寻找最优路径(MATLAB实现)
数据结构·算法·matlab
今天_也很困3 小时前
LeetCode 热题100-15.三数之和
数据结构·算法·leetcode
思成Codes5 小时前
ACM训练:接雨水3.0——动态接雨水
数据结构·算法
sin_hielo5 小时前
leetcode 2943
数据结构·算法·leetcode
Snow_day.6 小时前
有关平衡树
数据结构·算法·贪心算法·动态规划·图论
mikelv016 小时前
实现返回树状结构小记
java·数据结构