当前位置: 首页 > news >正文

C++双向链表删除操作:由浅入深完全指南

双向链表是一种基础且重要的数据结构,每个节点不仅包含数据,还包含指向前一个节点和后一个节点的指针。这种结构使得双向链表在插入和删除操作上,尤其是在已知节点位置时,比单向链表更具优势。

本文将聚焦于删除操作,带你从基本概念出发,逐步深入到边界处理和应用实践。


第一部分:基础篇 —— 删除节点的核心逻辑

在双向链表中删除一个节点,核心在于“重新布线”,将被删除节点前后两个节点连接起来,然后安全地释放该节点。

假设我们有一个简单的节点定义:

struct ListNode {int val;ListNode* prev; // 指向前一个节点ListNode* next; // 指向后一个节点ListNode(int x) : val(x), prev(nullptr), next(nullptr) {}
};

现在,假设我们要在链表中删除一个已知的节点 delNode。下图清晰地展示了这一过程:

deepseek_mermaid_20251110_5ac562.png

根据图示,我们可以将其转化为代码:

// 前提:delNode 不是空指针,且存在于链表中
void deleteNode(ListNode* delNode) {// 1. 处理前驱节点的next指针if (delNode->prev != nullptr) {delNode->prev->next = delNode->next;}// 2. 处理后继节点的prev指针if (delNode->next != nullptr) {delNode->next->prev = delNode->prev;}// 3. 安全删除节点delete delNode;
}

关键点:

  • 我们必须检查 delNode->prevdelNode->next 是否为空,因为要删除的节点可能是头节点或尾节点。
  • 操作顺序很重要,但在此例中,只要在解除链接前获取了必要的信息,顺序可以调整。

第二部分:进阶篇 —— 处理边界情况与设计封装

基础的删除逻辑很简单,但一个健壮的链表实现需要 meticulously (一丝不苟地) 处理各种边界情况。

情况一:删除头节点

如果 delNode 是链表的头节点,在删除后,链表的头指针需要被更新。

void deleteNode(ListNode** head_ref, ListNode* delNode) {// 检查空指针if (*head_ref == nullptr || delNode == nullptr) return;// 如果删除的是头节点,则需要更新头指针if (*head_ref == delNode) {*head_ref = delNode->next; // 新的头节点是原头的下一个}// ... (接下来的连接操作与基础篇相同)if (delNode->next != nullptr) {delNode->next->prev = delNode->prev;}if (delNode->prev != nullptr) {delNode->prev->next = delNode->next;}delete delNode;
}
情况二:删除尾节点

如果 delNode 是尾节点,我们只需要更新它前一个节点的 next 指针为 nullptr。基础代码中的 if (delNode->next != nullptr) 已经完美处理了这种情况,防止了访问空指针的 prev

情况三:删除唯一节点

如果链表只有一个节点,那么删除它后,头指针需要被置为 nullptr。上面的代码同样可以处理:它首先将 *head_ref 设置为 delNode->next(也就是 nullptr),然后进行连接操作(因为 prevnext 都是 nullptr,所以 if 内的语句不会执行)。


第三部分:实践篇 —— 完整的链表类与复杂删除

让我们在一个简单的双向链表类中实现删除功能,并探讨更复杂的场景。

class DoublyLinkedList {
private:ListNode* head;
public:DoublyLinkedList() : head(nullptr) {}// 删除指定值的第一个节点void deleteByValue(int value) {ListNode* current = head;while (current != nullptr) {if (current->val == value) {// 找到节点,调用删除逻辑if (current == head) {head = head->next;}if (current->next != nullptr) {current->next->prev = current->prev;}if (current->prev != nullptr) {current->prev->next = current->next;}delete current;return; // 只删除第一个找到的}current = current->next;}}// 删除指定位置的节点 (索引从0开始)void deleteByPosition(int position) {if (head == nullptr || position < 0) return;ListNode* current = head;for (int i = 0; current != nullptr && i < position; i++) {current = current->next;}// 如果current为空,说明位置超出链表长度if (current == nullptr) return;// 复用删除节点的核心逻辑if (current == head) {head = head->next;}if (current->next != nullptr) {current->next->prev = current->prev;}if (current->prev != nullptr) {current->prev->next = current->next;}delete current;}// 清空整个链表void clear() {while (head != nullptr) {ListNode* temp = head;head = head->next;delete temp;}}// ... 其他成员函数,如push_front, push_back, print等
};

复杂删除场景:

  1. 清空链表:clear() 函数所示,它反复删除头节点,直到链表为空。这是一种高效且安全的方法。
  2. 在析构函数中调用: 一个良好的 C++ 链表类必须在析构函数中清理所有节点,防止内存泄漏。
    ~DoublyLinkedList() {clear();
    }
    

第四部分:深入理解 —— 与单向链表删除的对比

这是理解双向链表优势的关键。

特性单向链表双向链表
删除给定节点O(n)。需要从头遍历以找到该节点的前驱节点。O(1)。因为通过 prev 指针可以直接找到前驱节点。
删除头节点O(1)O(1)
删除尾节点O(n)。需要找到倒数第二个节点。O(1)。通过尾节点的 prev 直接找到前驱。

结论: 当操作涉及到反向遍历或已知节点位置而非仅值时的删除,双向链表的效率远高于单向链表。

总结

从最基础的“重新布线”逻辑,到处理头节点、尾节点等边界情况,再到封装成完整的类并与单向链表进行对比,我们对C++双向链表的删除操作进行了一次由浅入深的探索。

记住成为一名优秀C++程序员的关键:

  • 始终注意内存管理newdelete 要成对出现。
  • 严谨处理边界:头节点、尾节点、空链表是bug的高发区。
  • 理解底层原理:明白指针是如何被操作的,才能写出正确、高效的代码。
http://www.dtcms.com/a/593373.html

相关文章:

  • 云手机轻松玩转网络手游
  • 手机拍照明晰度评估:传感器尺寸像素数量与处理器算法解析
  • Web VIVO手机商城网站项目4页面
  • 【杂谈】-人工智能时代的基础设施变革:引领未来十年科技发展的关键
  • 有关网络技术的网站iis7 建立网站
  • vue提交代码报错---eslint检查
  • 天津外贸公司网站制作wordpress中国区官方论坛
  • 成都企业网站商城定制网络推广方案包括哪些内容
  • 商城网站建设机构怎样做展示型网站
  • Rust类型系统奇技淫巧:幽灵类型(PhantomData)——理解编译器与类型安全
  • Visual Studio Code 之C/C++开发编译环境搭建
  • 长沙网站制造太原网站建设注意
  • PortSwigger靶场之SSRF with whitelist-based input filter通关秘籍
  • 太原网站快速排名提升手机商城网站制作公司
  • Redis 核心命令速查表
  • 中药饮片批发市场如何提升产品质量以迎合客户需求?
  • k8s中应用容器随redis集群自动重启
  • C语言结构体入门与实践:打造你的“数据百宝箱”
  • Docker核心概念与实战指南
  • 视频网站开发问题整人网站建设
  • 【Java】面向对象编程
  • 作业11.9
  • 西安网站开发公司网站服务器租用价格
  • 北京市城乡结合部建设领导小组办公室网站聊城做网站的公司效果
  • 百家号网站开发属于什么领域广东省住房和城乡建设局官网
  • MATLAB的加权K-means(Warp-KMeans)聚类算法
  • Python 图像处理库 scikit-image:从原理到实战
  • 帆软8.0报表,导出pdf无法显示图片。
  • Vue Router (命名视图)
  • CTFshow-web208