C++双向链表的增删查改操作方法讲解

关于C++双向链表的增删查改操作方法,一般可以分为以下几步:

第一步:定义链表结构体

我们都知道链表是一种动态数据结构,它的每个元素都包含指向前一个元素和后一个元素的指针。因此,在C++中,我们可以用结构体来定义一个链表节点,具体的定义如下:

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

其中,val是节点的值,prev和next分别指向前一个节点和后一个节点。在这里,我们使用nullptr来初始化指针。

第二步:实现链表的增加操作

链表的增加操作也可以分为头插和尾插两种方式。

头插法

头插法是将新节点插入到链表的头部。具体的实现如下:

void addAtHead(ListNode*& head, int val) {
     ListNode* node = new ListNode(val);
     if (!head) {
         head = node;
     } else {
         node->next = head;
         head->prev = node;
         head = node;
     }
}

第一行代码是创建一个新的节点。如果链表为空,则将这个新节点设置为头节点。如果链表不为空,则将这个新节点插入到头节点的前面,并更新头节点的信息。

尾插法

尾插法是将新节点插入到链表的尾部。具体的实现如下:

void addAtTail(ListNode*& head, int val) {
    ListNode* node = new ListNode(val);
    if (!head) {
        head = node;
    } else {
        ListNode* cur = head;
        while (cur->next) {
            cur = cur->next;
        }
        cur->next = node;
        node->prev = cur;
    }
}

第一行代码同样是创建一个新的节点。如果链表为空,则将这个新节点设置为头节点。如果链表不为空,则从头节点开始遍历到链表尾部,在尾节点的后面加入一个新节点。

第三步:实现链表的删除操作

链表的删除操作也可以分为删除头节点和删除尾节点两种方式。

删除头节点

删除头节点可以直接将头节点的后一个节点作为头节点,并释放原头节点的内存空间。具体的实现如下:

void deleteAtHead(ListNode*& head) {
    if (!head) {
        return;
    }
    ListNode* tmp = head;
    head = head->next;
    if (head) {
        head->prev = nullptr;
    }
    delete tmp;
}

如果链表不为空,则将头节点指针指向第二个节点。由于新的头节点的前面没有节点,因此将它的prev指针置空。最后,释放掉原来的头节点的内存空间。

删除尾节点

删除尾节点可以遍历到尾节点的前一个节点,并将它的next指针置空。然后,释放掉原尾节点的内存空间。具体的实现如下:

void deleteAtTail(ListNode*& head) {
    if (!head) {
        return;
    }
    if (!head->next) {
        delete head;
        head = nullptr;
        return;
    }
    ListNode* cur = head;
    while (cur->next) {
        cur = cur->next;
    }
    cur->prev->next = nullptr;
    delete cur;
}

如果链表只有一个节点,直接释放掉这个节点并将头指针置空。否则从头节点开始遍历到尾节点的前一个节点,并释放掉尾节点的内存空间。

第四步:实现链表的查找操作

链表的查找操作主要是根据节点的值进行查找。我们可以从头节点开始遍历每个节点,如果找到了对应的节点,则返回该节点的指针。否则,返回nullptr。具体的实现如下:

ListNode* search(ListNode* head, int val) {
    while (head) {
        if (head->val == val) {
            return head;
        }
        head = head->next;
    }
    return nullptr;
}

从头节点开始遍历每个节点,如果找到了节点的值等于val,则返回该节点的指针。否则,继续向后遍历,直到链表的末尾都没有找到节点,则返回nullptr。

第五步:实现链表的修改操作

修改链表中的节点可以直接通过访问节点的val来修改。具体的实现如下:

void update(ListNode* head, int oldVal, int newVal) {
    ListNode* node = search(head, oldVal);
    if (node) {
        node->val = newVal;
    }
}

从头节点开始查找节点的值等于oldVal的节点。如果找到了节点,则将该节点的值修改为newVal。

示例说明

示例一

通过头插法构建一个链表,并输出该链表的值。

ListNode* head = nullptr;
addAtHead(head, 1);
addAtHead(head, 2); 
addAtHead(head, 3); 

ListNode* cur = head;
while (cur) {
    cout << cur->val << " ";
    cur = cur->next;
}

输出结果为“3 2 1”。

示例二

通过尾插法构建一个链表,并删除尾节点。

