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

yizhihongxing

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日

相关文章

  • centos7 设置grub密码及单用户登录实例代码

    CentOS 7 设置 grub 密码及单用户登录 GRUB 是 Linux 中的一款启动管理器,它的主要任务是加载系统内核并启动操作系统。在 Linux 中,如果你拥有 root 权限,那么就相当于拥有了系统的最高权限。如果你的机器是通过 GRUB 单用户方式启动的,那么恶意用户只需要进入单用户模式就可以轻易地获取系统的 root 权限,从而对系统造成安全…

    other 2023年6月27日
    00
  • vue-cli 环境变量 process.env的使用及说明

    vue-cli 环境变量 process.env的使用及说明 在Vue.js项目中,我们可以通过使用process.env来访问环境变量,这在不同的环境下可以用来指定不同的参数或配置。本文将详细讲解如何使用process.env来设置和访问环境变量。 process.env的基本用法 process.env是Node.js中的全局变量,可以用来访问系统环境变…

    other 2023年6月27日
    00
  • 如何注册一个好的.com域名

    如何注册一个好的.com域名 步骤一:选择一个合适的域名注册平台 在注册一个好的.com域名之前,你需要选择一个可靠的域名注册平台。以下是一些受欢迎的域名注册平台的示例: GoDaddy:GoDaddy是全球最大的域名注册商之一,提供广泛的域名选择和易于使用的界面。 Namecheap:Namecheap是另一个受欢迎的域名注册平台,提供竞争力的价格和良好的…

    other 2023年8月5日
    00
  • C语言结构体指针的具体使用

    我将为你详细讲解“C语言结构体指针的具体使用”的攻略。 1. C语言结构体指针的定义 在C语言中,我们可以定义一个结构体类型,并通过“结构体指针”来访问结构体中的成员变量。 结构体指针的定义格式如下: struct 结构体类型名 *结构体指针变量名; 在定义结构体指针变量后,就可以通过“->”来访问结构体中的成员变量。 例如: struct Stude…

    other 2023年6月27日
    00
  • 程序员实用工具 推荐一款代码统计神器gitstats

    程序员实用工具推荐一款代码统计神器gitstats 在软件开发过程中,代码统计是一个非常重要的环节。它可以帮助我们了解代码的规模、结构质量,从而好地管理和优化代码。在这里,我向大家推荐一款代码统计神器——gitstats。 基本概念 gitstats一个基于 Git 仓库的代码统计工具,它可以生成各种有用的统计信息,包括代码行数、提交次数、活度、贡献者等等。…

    other 2023年5月7日
    00
  • 怪物猎人世界冰原DLC冥赤武器带属性测试 冥赤武器数据解析

    当涉及到冥赤武器数据解析时,以下是一个完整的攻略,包含两个示例说明: 1. 解析冥赤武器数据 冥赤武器数据可以通过游戏内的资源文件或者官方提供的API获取。你可以使用Python的第三方库(如requests)发送HTTP请求获取API数据,然后使用json库解析返回的JSON数据。 示例代码: import requests import json # 发…

    other 2023年10月19日
    00
  • 怎么修改电脑ip地址?电脑ip地址修改方法介绍

    怎么修改电脑IP地址?电脑IP地址修改方法介绍 1. 打开网络设置 首先,我们需要打开电脑的网络设置界面。在Windows操作系统中,可以通过以下步骤打开网络设置: 点击任务栏右下角的网络图标(Wi-Fi或以太网图标)。 在弹出的菜单中,选择“网络和Internet设置”选项。 在Mac操作系统中,可以通过以下步骤打开网络设置: 点击屏幕右上角的苹果图标。 …

    other 2023年7月29日
    00
  • <魔域>按键精灵脚本

    魔域按键精灵脚本 作为一款经典的网络游戏,魔域一度风靡全球。在游戏中,不少玩家会选择使用按键精灵脚本,以便能够更好地操作游戏角色和完成任务。那么,如何使用按键精灵脚本呢? 什么是按键精灵脚本? 按键精灵脚本是一款自动化脚本软件,允许用户通过记录并重现特定的动作序列,将这些操作序列应用于不同的应用程序。在魔域中,按键精灵脚本可以用于自动操作角色,执行任务,甚至…

    其他 2023年3月29日
    00
合作推广
合作推广
分享本页
返回顶部