C++零基础精通数据结构之带头双向循环链表

C++零基础精通数据结构之带头双向循环链表

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

带头双向循环链表是一个常见的数据结构,它可以用来实现链表和队列等数据结构。带头双向循环链表的特点是:

  1. 每个节点有两个指针,一个指向前一个节点,一个指向后一个节点。
  2. 链表中有一个头节点,但是它不存储数据。
  3. 链表的尾节点指向头节点,头节点的前一个节点指向链表的尾节点。这样就形成了一个循环。

怎样实现带头双向循环链表?

带头双向循环链表的节点结构体

struct Node {
    int data;
    Node* prev;
    Node* next;
};

节点包含一个数据域 data,以及两个指针 prevnext

初始化带头双向循环链表

Node* init() {
    Node* head = new Node;         // 创建头节点
    head->prev = head;            // 头节点的上一个节点是头节点自身
    head->next = head;            // 头节点的下一个节点是头节点自身
    return head;                  // 返回头节点
}

初始化带头双向循环链表,先创建一个头节点,然后让头节点的上一个指针和下一个指针都指向自身,最后返回头节点。

判断带头双向循环链表是否为空

bool isEmpty(Node* head) {
    return head->next == head;
}

如果头节点的下一个节点指向头节点自身,说明链表为空,返回 true

在带头双向循环链表尾部插入一个节点

void insertAtTail(Node* head, int data) {
    Node* newNode = new Node;
    newNode->data = data;
    newNode->prev = head->prev;   // 新节点的上一个节点是原链表的尾节点
    newNode->next = head;         // 新节点的下一个节点是头节点
    head->prev->next = newNode;   // 原链表的尾节点的下一个节点是新节点
    head->prev = newNode;         // 头节点的上一个节点是新节点
}

创建一个新节点,将它的数据域和上一个指针赋值,然后将它的下一个指针指向头节点,接着将原链表的尾节点的下一个指针指向新节点,最后将头节点的上一个指针指向新节点。

在带头双向循环链表头部插入一个节点

void insertAtHead(Node* head, int data) {
    Node* newNode = new Node;
    newNode->data = data;
    newNode->prev = head;         // 新节点的上一个节点是头节点
    newNode->next = head->next;   // 新节点的下一个节点是原链表的头节点
    head->next->prev = newNode;   // 原链表的头节点的上一个节点是新节点
    head->next = newNode;         // 头节点的下一个节点是新节点
}

创建一个新节点,将它的数据域和下一个指针赋值,然后将它的上一个指针指向头节点,接着将原链表的头节点的上一个指针指向新节点,最后将头节点的下一个指针指向新节点。

删除节点

void remove(Node* head, int data) {
    Node* p = head->next;
    while (p != head && p->data != data) {   // 找到要删除的节点
        p = p->next;
    }
    if (p != head) {
        p->prev->next = p->next;   // 上一个节点的下一个指针指向下一个节点
        p->next->prev = p->prev;   // 下一个节点的上一个指针指向上一个节点
        delete p;                  // 释放被删除的节点的内存
    }
}

先找到要删除的节点,然后将它的上一个节点的下一个指针指向它的下一个节点,将它的下一个节点的上一个指针指向它的上一个节点,最后释放它的内存。

示例说明

示例1:插入数据、遍历数据、删除数据