ListNode* head = nullptr;
addAtTail(head, 1);
addAtTail(head, 2); 
addAtTail(head, 3); 

deleteAtTail(head);

ListNode* cur = head;
while (cur) {
    cout << cur->val << " ";
    cur = cur->next;
}

输出结果为“1 2”。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++双向链表的增删查改操作方法讲解 - Python技术站

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

相关文章

  • Java线程的联合用法实例分析

    Java线程的联合用法实例分析 联合用法简介 Java线程的联合用法(join)是指等待一个线程执行完成,再执行另一个线程。联合用法常常用于需要计算时间的多个线程执行时,我们常常希望等待其中一个线程执行完成,再执行下一个线程,保证计算的时间的准确性。线程等待的过程中,当前线程会被阻塞,直到联合线程执行完毕才会继续执行。 联合用法的用法 Java线程的联合用法…

    other 2023年6月27日
    00
  • 解析如何开发FineReport的自定义控件

    让我来详细讲解一下“解析如何开发FineReport的自定义控件”的攻略。 1. 前置知识 在开发FineReport的自定义控件之前,你需要掌握以下几个知识点: FineReport的基本使用和原理 Java基础编程和面向对象编程(尤其是抽象类、接口等概念) 熟练运用GUI编程(Swing、AWT等) 2. 开发自定义控件的步骤 下面是开发自定义控件的步骤…

    other 2023年6月26日
    00
  • Visual Studio 2019 DLL动态库连接实例(图文教程)

    “Visual Studio 2019 DLL动态库连接实例(图文教程)”是一篇介绍如何在Visual Studio 2019中使用动态链接库(DLL)的教程。该教程旨在让读者了解如何创建和使用DLL,并且包含了基本的代码示例和图文说明。下面是该教程的完整攻略,包括两条示例说明: 1. 创建动态链接库 首先,我们需要创建一个动态链接库项目。在Visual S…

    other 2023年6月26日
    00
  • cmdbuild部署教程

    cmdbuild部署教程 什么是cmdbuild? cmdbuild是一款基于Web的开源配置管理数据库软件,用于IT资产管理、服务管理、工单管理等。它可以帮助组织实现更好的IT资产管理,提高业务响应速度和工作效率。 cmdbuild部署步骤 1. 确认环境 在开始部署过程之前,需要确认已经安装好以下环境: Java 8 或以上版本 PostgreSQL 9…

    其他 2023年3月29日
    00
  • mybatis typeAliases 给实体类起别名的方法

    MyBatis TypeAliases给实体类起别名的方法 在MyBatis中,可以使用typeAliases来为实体类起别名。这样做的好处是可以简化代码中使用的实体类名称,提高可读性和可维护性。以下是使用typeAliases给实体类起别名的完整攻略。 步骤一:配置typeAliases 首先,需要在MyBatis的配置文件(例如mybatis-confi…

    other 2023年6月28日
    00
  • Unity初探之黑暗之光(1)

    Unity初探之黑暗之光(1) 引言 Unity是一款游戏引擎,能够帮助开发者制作高质量、多平台的游戏应用。黑暗之光是一款由Unity开发的第一人称冒险游戏,是Unity在游戏领域的杰作之一。本篇文章将介绍黑暗之光游戏的制作过程,包括环境搭建、场景设计、角色动画等方面。 环境搭建 在开始制作游戏前,我们需要准备好相关环境。由于Unity是运行在Windows…

    其他 2023年3月28日
    00
  • Linux中使用Pyinotify模块实时监控文件系统更改

    当我们需要实时监控文件系统下文件或目录的变化时,可以借助Python的Pyinotify模块来实现。本文将详细讲解如何在Linux中使用Pyinotify模块实时监控文件系统更改。 安装Pyinotify模块 首先,我们需要在Linux系统中安装Pyinotify模块。可以通过以下命令进行安装: pip install pyinotify 编写监控程序 接下…

    other 2023年6月27日
    00
  • Java Dubbo框架知识点梳理

    Java Dubbo框架知识点梳理 1. 什么是 Dubbo Dubbo 是一款高性能 Java RPC 框架,它提供了服务治理、降级、容错、负载均衡、分流、路由、动态配置等基础能力,同时还支持多种协议、多种注册中心、多种负载均衡方式。Dubbo 可以帮助开发者快速构建分布式应用。 2. Dubbo 核心概念 2.1 服务提供者 Provider 提供服务的…

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