如何用C++实现双向循环链表

下面是如何用C++实现双向循环链表的完整攻略。

什么是双向循环链表

双向循环链表是一种常见的数据结构,其将每个节点都视为一个对象,一个节点除了存储自己的数据外,还会保存一个指向前一个节点和后一个节点的指针,因此可以用来表示一系列数据的集合。

在双向循环链表中,最后一个节点的指针指向第一个节点,第一个节点的指针指向最后一个节点,这种结构称为循环链表。而双向链表的特点是每个节点有两个指针,一个指针指向前一个节点,一个指针指向后一个节点。

如何实现

定义结构体

C++ 代码实现双向循环链表需要定义链表节点的结构,这里我们采用结构体的方式来定义。

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

在上面的代码中,我们定义了一个名为 ListNode 的结构体,其中包含了一个整数类型的 val 字段,一个指向前一个节点的指针 prev,一个指向后一个节点的指针 next。同时,我们为该结构体提供了一个构造函数,用来初始化节点数据。

实现插入操作

节点插入是链表的一个核心操作,它可以用来添加新的节点到链表中。

void insert(ListNode* &head, ListNode* &tail, ListNode* node) {
    if (head == nullptr) {
        head = node;
        tail = node;
        head->prev = tail;
        tail->next = head;
        return;
    }
    node->next = head;
    node->prev = tail;
    head->prev = node;
    tail->next = node;
    tail = node;
}

在上面的代码中,我们定义了一个 insert 函数,它接收三个参数:链表的头指针 head、链表的尾指针 tail 和要插入的新节点 node

当链表为空时,插入的节点即为头节点,同时也是尾节点。因此我们需要将头指针和尾指针都指向插入的节点,并将插入的节点指向自身作为下一个节点和上一个节点。

当链表不为空时,我们将插入的节点插入到链表的末尾,并将它的前驱和后继指针指向链表的头尾节点。

实现删除操作

节点删除是链表的另一个核心操作,它可以用来删除链表中的指定节点。

void erase(ListNode* &head, ListNode* &tail, ListNode* node) {
    if (head == nullptr || node == nullptr) {
        return;
    }
    if (head == tail && head == node) {
        delete node;
        head = nullptr;
        tail = nullptr;
        return;
    }
    if (node == head) {
        head = node->next;
        head->prev = tail;
        tail->next = head;
        delete node;
        return;
    }
    if (node == tail) {
        tail = node->prev;
        tail->next = head;
        head->prev = tail;
        delete node;
        return;
    }
    node->prev->next = node->next;
    node->next->prev = node->prev;
    delete node;
}

在上面的代码中,我们定义了一个 erase 函数,它接收三个参数:链表的头指针 head、链表的尾指针 tail 和要删除的节点 node

在删除节点之前,我们需要先判断链表是否为空以及要删除的节点是否存在。当链表为空或要删除的节点不存在时,直接返回。

当要删除的节点是头尾节点时,我们需要判断删除的节点是否是链表唯一的一个节点,如果是唯一的节点,则将头指针和尾指针都置空;否则,将头指针或尾指针指向该节点的下一个或上一个节点。

当要删除的节点是中间节点时,我们需要将节点的上一个节点的后继指针指向它的下一个节点,将节点的下一个节点的前驱指针指向它的上一个节点,最后删除该节点即可。

示例代码

下面给出两个示例代码,分别展示如何实现双向循环链表的插入和删除操作。

#include <iostream>

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

void insert(ListNode* &head, ListNode* &tail, ListNode* node) {
    if (head == nullptr) {
        head = node;
        tail = node;
        head->prev = tail;
        tail->next = head;
        return;
    }
    node->next = head;
    node->prev = tail;
    head->prev = node;
    tail->next = node;
    tail = node;
}

void erase(ListNode* &head, ListNode* &tail, ListNode* node) {
    if (head == nullptr || node == nullptr) {
        return;
    }
    if (head == tail && head == node) {
        delete node;
        head = nullptr;
        tail = nullptr;
        return;
    }
    if (node == head) {
        head = node->next;
        head->prev = tail;
        tail->next = head;
        delete node;
        return;
    }
    if (node == tail) {
        tail = node->prev;
        tail->next = head;
        head->prev = tail;
        delete node;
        return;
    }
    node->prev->next = node->next;
    node->next->prev = node->prev;
    delete node;
}

