type
status
date
slug
summary
tags
category
icon
password
💡
这节课是信息学奥赛系列的第 6 讲,主要内容是结构体指针与链表结构。

📝 课程大纲

结构体指针

  • 结构体指针的定义与使用
  • 自引用结构

链表结构

  • 链表的定义
  • 链表的结构、建立、输出
  • 链表的遍历、搜索
  • 链表结点的插入、删除
  • 求链表的长度
  • 双向链表
  • 循环链表

🤗 整理归纳

链表入门

notion image
链表是复合类型,可以用 struct 定义它的每个结点
结点是递归类型,它的数据包含了指向本类型的指针
注意,只可以包含 Node* 类型的变量, 不可以包含 Node next;
想想看,如果这样,sizeof(Node) = ????
结点的内存一般是动态申请的。
当增加数据的时候,申请内存。
删除数据的时候,释放内存。
notion image

对结点的常规操作

  • 求链表的长度
    • 这是个耗时的动作,可以想办法优化
  • 增加
    • 为什么要返回?
      为什么不在尾巴上添加?
  • 查找
    • 删除
      • 删除需要取得目标的前一个结点,原理:
        notion image
    实时效果反馈
    1怎样在链表表尾添加新结点?____
    A 首先让表头指针指向表尾
    B 首先让表尾指针指向表头
    C 首先根据表头,找到表尾结点
    D 首先把表尾 next 置为 NULL
    2当单向链表较长时,下列哪个操作特别耗时?:____
    A 求链表的长度
    B 在表头添加结点
    C 删除表头
    D 判断是否为空链表
    答案
    1=>C 2=>A

    带表头的单链表

    notion image
    最简单链表的弱点:
    • 在指定位置插入、删除,都需要该位置的前趋结点
    • 为了方便查找后进一步处理,查找后返回目标的前趋,可是还要兼顾“找不到”这个信息
    • 每次操作后都要返回新的头结点很不方便。
    • 删除和查找,逻辑重复,坏味道。。。
    • 删除所有结点怎么处理?
    增加一个头结点,即可解决很多问题。
    插入,插入为 p 的后继
    notion image
    任意位置的插入
    notion image
    notion image
    删除并不负责释放空间。这样设计很灵活。
    因为,使用者可能想把某个结点摘下来,挂到其它地方去

    动态内存的管理

    从这个实际的例子看到:
    • 只要可行,就优先执行:谁申请,谁释放的原则
    • 该原则,很难完全贯彻执行,分离的管理要小心、细致,很容易泄漏
    • 照顾 API 设计的原则:尽量不要重复;不要冗余;尽量灵活;尽量易于使用
    实时效果反馈
    1下列哪个==不是== 增加表头结点,带来的好处:____
    A 更方便地返回目标结点的前趋
    B 可以减少 NULL 指针的判断
    C 可以避免总是去更改 head
    D 可以更快找到尾结点
    2动态内存管理的一般原则是:____
    A 谁申请,谁负责释放
    B 被调方申请,主调方释放
    C 一个被调函数中申请,在另一个被调函数中释放
    D 较早申请的,较先释放
    答案
    1=>D 2=>A

    双向循环链表

    notion image
    增加表头后,单向链表仍有缺点:
    • 从当前结点找它的前趋很吃力
    • 从表头找到表尾很吃力,因而在表尾添加很麻烦
    • 插入、删除时,总是持有当前结点的前趋,这很不直观。
    解决方案:
    没有免费的午餐,
    牺牲空间,换来方便……
    notion image
    增加了一个 prev 数据域,与 next 呈对称之势
    • 在栈中创建头结点的正确姿势
    这是先让蛇咬住自己的尾巴,形成一个闭合的空环
    • 在 p 结点之前,挂接 q 结点(插入)
    notion image
    先挂红指针,后挂粉色指针
    • 删除当前结点
    这里有个 API 设计技巧:
    为什么要返回 p?p 是主调方送来的,我还原样送回去?
    为了 主调方的 接力写法
    看这个删除所有结点的表达法:
    实时效果反馈
    1双向循环链表的好处,说法==错误==的是:____
    A 可以快速找到尾结点
    B 可以很方便在尾部添加
    C 可以很快求出链表长度
    D 可以很快找出当前结点的前趋和后继
    2在双向循环链表中插入新结点 q,需要更改几个指针?:____
    A 1
    B 2
    C 3
    D 4
    答案
    1=>C 2=>D

    约瑟夫环

    notion image
    【问题】
    有 n 个小朋友排成一个圆圈,编号 1~n (顺时针)。
    从 1 号开始,顺时针报数 1, 2, 3...,报到 3 的小朋友出列,下一个继续从 1 开始报。
    求最后剩下的小朋友是几号?
    【分析】
    构建一个与问题相仿的模型:
    单向循环链表,无表头
    data 中存小朋友的编号
    不断重复游戏规则,最后剩下一个小朋友时,输出它的号码
    【构建的过程很重要】
    • 自顶向下的风格
      • 先不要陷入细节,从宏观上写,先写需求,后写实现
        复杂的逻辑分解开,放在不同的函数里
    • 测试驱动的风格
      • 代码未动,测试先行
        边写边测试,不要等全写完了,一堆的错误
    实时效果反馈
    1使用循环链表,我们==不可以==做?____
    A 连续地在表头插入时,可以不用更改head指针
    B 方便地从表尾回到表头
    C 方便地找到前趋结点
    D 方便地找到后继结点
    2free 与 delete 的区别是?____
    A free 只是释放空间,并不知道类型,不会调用相应的析构函数
    B delete 比 free 释放更规范,是新标准
    C delete 效率更高
    D delete 会进行碎片清理
    答案
    1=>C 2=>A
    相关文章
    线上课 #18:研究性学习开题仪式 & 如何科学地提问
    Lazy loaded image
    线上课 #17:栈与队列
    Lazy loaded image
    线上课 #16:Git & GitHub 教程
    Lazy loaded image
    线下课 #5:研究性学习动员
    Lazy loaded image
    线下课 #4:氵课
    Lazy loaded image
    线下课 #3:Web 前端“速成”
    Lazy loaded image
    DTIOC 2024.11 题目与参考题解算法竞赛入门教程
    Loading...
    DrimTech
    DrimTech
    一群热爱信息技术,善于创造的羊羔
    最新发布
    线上课 #18:研究性学习开题仪式 & 如何科学地提问
    2025-1-13
    线上课 #17:栈与队列
    2025-1-13
    『林桛杨高』Demo 带你漫游杨高
    2025-1-9
    直面挑战,追求卓越——DrimTech 2024
    2024-12-31
    DrimTech 祝大家 1024 程序员节快乐
    2024-12-31
    邮箱添加别名教程
    2024-12-29
    公告
    🎉 drim.cc 🎉
    DrimTech 官方域名,它来了!