26考研——线性表_ 线性表的链式表示_双循环链表(2)

news2025/4/7 3:28:56

408答疑


文章目录

  • 三、 线性表的链式表示
    • 双循环链表
      • 单链表与双链表的比较
        • 单链表的特点
        • 双链表的特点
      • 双链表上基本操作的实现
        • 双链表的插入操作
        • 双链表的删除操作
      • 双链表的代码实操
        • 定义结点
        • 创建一个结点
        • 带头结点的双链表初始化
        • 创建双链表
        • 打印双链表
        • 查找结点
        • 插入结点
          • 在指定节点后插入新节点
          • 在指定节点前插入新节点
        • 删除结点
        • 反转链表
        • 排序链表
      • 循环链表
        • 循环单链表
          • 操作描述
          • 操作特点
        • 循环双链表
      • 链表的分类
  • 五、参考资料
    • 鲍鱼科技课件
    • 26王道考研书


三、 线性表的链式表示

双循环链表

单链表与双链表的比较

单链表的特点
  • 单链表结点中只有一个指向其后继的指针,使得单链表只能从前往后依次遍历。
  • 访问某个结点的前驱(插入、删除操作时),只能从头开始遍历,访问前驱的时间复杂度为 O ( n ) O(n) O(n)
  • 为了克服单链表的这个缺点,引入了双链表。
双链表的特点
  • 双链表结点中有两个指针 priornext,分别指向其直接前驱和直接后继,如下图所示。表头结点的 prior 域和尾结点的 next 域都是 NULL

在这里插入图片描述

  • 双链表在单链表结点中增加了一个指向其前驱的指针 prior,因此双链表的按值查找和按位查找的操作与单链表的相同。但双链表在插入和删除操作的实现上,与单链表有着较大的不同。这是因为“链”变化时也需要对指针 prior 做出修改,其关键是保证在修改的过程中不断链。此外,双链表可以很方便地找到当前结点的前驱,因此,插入、删除操作的时间复杂度仅为 O ( 1 ) O(1) O(1)

双链表上基本操作的实现

双链表的插入操作
  • 在双链表中 p 所指的结点之后插入结点 *s,其指针的变化过程如图所示。

在这里插入图片描述

  • 插入操作的步骤如下:

    1. s->next 指向 p->next
    2. p->next->prior 指向 s
    3. s->prior 指向 p
    4. p->next 指向 s
  • 上述代码的语句顺序不是唯一的,但也不是任意的。步骤 1 必须在步骤 4 之前,否则 *p 的后继结点的指针就会丢失,导致插入失败。

双链表的删除操作
  • 删除双链表中结点 *p 的后继结点 *q,其指针的变化过程如图所示。

在这里插入图片描述

  • 删除操作的步骤如下:

    1. p->next 指向 q->next
    2. q->next->prior 指向 p
    3. 释放 q 结点空间

双链表的代码实操

定义结点
  • 定义双链表的节点类型,包括数据域、前驱指针和后继指针。
typedef struct DCListNode {
    ElemType data;          // 数据域
    struct DCListNode *prev; // 前驱指针
    struct DCListNode *next; // 后继指针
} DCListNode, *DCLinkList;
创建一个结点
  • 创建并初始化一个新的双链表节点。
DCListNode* buyNode(ElemType x) {
    DCListNode *s = (DCListNode*)malloc(sizeof(DCListNode));
    s->data = x;
    return s;
}
带头结点的双链表初始化
  • 初始化一个带头结点的双链表。
void initDCList(DCListNode **head) {
    *head = (DCListNode*)malloc(sizeof(DCListNode));
    (*head)->prev = *head;
    (*head)->next = *head;
}
创建双链表
  • 根据给定数组创建一个双链表。
void createDCList(DCLinkList DCL, ElemType ar[], int n) {
    DCListNode *p = DCL;
    for (int i = 0; i < n; ++i) {
        DCListNode *s = (DCListNode*)malloc(sizeof(DCListNode));
        s->data = ar[i];
        s->prev = p->prev;
        s->next = p;
        p->prev->next = s;
        p->prev = s;
    }
}
打印双链表
  • 从头结点的下一个节点开始,打印链表中的每个节点数据,直到回到头结点。
