【408数据结构 06】双链表、循环链表、静态链表
专栏导航 :本篇是《408数据结构:C++手写实现 + 图解 + 真题》第 06 篇。
上一篇 :【408数据结构 05】单链表进阶:反转、找中点、判环、合并
下一篇:【408数据结构 07】栈:顺序栈与链栈,C++手写
### 文章目录
- [【408数据结构 06】双链表、循环链表、静态链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [@toc](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [一、本篇考点定位](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [二、双链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.1 定义](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.2 图解](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.3 结点定义](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.4 初始化](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.5 插入操作](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.6 删除操作](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.7 按位查找](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [2.8 双链表的优势](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [三、循环链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [3.1 循环单链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [3.2 循环双链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [3.3 循环链表的优势](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [3.4 约瑟夫环问题](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [四、静态链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.1 定义](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.2 图解](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.3 结构定义](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.4 初始化](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.5 插入操作](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.6 删除操作](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [4.7 静态链表的优缺点](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [五、四种链表对比](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [六、完整测试代码](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [七、408 真题与考法](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [7.1 选择题:双链表插入](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [7.2 选择题:双链表删除](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [7.3 选择题:循环链表判空](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [7.4 选择题:静态链表](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [7.5 综合题:双链表删除结点](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [7.6 综合题:循环链表合并](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [八、易错点总结](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
- [九、总结与下一篇预告](#文章目录 【408数据结构 06】双链表、循环链表、静态链表 @[toc] 一、本篇考点定位 二、双链表 2.1 定义 2.2 图解 2.3 结点定义 2.4 初始化 2.5 插入操作 2.6 删除操作 2.7 按位查找 2.8 双链表的优势 三、循环链表 3.1 循环单链表 3.2 循环双链表 3.3 循环链表的优势 3.4 约瑟夫环问题 四、静态链表 4.1 定义 4.2 图解 4.3 结构定义 4.4 初始化 4.5 插入操作 4.6 删除操作 4.7 静态链表的优缺点 五、四种链表对比 六、完整测试代码 七、408 真题与考法 7.1 选择题:双链表插入 7.2 选择题:双链表删除 7.3 选择题:循环链表判空 7.4 选择题:静态链表 7.5 综合题:双链表删除结点 7.6 综合题:循环链表合并 八、易错点总结 九、总结与下一篇预告)
一、本篇考点定位
单链表只能单向遍历,插入删除时需要找前驱,效率不高。
为了解决这些问题,出现了双链表 、循环链表 和静态链表。
408 对这三种链表的考查集中在:
| 考点 | 重要程度 | 常见题型 |
|---|---|---|
| 双链表的结点结构与插入删除 | ★★★★★ | 选择题 + 算法题 |
| 循环单链表的判空与遍历 | ★★★★ | 选择题 |
| 循环双链表的特点 | ★★★★ | 选择题 |
| 静态链表的数组模拟 | ★★★★ | 选择题 |
| 三种链表与单链表的对比 | ★★★★ | 选择题 |
一句话概括本篇目标:
掌握双链表的指针操作、循环链表的判空条件、静态链表的数组模拟,能区分四种链表的特点。
二、双链表
2.1 定义
双链表(Doubly Linked List)每个结点有两个指针:
prior:指向前驱结点。next:指向后继结点。
结点结构:
text
+---------+---------+---------+
| prior | data | next |
+---------+---------+---------+
2.2 图解
带头结点的双链表:
text
+------+------+------+ +------+------+------+ +------+------+------+
NULL <--|prior | data | next |<-->|prior | data | next |<-->|prior | data | next |--> NULL
+------+------+------+ +------+------+------+ +------+------+------+
头结点 第1个结点 第2个结点
2.3 结点定义
cpp
typedef int ElemType;
typedef struct DNode {
ElemType data;
struct DNode *prior;
struct DNode *next;
} DNode, *DLinkList;
2.4 初始化
cpp
bool InitDList(DLinkList &L) {
L = new DNode;
if (L == nullptr) {
return false;
}
L->prior = nullptr;
L->next = nullptr;
return true;
}
2.5 插入操作
在结点 p 之后插入结点 s。
图解:
text
插入前:
... <--> [p] <--> [q] <--> ...
创建新结点 s:
s -> [x]
插入步骤:
1. s->next = p->next; // s 的后继指向 q
2. if (p->next != nullptr) p->next->prior = s; // q 的前驱指向 s
3. s->prior = p; // s 的前驱指向 p
4. p->next = s; // p 的后继指向 s
插入后:
... <--> [p] <--> [s] <--> [q] <--> ...
代码:
cpp
bool DListInsertAfter(DNode *p, ElemType e) {
if (p == nullptr) {
return false;
}
DNode *s = new DNode;
s->data = e;
s->next = p->next;
if (p->next != nullptr) {
p->next->prior = s;
}
s->prior = p;
p->next = s;
return true;
}
注意:顺序不能乱 ,尤其是第 2 步要在第 4 步之前,否则 p->next 已经被修改。
2.6 删除操作
删除结点 p 的后继结点 q。
图解:
text
删除前:
... <--> [p] <--> [q] <--> [r] <--> ...
删除步骤:
1. q = p->next;
2. p->next = q->next;
3. if (q->next != nullptr) q->next->prior = p;
4. delete q;
删除后:
... <--> [p] <--> [r] <--> ...
代码:
cpp
bool DListDeleteAfter(DNode *p, ElemType &e) {
if (p == nullptr || p->next == nullptr) {
return false;
}
DNode *q = p->next;
e = q->data;
p->next = q->next;
if (q->next != nullptr) {
q->next->prior = p;
}
delete q;
return true;
}
2.7 按位查找
双链表可以双向查找,但按位查找仍然需要遍历。
cpp
DNode *DGetElem(DLinkList L, int i) {
if (i < 1) {
return nullptr;
}
DNode *p = L->next;
int j = 1;
while (p != nullptr && j < i) {
p = p->next;
j++;
}
return p;
}
2.8 双链表的优势
| 操作 | 单链表 | 双链表 |
|---|---|---|
| 找前驱 | O(n) | O(1) |
| 找后继 | O(1) | O(1) |
| 插入(已知前驱) | O(1) | O(1) |
| 删除(已知结点) | O(n)(需找前驱) | O(1) |
| 空间开销 | 一个指针 | 两个指针 |
408 常考:
双链表删除某个结点
p时,可以直接通过p->prior找到前驱,时间复杂度 O(1)。单链表删除结点
p时,需要从头找前驱,时间复杂度 O(n)。
三、循环链表
3.1 循环单链表
循环单链表:尾结点的 next 指向头结点,形成一个环。
图解:
text
L -> [头] -> [a1] -> [a2] -> [a3] -> [头]
^ |
|______________________________|
特点:
- 从任意结点出发都能遍历整个链表。
- 判空条件 :
L->next == L。 - 尾结点的
next指向L。
代码:
cpp
bool InitCircularList(LinkList &L) {
L = new LNode;
if (L == nullptr) {
return false;
}
L->next = L; // 指向自己
return true;
}
bool IsEmptyCircular(LinkList L) {
return L->next == L;
}
遍历:
cpp
void PrintCircularList(LinkList L) {
LNode *p = L->next;
while (p != L) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
3.2 循环双链表
循环双链表:尾结点的 next 指向头结点,头结点的 prior 指向尾结点。
图解:
text
+------+------+------+ +------+------+------+ +------+------+------+
+--->|prior | data | next |<-->|prior | data | next |<-->|prior | data | next |<---+
| +------+------+------+ +------+------+------+ +------+------+------+ |
| 头结点 第1个结点 第2个结点 |
| |
+----------------------------------------------------------------------------------+
特点:
- 判空条件 :
L->next == L && L->prior == L。 - 任意结点出发都能双向遍历。
- 插入删除时不需要判断
nullptr,因为前后都有结点。
3.3 循环链表的优势
- 从任意结点出发都能遍历全表。
- 尾指针操作方便 :如果维护尾指针
rear,则rear->next就是头结点,插入删除首尾都很方便。 - 适合环形队列、约瑟夫环等问题。
3.4 约瑟夫环问题
题目:
n 个人围成一圈,从第 1 个人开始报数,报到 m 的人出列,然后从下一个人继续报数,直到所有人出列。
思路:
用循环链表模拟,每次数到 m 就删除结点。
代码:
cpp
void Josephus(int n, int m) {
LinkList L;
InitCircularList(L);
LNode *r = L;
for (int i = 1; i <= n; i++) {
LNode *s = new LNode;
s->data = i;
s->next = L;
r->next = s;
r = s;
}
LNode *p = L->next;
LNode *pre = L;
while (p->next != p) {
for (int i = 1; i < m; i++) {
pre = p;
p = p->next;
}
cout << p->data << " ";
pre->next = p->next;
delete p;
p = pre->next;
}
cout << p->data << endl;
delete p;
delete L;
}
四、静态链表
4.1 定义
静态链表用数组模拟链表,每个数组元素包含:
data:数据域。next:游标,存放下一个元素在数组中的下标。
结点结构:
text
+---------+---------+
| data | next |
+---------+---------+
4.2 图解
text
下标: 0 1 2 3 4 5
+-----+-----+-----+-----+-----+-----+
data: | | a | b | c | d | |
next: | 1 | 2 | 3 | 4 | 0 | |
+-----+-----+-----+-----+-----+-----+
头结点 第1个 第2个 第3个 第4个 备用
- 下标 0 是头结点,
next = 1表示第一个数据元素在下标 1。 - 下标 4 的
next = 0,表示链表结束。 - 下标 5 是备用结点。
4.3 结构定义
cpp
#define MAXSIZE 100
typedef struct {
ElemType data;
int next;
} SLinkList[MAXSIZE];
4.4 初始化
cpp
void InitStaticList(SLinkList L) {
for (int i = 0; i < MAXSIZE - 1; i++) {
L[i].next = i + 1;
}
L[MAXSIZE - 1].next = 0;
L[0].next = 0; // 头结点 next 为 0,表示空表
}
4.5 插入操作
在第 i 个位置插入元素 e。
cpp
bool StaticListInsert(SLinkList L, int i, ElemType e) {
if (i < 1) {
return false;
}
int k = 0; // 头结点下标
for (int j = 1; j < i; j++) {
k = L[k].next;
if (k == 0) {
return false;
}
}
// 分配新结点
int newNode = L[0].next;
if (newNode == 0) {
return false; // 空间已满
}
L[0].next = L[newNode].next;
L[newNode].data = e;
L[newNode].next = L[k].next;
L[k].next = newNode;
return true;
}
4.6 删除操作
删除第 i 个元素。
cpp
bool StaticListDelete(SLinkList L, int i, ElemType &e) {
if (i < 1) {
return false;
}
int k = 0;
for (int j = 1; j < i; j++) {
k = L[k].next;
if (k == 0) {
return false;
}
}
int q = L[k].next;
if (q == 0) {
return false;
}
e = L[q].data;
L[k].next = L[q].next;
// 回收结点
L[q].next = L[0].next;
L[0].next = q;
return true;
}
4.7 静态链表的优缺点
优点:
- 不用指针,适合不支持指针的语言。
- 插入删除不需要移动元素。
- 数组下标代替指针,方便调试。
缺点:
- 需要预先分配固定大小空间。
- 不能动态扩容。
- 游标操作容易出错。
408 常考:
静态链表中,
next存放的是数组下标,不是地址。静态链表插入删除的时间复杂度与动态链表相同。
五、四种链表对比
| 对比项 | 单链表 | 双链表 | 循环单链表 | 静态链表 |
|---|---|---|---|---|
| 指针数量 | 1 个 | 2 个 | 1 个 | 游标 |
| 找前驱 | O(n) | O(1) | O(n) | O(n) |
| 找后继 | O(1) | O(1) | O(1) | O(1) |
| 判空 | L->next == NULL |
L->next == NULL |
L->next == L |
L[0].next == 0 |
| 尾结点 next | NULL | NULL | 指向头结点 | 0 |
| 空间开销 | 小 | 大 | 小 | 固定 |
| 随机访问 | 不支持 | 不支持 | 不支持 | 不支持 |
记忆口诀:
单链表找后继快,双链表找前驱快,循环链表转圈快,静态链表数组代。
六、完整测试代码
cpp
#include <iostream>
using namespace std;
typedef int ElemType;
// ==================== 双链表 ====================
typedef struct DNode {
ElemType data;
struct DNode *prior;
struct DNode *next;
} DNode, *DLinkList;
bool InitDList(DLinkList &L) {
L = new DNode;
if (L == nullptr) return false;
L->prior = nullptr;
L->next = nullptr;
return true;
}
void CreateDListTail(DLinkList &L, int a[], int n) {
InitDList(L);
DNode *r = L;
for (int i = 0; i < n; i++) {
DNode *s = new DNode;
s->data = a[i];
s->next = nullptr;
s->prior = r;
r->next = s;
r = s;
}
}
void PrintDList(DLinkList L) {
DNode *p = L->next;
while (p != nullptr) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
bool DListInsertAfter(DNode *p, ElemType e) {
if (p == nullptr) return false;
DNode *s = new DNode;
s->data = e;
s->next = p->next;
if (p->next != nullptr) {
p->next->prior = s;
}
s->prior = p;
p->next = s;
return true;
}
bool DListDeleteAfter(DNode *p, ElemType &e) {
if (p == nullptr || p->next == nullptr) return false;
DNode *q = p->next;
e = q->data;
p->next = q->next;
if (q->next != nullptr) {
q->next->prior = p;
}
delete q;
return true;
}
void DestroyDList(DLinkList &L) {
DNode *p = L;
while (p != nullptr) {
DNode *q = p;
p = p->next;
delete q;
}
L = nullptr;
}
// ==================== 循环单链表 ====================
typedef struct LNode {
ElemType data;
struct LNode *next;
} LNode, *LinkList;
bool InitCircularList(LinkList &L) {
L = new LNode;
if (L == nullptr) return false;
L->next = L;
return true;
}
void CreateCircularList(LinkList &L, int a[], int n) {
InitCircularList(L);
LNode *r = L;
for (int i = 0; i < n; i++) {
LNode *s = new LNode;
s->data = a[i];
s->next = L;
r->next = s;
r = s;
}
}
void PrintCircularList(LinkList L) {
LNode *p = L->next;
while (p != L) {
cout << p->data << " ";
p = p->next;
}
cout << endl;
}
// ==================== 静态链表 ====================
#define MAXSIZE 100
typedef struct {
ElemType data;
int next;
} SLinkList[MAXSIZE];
void InitStaticList(SLinkList L) {
for (int i = 0; i < MAXSIZE - 1; i++) {
L[i].next = i + 1;
}
L[MAXSIZE - 1].next = 0;
L[0].next = 0;
}
bool StaticListInsert(SLinkList L, int i, ElemType e) {
if (i < 1) return false;
int k = 0;
for (int j = 1; j < i; j++) {
k = L[k].next;
if (k == 0) return false;
}
int newNode = L[0].next;
if (newNode == 0) return false;
L[0].next = L[newNode].next;
L[newNode].data = e;
L[newNode].next = L[k].next;
L[k].next = newNode;
return true;
}
void PrintStaticList(SLinkList L) {
int p = L[0].next;
while (p != 0) {
cout << L[p].data << " ";
p = L[p].next;
}
cout << endl;
}
// ==================== 测试 ====================
int main() {
// 双链表测试
DLinkList DL;
int a[] = {1, 2, 3, 4, 5};
CreateDListTail(DL, a, 5);
cout << "双链表: ";
PrintDList(DL);
DListInsertAfter(DL->next, 99);
cout << "在第一个结点后插入99: ";
PrintDList(DL);
ElemType e;
DListDeleteAfter(DL->next, e);
cout << "删除第一个结点后的结点: " << e << endl;
cout << "删除后: ";
PrintDList(DL);
DestroyDList(DL);
// 循环单链表测试
LinkList CL;
CreateCircularList(CL, a, 5);
cout << "循环单链表: ";
PrintCircularList(CL);
// 静态链表测试
SLinkList SL;
InitStaticList(SL);
for (int i = 1; i <= 5; i++) {
StaticListInsert(SL, i, i * 10);
}
cout << "静态链表: ";
PrintStaticList(SL);
return 0;
}
运行结果:
text
双链表: 1 2 3 4 5
在第一个结点后插入99: 1 99 2 3 4 5
删除第一个结点后的结点: 99
删除后: 1 2 3 4 5
循环单链表: 1 2 3 4 5
静态链表: 10 20 30 40 50
七、408 真题与考法
7.1 选择题:双链表插入
题目:
在双链表中,在 p 所指结点之后插入 s 所指结点,正确的操作是( )。
A. s->next = p->next; p->next->prior = s; s->prior = p; p->next = s;
B. p->next = s; s->prior = p; s->next = p->next; p->next->prior = s;
C. s->prior = p; s->next = p->next; p->next = s; p->next->prior = s;
D. s->next = p->next; p->next = s; s->prior = p; p->next->prior = s;
答案:A
注意:B 中先修改了 p->next,导致 p->next 已经不是原来的后继,会出错。
7.2 选择题:双链表删除
题目:
在双链表中,删除 p 所指结点的后继结点 q,正确的操作是( )。
A. p->next = q->next; q->next->prior = p; free(q);
B. q->next->prior = p; p->next = q->next; free(q);
C. p->next = q->next; q->prior = p; free(q);
D. q->prior = p; p->next = q->next; free(q);
答案:A
7.3 选择题:循环链表判空
题目:
带头结点的循环单链表 L 为空的判断条件是( )。
A. L == NULL
B. L->next == NULL
C. L->next == L
D. L->prior == L
答案:C
7.4 选择题:静态链表
题目:
静态链表中,每个结点的 next 域存放的是( )。
A. 下一个结点的地址
B. 下一个结点的数组下标
C. 下一个结点的值
D. 下一个结点的指针
答案:B
7.5 综合题:双链表删除结点
题目:
设计一个算法,在带头结点的双链表中删除所有值为 x 的结点,并分析时间复杂度。
代码:
cpp
void DDeleteAllX(DLinkList &L, ElemType x) {
DNode *p = L->next;
while (p != nullptr) {
if (p->data == x) {
DNode *q = p;
if (p->next != nullptr) {
p->next->prior = p->prior;
}
p->prior->next = p->next;
p = p->next;
delete q;
} else {
p = p->next;
}
}
}
复杂度:
- 时间复杂度:
O(n)。 - 空间复杂度:
O(1)。
7.6 综合题:循环链表合并
题目:
有两个带头结点的循环单链表 A 和 B,设计算法将它们合并为一个循环单链表,要求时间复杂度 O(1)。
思路:
找到两个链表的尾结点,然后修改指针。
cpp
void MergeCircularList(LinkList &A, LinkList &B) {
if (A == nullptr || B == nullptr) return;
LNode *ra = A;
while (ra->next != A) {
ra = ra->next;
}
LNode *rb = B;
while (rb->next != B) {
rb = rb->next;
}
ra->next = B->next;
rb->next = A;
delete B;
}
复杂度:
- 时间复杂度:
O(n + m),需要找到尾结点。 - 空间复杂度:
O(1)。
如果维护尾指针,则时间复杂度可以降到 O(1)。
八、易错点总结
-
双链表插入顺序不能乱
先处理
s的前驱后继,再处理p和q的指针。 -
双链表删除要判断后继是否为空
if (q->next != nullptr) q->next->prior = p;不能漏。 -
循环单链表判空是
L->next == L不是
L->next == NULL。 -
循环双链表判空要同时判断前后
L->next == L && L->prior == L。 -
静态链表的
next是数组下标不是指针,0 表示结束。
-
静态链表插入要分配空闲结点
从备用链表取结点,
L[0].next是备用链表头。 -
静态链表删除要回收结点
把删除的结点插回备用链表。
-
循环链表遍历要判断是否回到头结点
while (p != L),不是while (p != nullptr)。 -
算法题最后写复杂度
时间复杂度、空间复杂度都要写。
九、总结与下一篇预告
本篇讲了:
- 双链表的结点结构与插入删除。
- 循环单链表、循环双链表的判空与遍历。
- 静态链表的数组模拟与插入删除。
- 四种链表的对比。
- 完整测试代码与 408 真题。
- 常见易错点。
一句话总结:
双链表用空间换时间,循环链表用环解决遍历问题,静态链表用数组模拟指针。
下一篇进入栈:
【408数据结构 07】栈:顺序栈与链栈,C++手写
我会讲栈的定义、顺序栈与链栈的实现、共享栈、栈的应用,配 408 真题和完整 C++ 代码。
专栏导航
- 上一篇:【408数据结构 05】单链表进阶:反转、找中点、判环、合并
- 下一篇:【408数据结构 07】栈:顺序栈与链栈,C++手写
- 专栏目录:《408数据结构:C++手写实现 + 图解 + 真题》
标签 :数据结构、C++、考研408、计算机考研、算法
分类:数据结构与算法
如果这篇对你有帮助,欢迎点赞、收藏、评论。你的支持是我持续更新的动力。