C++带头双向循环链表超详细解析

yizhihongxing

C++带头双向循环链表超详细解析

1. 什么是带头双向循环链表?

带头双向循环链表(DCLL)是一种数据结构,它由一系列节点组成,并将它们通过指针连接起来。每个节点包含两个指针,分别指向其前驱节点和后继节点,同时还保存了一个值域。

带头双向循环链表有两个特点:

  1. 它头指针head是一个“虚拟节点”,它并不存储数据,仅仅用来标记链表的开始。因此,DCLL链表中不会出现“头指针为空”的情况。

  2. 它是个环,即最后一个节点的后继节点指向head,而head的前驱节点指向最后一个节点。因此,我们可以在列表中沿着前驱和后继指针向前或向后移动,直到回到head,实现一个循环访问的效果。

2. 如何实现带头双向循环链表?

我们可以通过C++中的类和指针来实现带头双向循环链表。

以下是带头双向循环链表的结构体定义:

struct ListNode {
    int val;
    ListNode *prev, *next;
    ListNode(int x) : val(x), prev(nullptr), next(nullptr) {}
};

(1) 插入节点

  • 实现向链表末尾插入节点的函数:
void insert_back(ListNode *&head, int val) {
    if (head == nullptr) {
        head = new ListNode(0);  // head是一个虚拟节点
        head->prev = head->next = head;  // 初始时,head节点的前驱指针与后继指针都指向自己
    }
    ListNode *cur = new ListNode(val);
    cur->prev = head->prev;
    cur->next = head;
    head->prev->next = cur;
    head->prev = cur;
}
  • 实现向链表头部插入节点的函数:
void insert_front(ListNode *&head, int val) {
    if (head == nullptr) {
        head = new ListNode(0);  // head是一个虚拟节点
        head->prev = head->next = head;  // 初始时,head节点的前驱指针与后继指针都指向自己
    }
    ListNode *cur = new ListNode(val);
    cur->prev = head;
    cur->next = head->next;
    head->next->prev = cur;
    head->next = cur;
}

(2) 删除节点

  • 删除链表中某个值为val的节点:
void remove(ListNode *&head, int val) {
    if (head == nullptr) return;
    ListNode *cur = head->next;
    while (cur != head) {
        if (cur->val == val) {
            cur->prev->next = cur->next;
            cur->next->prev = cur->prev;
            delete cur;
            return;
        }
        cur = cur->next;
    }
}

(3) 遍历链表

  • 遍历正向链表:
void traverse(ListNode *&head) {
    if (head == nullptr) return;
    ListNode *cur = head->next;
    while (cur != head) {
        cout << cur->val << " ";
        cur = cur->next;
    }
}
  • 遍历反向链表:
void traverse_reverse(ListNode *&head) {
    if (head == nullptr) return;
    ListNode *cur = head->prev;
    while (cur != head) {
        cout << cur->val << " ";
        cur = cur->prev;
    }
}

3. 两条示例说明

下面分别演示向链表末尾插入元素和向链表头部插入元素的用法:

int main() {
    ListNode *head = nullptr;
    // 向链表末尾插入元素
    insert_back(head, 1);
    insert_back(head, 2);
    insert_back(head, 3);
    traverse(head);  // 正向遍历:1 2 3
    traverse_reverse(head);  // 反向遍历:3 2 1

    // 向链表头部插入元素
    insert_front(head, 4);
    insert_front(head, 5);
    insert_front(head, 6);
    traverse(head);  // 正向遍历:6 5 4 1 2 3
    traverse_reverse(head);  // 反向遍历:3 2 1 4 5 6

    return 0;
}