void printDCList(DCLinkList DCL) {
    DCListNode *p = DCL->next;
    while (p != DCL) {
        printf("%d-->", p->data);
        p = p->next;
    }
    printf("Over.\n");
}
查找结点
  • 从头结点开始,遍历链表直到找到目标节点或到达头结点。
DCListNode* findDCNode(DCLinkList DCL, ElemType key) {
    DCListNode *p = DCL->next;
    while (p != DCL && p->data != key)
        p = p->next;

    if (p != DCL)
        return p; // 找到了节点

    return NULL;  // 没有找到节点
}
插入结点
在指定节点后插入新节点
  • 在双链表中指定节点 pos 之后插入一个新节点 x。
void insertDCNodeBack(DCLinkList DCL, DCListNode *pos, ElemType x) {
    DCListNode *s = buyNode(x);
    s->prev = pos;
    s->next = pos->next;
    s->next->prev = s;
    s->prev->next = s;
}
在指定节点前插入新节点
  • 在双链表中指定节点 pos 之前插入一个新节点 x。
void insertDCNodeFront(DCLinkList DCL, DCListNode *pos, ElemType x) {
    DCListNode *s = buyNode(x);
    s->prev = pos->prev;
    s->next = pos;
    s->next->prev = s;
    s->prev->next = s;
}
删除结点
  • 找到目标节点,调整前后节点的指针并释放目标节点。
void deleteDCNode(DCLinkList DCL, ElemType key) {
    DCListNode *p = findDCNode(DCL, key);
    if (p == NULL)
        return; // 删除失败

    p->prev->next = p->next;
    p->next->prev = p->prev;
    free(p);
}
反转链表
  • 逐个摘除链表中的节点并重新插入到链表头部。
void reverseDCList(DCLinkList DCL) {
    DCListNode *p = DCL->next;
    DCListNode *q = p->next;
    p->next = DCL;
    DCL->prev = p;

    while (q != DCL) {
        p = q;
        q = q->next;

        p->next = DCL->next;
        p->prev = DCL;
        p->prev->next = p;
        p->next->prev = p;
    }
}
排序链表
  • 逐个摘除链表中的节点并按顺序插入到链表中。
void sortDCList(DCLinkList DCL) {
    DCListNode *p = DCL->next;
    DCListNode *q = p->next;

    p->next = DCL;
    DCL->prev = p;

    while (q != DCL) {
        p = q;
        q = q->next;

        DCListNode *cur = DCL->next;
        while (cur != DCL && p->data > cur->data)
            cur = cur->next;

        p->next = cur;
        p->prev = cur->prev;
        p->prev->next = p;
        p->next->prev = p;
    }
}

循环链表

循环单链表
  • 循环单链表的特点是最后一个结点的 next 指针指向头结点,形成一个环。这种结构使得链表可以从任意位置开始遍历,而不必担心到达链表的末尾,如下图所示。

在这里插入图片描述

  • 特点
    • 表尾结点的 next 域指向头结点。
    • 判空条件不是头结点的指针是否为空,而是它是否等于头指针 L
操作描述
  • 循环单链表的插入、删除算法与单链表的几乎一样,所不同的是,若操作是在表尾进行,则执行的操作不同,以让单链表继续保持循环的性质。这是因为循环单链表是一个“环”,所以在任何位置上的插入和删除操作都是等价的,而无须判断是否是表尾。
操作特点
  • 在单链表中只能从表头结点开始往后顺序遍历整个链表,而循环单链表可以从表中的任意一个结点开始遍历整个链表。
  • 有时对循环单链表不设头指针而仅设尾指针,以使得操作效率更高。其原因是,若设的是头指针,对在表尾插入元素需要 O ( n ) O(n) O(n) 的时间复杂度,而若设的是尾指针 rr->next 即头指针,对在表头或表尾插入元素都只需要 O ( 1 ) O(1) O(1) 的时间复杂度。
循环双链表
  • 循环双链表在循环单链表的基础上增加了一个指向前驱的指针 prior,使得链表可以从任意结点向前或向后遍历,如下图所示。

在这里插入图片描述

  • 特点
    • 头结点的 prior 指针指向表尾结点。
    • 尾结点的 next 指针指向头结点。
    • 判空条件是头结点的 priornext 域都等于 L