int main() {
    Node* head = init();                  // 初始化带头双向循环链表
    insertAtTail(head, 1);                // 在尾部插入1
    insertAtTail(head, 2);                // 在尾部插入2
    insertAtHead(head, 0);                // 在头部插入0
    insertAtTail(head, 3);                // 在尾部插入3
    insertAtTail(head, 4);                // 在尾部插入4

    Node* p = head->next;                 // 遍历链表
    while (p != head) {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;

    remove(head, 1);                      // 删除1

    p = head->next;                       // 遍历链表
    while (p != head) {
        cout << p->data << " ";
        p = p->next;
    }
    cout << endl;

    return 0;
}

输出结果:

0 1 2 3 4
0 2 3 4

示例2:插入数据、判断链表是否为空

int main() {
    Node* head = init();                  // 初始化带头双向循环链表
    insertAtTail(head, 1);                // 在尾部插入1
    insertAtTail(head, 2);                // 在尾部插入2

    if (isEmpty(head)) {                  // 判断链表是否为空
        cout << "链表为空" << endl;
    } else {
        cout << "链表不为空" << endl;
    }

    return 0;
}

输出结果:

链表不为空

至此,带头双向循环链表的初始化、插入、删除、遍历和判断是否为空的基本操作都已经讲解完毕。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++零基础精通数据结构之带头双向循环链表 - Python技术站

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

相关文章

  • C++ getcwd函数获取项目运行路径方法详解

    C++ getcwd函数获取项目运行路径方法详解 介绍 getcwd是一个C++标准库的函数,用于获取当前工作目录的路径名。在某些情况下,需要找出项目的运行路径,以便正确地访问项目中的文件和其他资源。 步骤 以下是一个获取项目运行路径的示例代码: #include <iostream> #include <unistd.h> int …

    other 2023年6月27日
    00
  • oracle序列(查询序列的值 修改序列的值)

    oracle序列(查询序列的值 修改序列的值) 什么是Oracle序列? Oracle序列是一种由Oracle数据库管理系统提供的对象,它生成唯一并且有序的数字序列,常常用于给数据库的主键提供自增长的值。序列是一种非常方便的方式,它可以在多个表中为多个列提供唯一的值。 查询序列的值 如果你想要查询一个序列的当前值,可以使用如下的 SQL 语句: SELECT…

    其他 2023年3月28日
    00
  • 为什么不要在 Flutter 中使用全局变量

    为什么不要在 Flutter 中使用全局变量 在 Flutter 中,使用全局变量可能会导致一些问题和不良影响。下面是一些原因和示例说明,解释为什么不建议在 Flutter 中使用全局变量。 1. 命名冲突和难以维护 使用全局变量可能导致命名冲突和代码难以维护。在一个大型的 Flutter 应用程序中,可能会有多个开发人员同时工作,每个人都可能定义自己的全局…

    other 2023年7月29日
    00
  • python交互模式下输入换行/输入多行命令的方法

    当使用Python交互模式时,输入一次命令后回车会直接执行该命令。如果要输入多个命令或代码,则需要换行或者输入多行命令。 输入多行命令的方法 1. 使用三重引号字符串 当需要输入多行字符串时,可以使用三重引号字符串。在Python交互模式中,输入三个引号(单引号或双引号都可以)时,Python将自动进入多行输入模式,直到输入连续三个引号结束输入。示例代码如下…

    other 2023年6月26日
    00
  • ubuntu18.04安装frp的配置说明

    Ubuntu 18.04安装frp的配置说明 frp是一种高性能的反向代理工具,可以帮助我们将内网服务暴露到公网上。本攻略将介如何在Ubuntu 18.04上安装frp,并提供两个示例。 安装frp 以下是在Ubuntu 18.04上安frp的步骤: 下载frp。可以从frp的官方网站下载最新版本的frp,命令如下: wget https://github.…

    other 2023年5月9日
    00
  • thusc2015

    THUSC2015: 迎接未来的编程教育 编程教育是当前全球热门话题之一。很多国家和地区都开始将编程纳入了基础教育课程,或是通过各种方式提供编程学习机会,以培养下一代的IT人才。而在中国,由清华大学组织的THUSC2015编程营,自2015年开始,一直致力于为青少年提供优质的编程教育体验。 强大的师资力量 THUSC2015拥有一支由清华大学Turing计算…

    其他 2023年3月28日
    00
  • 局域网中IP地址的设置

    局域网中IP地址的设置攻略 在局域网中设置IP地址是连接到网络的重要步骤。下面是一个详细的攻略,帮助你设置局域网中的IP地址。 步骤一:了解IP地址 IP地址是一个由数字和点组成的标识符,用于在网络中唯一标识设备。IP地址分为两类:IPv4和IPv6。IPv4是目前广泛使用的版本,它由四个十进制数(0-255)组成,例如192.168.0.1。IPv6是下一…

    other 2023年7月30日
    00
  • React Native安卓代码混淆和打包

    @CachePut是Spring Boot框架中的一个注解,用于将方法的返回值更新到缓存中。本文将详细讲解@CachePut的作用和使用方法,并提供两个示例说明。 作用 @CachePut注解的作用是将方法的返回值更新到缓存中,以保证缓存中的数据与数据库中的数据一致。 使用方法 使用@CachePut注解时,需要在应用程序的主类上添加@EnableCachi…

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