以上两个示例可以很好地演示带头双向循环链表的插入节点和遍历函数的用法。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++带头双向循环链表超详细解析 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 深入了解Synthetix V3:功能、优势和未来计划

    深入了解Synthetix V3:功能、优势和未来计划 Introduction Synthetix 是一个去中心化的合成资产协议,它在区块链上提供对各种资产(如 BTC、ETH、黄金和美元)的合成替代品。Synthetix V3 也称为 L2,这是 Synthetix 协议的最新版本,它通过在 Optimism 等 Layer 2 解决方案上部署 Synt…

    other 2023年6月26日
    00
  • 解读Jvm的内存结构与GC及jvm参数调优

    解读Jvm的内存结构与GC及jvm参数调优攻略 1. Jvm的内存结构 Jvm的内存结构主要分为以下几个部分: 方法区(Method Area):用于存储类的信息、常量、静态变量等。在JDK8及之前的版本中,方法区被实现为永久代(Permanent Generation),而在JDK8及之后的版本中,被实现为元空间(Metaspace)。 堆(Heap):用…

    other 2023年7月31日
    00
  • SpringBoot中整合Minio文件存储的安装部署过程

    下面就来分享一下”SpringBoot中整合Minio文件存储的安装部署过程”的攻略吧。 一、安装部署Minio 步骤1:下载Minio 从 Minio的官方网站 下载Minio服务端的压缩包。解压后,可以看到其中包含了可执行的minio程序。 步骤2:启动Minio 执行以下命令启动单节点Minio服务: ./minio server /data 其中/d…

    other 2023年6月25日
    00
  • js的基本数据类型与引用数据类型

    下面是关于JavaScript的基本数据类型与引用数据类型的完整攻略,包括定义、区别、使用方法和两个示例说明。 定义 JavaScript中的数据类型分为基本数据类型和引用数据类型。基本数据类型包括:数字、字符串、布尔值、null和undefined。引用数据类型包括:对象、数组和函数。 区别 基本数据类型和引用数据类型的区别在于,基本数据类型的值是简单的数…

    other 2023年5月6日
    00
  • 几款好用的前端开发编辑器推荐安利

    当今的前端开发编辑器数量众多,有很多种选择,而且每个编辑器都有自己的优势和不足。下面介绍几款好用的前端开发编辑器,供大家选择。 Visual Studio Code Visual Studio Code 是一个涵盖了很多编程语言的轻量级代码编辑器,支持 Windows、Linux 和 Mac OS X 等操作系统,是目前最流行的前端编辑器之一。这个编辑器可以…

    other 2023年6月26日
    00
  • lbe安全大师主动防御加载失败怎么办

    下面是针对“lbe安全大师主动防御加载失败怎么办”的完整攻略。 什么是lbe安全大师 lbe安全大师是一款安卓智能手机安全软件,它可以帮助你检测并清除手机里的病毒和恶意软件,保护你的隐私和数据安全。此外,lbe安全大师还可以进行主动防御,阻止恶意软件在系统中的行为。 加载失败可能原因 当我们在使用lbe安全大师的主动防御功能时,有时会遇到加载失败的情况。这可…

    other 2023年6月25日
    00
  • r-如何更改ggplot2的scale_fill_brewer中仅一个值的颜色?

    R-如何更改ggplot2的scale_fill_brewer中仅一个值的颜色? 在ggplot2中,scale_fill_brewer函数可以用于设置颜色调色板。有时候,我们需要改调色板中仅一个值的颜色。本文将介绍如何实现这个目标,并提供两个示例说明。 步骤1:使用scale_fill_manual函数 我们可以使用scale_manual函数来手动设置色…

    other 2023年5月8日
    00
  • asp.net 文件路径之获得虚拟目录的网站的根目录

    获取虚拟目录的根目录常用于ASP.NET应用程序中引用相对于根目录的文件或路径。以下是获取虚拟目录根目录的步骤: 步骤1:获取HttpContext对象 我们可以通过HttpContext对象来获得虚拟目录的根目录。 HttpContext context = HttpContext.Current; 步骤2:获取请求对象 HttpContext对象有一个R…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部