链表的分类

  • 循环链表可以是单链表或双链表,可以带头结点或不带头结点,也可以是循环的或非循环的( 2 3 2^3 23种可能性)。这三种特性可以组合出八种不同的链表类型,如下图所示。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述

五、参考资料

鲍鱼科技课件

b站免费王道课后题讲解:
在这里插入图片描述

网课全程班:
在这里插入图片描述

26王道考研书

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2328845.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于springboot的考研成绩查询系统(源码+lw+部署文档+讲解),源码可白嫖!

摘要 这些年随着Internet的迅速发展&#xff0c;我们国家和世界都已经进入了互联网大数据时代&#xff0c;计算机网络已经成为了整个社会以及经济发展的巨大动能&#xff0c;考研成绩查询管理事务现在已经成为社会关注的重要内容&#xff0c;因此运用互联网技术来提高考研成绩…

es自定义ik分词器中文词库实现热更新

基于web地址的方式实现ik分词热更新。 操作系统&#xff1a;win 11 es version&#xff1a;8.6.2 ik version&#xff1a;8.6.2 1、创建web服务&#xff0c;并提供ik查询词库接口 编写分词http url代码&#xff0c;返回自定义分词内容分词词库数据来自业务需求&#xff0c;存…

OpenStack 卷虚拟机跨租户迁移方案

目标&#xff1a;迁移租户A的卷虚机到租户B 场景&#xff1a;使用卷虚拟机&#xff0c;租户a和b使用相同网络 租户A的操作&#xff1a; 1.记录虚拟机的ip地址&#xff0c;Mac信息&#xff0c; nova interface-list neutron port-show 2.对虚拟机进行关机操作&#xff0c;将…

添加购物车功能

业务需求&#xff1a; 用户提交三个字段&#xff0c;服务端根据提交的字段判断是菜品还是套餐&#xff0c;根据菜品或者套餐添加购物车表中。 代码实现 RestController Slf4j RequestMapping("/user/shoppingCart") public class ShoppingCartController {Autowired…

Python爬虫第2节-网页基础和爬虫基本原理

目录 一、网页基础 1.1 网页的组成 1.2 网页的结构 1.3 节点树及节点间的关系 1.4 选择器 二、爬虫的基本原理 2.1 爬虫概述 2.2 能抓怎样的数据 2.3 JavaScript 渲染页面 一、网页基础 使用浏览器访问网站时&#xff0c;我们会看到各式各样的页面。你是否思考过&…

【网络协议】三次握手与四次挥手

例如我们使用MobaXterm登录服务器的时候&#xff0c;基于TCP协议的之间是如何进行通信的&#xff1f; 使用工具&#xff1a;wireshark抓取传输层TCP协议 三次握手 mobaxterm&#xff1a;登录服务器触发三次握手 wireshark过滤分析 ip.addr 192.168.3.239 192.168.3.239登录…

JS API

const变量优先 即对象、数组等引用类型数据可以用const声明 API作用和分类 DOM (ducument object model) 操作网页内容即HTML标签的 树状模型 HTML中标签 JS中对象 最大对象 document 其次大 html 以此类推 获取DOM对象 CSS 中 使用选择器 JS 中 选多个 时代的眼泪 修…

“一路有你”公益行携手《东方星动》走进湖南岳阳岑川镇中心小学

2025年4月2日&#xff0c;“一路有你”公益行携手《东方星动》走进湖南岳阳岑川镇&#xff0c;一场充满爱与温暖的捐赠仪式在岑川镇中心小学隆重举行。这是一场跨越千里的爱心捐赠&#xff0c;也是一场别开生面的国防教育&#xff0c;更是一场赋能提质的文化盛宴。 岑川镇地处湘…

vue组件开发:什么是VUE组件?

什么是VUE组件 在我们实际开发过程中你也许会发现有很多代码是重复的&#xff0c;它们可能是一个按钮、一个表单、一个列表等等&#xff0c;其中最为显著的应该是列表。 以CSDN的首页为例&#xff1a; 上述截图中的文章列表可能会在多处出现&#xff0c;比如此截图是精选博客…

仿小红书社交源码+及时通讯聊天软件APP源码