int main() {
    ListNode* head = nullptr;
    ListNode* tail = nullptr;

    insert(head, tail, new ListNode(1));
    insert(head, tail, new ListNode(2));
    insert(head, tail, new ListNode(3));

    ListNode* cur = head;

    std::cout << "正向遍历:" << std::endl;
    for (int i = 0; i < 3; ++i) {
        std::cout << cur->val << std::endl;
        cur = cur->next;
    }

    std::cout << "反向遍历:" << std::endl;
    for (int i = 0; i < 3; ++i) {
        std::cout << cur->val << std::endl;
        cur = cur->prev;
    }

    erase(head, tail, head);
    erase(head, tail, tail);

    cur = head;

    std::cout << "正向遍历:" << std::endl;
    while (cur) {
        std::cout << cur->val << std::endl;
        cur = cur->next;
    }

    std::cout << "反向遍历:" << std::endl;
    cur = tail;
    while (cur) {
        std::cout << cur->val << std::endl;
        cur = cur->prev;
    }

    return 0;
}

上面的代码实现了链表的插入和删除操作,并展示了插入和删除操作后链表的遍历结果。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:如何用C++实现双向循环链表 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • C语言多维数组

    下面是“C语言多维数组”的完整使用攻略。 多维数组的定义与初始化 在C语言中,多维数组可以用来存储表格或矩阵等数据结构,它由一系列一维数组所组成,因此可以说,多维数组其实就是数组的数组。在定义多维数组时,需要确定它的维数和每一维的大小,例如: int arr[3][4]; //表示一个3行4列,总共12个元素的二维数组 也可以在定义同时初始化,例如: int…

    C 2023年5月10日
    00
  • C语言实现BF算法案例详解

    C语言实现BF算法案例详解 什么是BF算法 BF算法是一种简单的字符串匹配算法,它的全称为Brute Force算法,中文翻译为暴力匹配算法。该算法的思想是对匹配串中与主串中的字符逐一进行比较,直到匹配成功或者不匹配结束。 实现BF算法的步骤 步骤一:暴力匹配 我们可以从主串的第一个字符开始,每次匹配一个字符,直到匹配成功或者匹配失败为止。如果匹配成功,就继…

    C 2023年5月22日
    00
  • vue和react中关于插槽详解

    当我们在使用Vue或React构建组件时,经常会遇到需要给组件传递内容的情况。比如一个弹出框,需要在内容区域中传递不同的文本、表单或者其他组件作为content。这时候,我们可以使用插槽的概念来进行解决。 概述 插槽(Slot)是Vue和React中组件通信的一种技术,它允许我们在一个组件的模板中预留一定的位置,然后在使用该组件的父组件中,使用自定义的内容来…

    C 2023年5月23日
    00
  • C语言代码实现简单2048游戏

    C语言代码实现简单2048游戏攻略 简介 在这篇攻略中,我将教您如何使用C语言编写简单的2048游戏。2048是一个流行的数字益智游戏,目标是在一个4×4的方格中合并数字,并达到最大的数字2048。在这个过程中,我们将使用C语言并结合控制流和数组等知识点来完成我们的游戏。 步骤 步骤1:定义游戏棋盘 在2048游戏中,我们需要定义一个4×4的棋盘来存储游戏状…

    C 2023年5月23日
    00
  • C语言的进制转换及算法实现教程

    C语言的进制转换及算法实现教程 概述 在计算机科学和编程中,进制转换是一个重要的概念,它涉及到二进制、十进制、八进制与十六进制之间的相互转换。C语言作为一种非常流行和强大的编程语言,也支持这些进制之间的转换。 本教程将向您介绍C语言中进制转换的基本概念和算法,以及如何在代码中实现这些转换过程。 进制转换的基本概念 二进制:由0和1组成,是计算机中最基本的数字…

    C 2023年5月23日
    00
  • C# Newtonsoft.Json 的使用说明

    C# Newtonsoft.Json是一个常用的Json操作库,使用它可以方便地实现Json格式的数据的序列化与反序列化。下面来详细讲解一下如何使用该库。 1. 安装Newtonsoft.Json 首先需要在项目中安装Newtonsoft.Json库。可以通过Nuget包管理器搜索 “Newtonsoft.Json” 进行安装,也可以从 官方网站 下载安装包…

    C 2023年5月23日
    00
  • jQuery深拷贝Json对象简单示例

    当我们需要复制一个json对象时,直接使用=赋值是不行的,因为这会导致两个变量指向同一个内存地址,修改其中一个对象的值会同时修改另一个对象的值。这时候我们需要使用深拷贝来复制json对象,这样两个对象就指向不同的内存地址,不会相互影响。 以下是深拷贝Json对象的示例代码: // 定义json对象 var obj1 = {"name":&…

    C 2023年5月23日
    00
  • 批处理 Set 命令详解 让你理解set命令

    批处理 Set 命令详解 什么是 Set 命令? Set 命令是 Windows CMD 中的命令之一,它用于设置环境变量,例如设置系统路径等。 Set 命令的语法 set [变量名=值] 变量名和值之间需要用等号 = 连接。 Set 命令的用法 1. 设置系统环境变量 使用 Set 命令可以设置系统环境变量,例如设置 PATH 变量: set PATH=C…

    C 2023年5月22日
    00
合作推广
合作推广
分享本页
返回顶部