多端支持&#xff0c;数据互通 本程序支持H5、小程序、安卓、iOS四端运行&#xff0c;共用同一套后台管理系统&#xff0c;确保数据同步&#xff0c;用户可在不同设备上无缝切换&#xff0c;实现真正的多端互通。 技术架构 前端技术&#xff1a;Vue2、uni-app、HTML、CSS、Jav…

Java基础:面向对象进阶(二)

01-static static修饰成员方法 static注意事项&#xff08;3种&#xff09; static应用知识&#xff1a;代码块 static应用知识&#xff1a;单列模式 02-面向对象三大特征之二&#xff1a;继承 什么是继承&#xff1f; 使用继承有啥好处? 权限修饰符 单继承、Object类 方法重…

ttkbootstrap 实现日期选择器, 开始和结束时间

ttkbootstrap 实现日期选择器&#xff0c; 开始和结束时间 1. 展示 2. 打印 3. 源码 from datetime import datetime import ttkbootstrap as ttkclass DateTimeEntryStart(ttk.Frame):def __init__(self, masterNone, **kwargs):super().__init__(master, **kwargs)self.dat…

Vulnhub-PrinkysPalacev3

Vulnhub-PrinkysPalacev3 1、主机发现 arp-scan -l 扫描同网段 2、端口扫描 nmap -sS -sV 192.168.66.185 nmap -sS -A -T4 -p- 192.168.66.185 nmap --scriptvuln 192.168.66.185 PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 2.0.8 or later 5555/tcp o…

matlab从pytorch中导入LeNet-5网络框架

文章目录 一、Pytorch的LeNet-5网络准备二、保存用于导入matlab的model三、导入matlab四、用matlab训练这个导入的网络 这里演示从pytorch的LeNet-5网络导入到matlab中进行训练用。 一、Pytorch的LeNet-5网络准备 根据LeNet-5的结构图&#xff0c;我们可以写如下结构 import…

Spring Boot向Vue发送消息通过WebSocket实现通信

注意&#xff1a;如果后端有contextPath&#xff0c;如/app&#xff0c;那么前端访问的url就是ip:port/app/ws 后端实现步骤 添加Spring Boot WebSocket依赖配置WebSocket端点和消息代理创建控制器&#xff0c;使用SimpMessagingTemplate发送消息 前端实现步骤 安装sockjs-…

网络编程—Socket套接字(UDP)

上篇文章&#xff1a; 网络编程—网络概念https://blog.csdn.net/sniper_fandc/article/details/146923380?fromshareblogdetail&sharetypeblogdetail&sharerId146923380&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目录 1 概念 2 Soc…

视频设备轨迹回放平台EasyCVR综合智能化,搭建运动场体育赛事直播方案

一、背景 随着5G技术的发展&#xff0c;体育赛事直播迎来了新的高峰。无论是NBA、西甲、英超、德甲、意甲、中超还是CBA等热门赛事&#xff0c;都是值得记录和回放的精彩瞬间。对于体育迷来说&#xff0c;选择观看的平台众多&#xff0c;但是作为运营者&#xff0c;搭建一套体…

AIGC实战——CycleGAN详解与实现

AIGC实战——CycleGAN详解与实现 0. 前言1. CycleGAN 基本原理2. CycleGAN 模型分析3. 实现 CycleGAN小结系列链接 0. 前言 CycleGAN 是一种用于图像转换的生成对抗网络(Generative Adversarial Network, GAN)&#xff0c;可以在不需要配对数据的情况下将一种风格的图像转换成…

VS2022远程调试Linux程序

一、 1、VS2022安装参考 VS Studio2022安装教程&#xff08;保姆级教程&#xff09;_visual studio 2022-CSDN博客 注意&#xff1a;勾选的时候&#xff0c;要勾选下方的选项&#xff0c;才能调试Linux环境下运行的程序&#xff01; 2、VS2022远程调试Linux程序测试 原文参…

345-java人事档案管理系统的设计与实现

345-java人事档案管理系统的设计与实现 项目概述 本项目为基于Java语言的人事档案管理系统&#xff0c;旨在帮助企事业单位高效管理员工档案信息&#xff0c;实现档案的电子化、自动化管理。系统涵盖了员工信息的录入、查询、修改、删除等功能&#xff0c;同时具备权限控制和…