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

简单的双向循环链表实现与使用指南

CnLinkedList:双向循环链表实现与使用指南

概述

CnLinkedList是一个轻量级的双向循环链表实现,具有自包含节点结构的特点。每个节点既作为数据载体,又负责维护链表的连接关系,无需额外的链表管理对象。这种设计使得链表操作高效且内存使用紧凑,适合需要频繁插入、删除节点的场景。

类定义与实现

class CnLinkedList
{
public:CnLinkedList() {m_pcPrev = this;m_pcNext = this;}virtual ~CnLinkedList() {}inline void InsertPrev(CnLinkedList* pcLinkedList) {pcLinkedList->m_pcPrev = m_pcPrev;pcLinkedList->m_pcNext = this;m_pcPrev->m_pcNext = pcLinkedList;m_pcPrev = pcLinkedList;}inline CnLinkedList* RemovePrev() {CnLinkedList* pcPrev = m_pcPrev;if (this != pcPrev) {m_pcPrev = pcPrev->m_pcPrev;pcPrev->m_pcPrev->m_pcNext = this;}pcPrev->m_pcPrev = pcPrev;pcPrev->m_pcNext = pcPrev;return pcPrev;}inline CnLinkedList* GetPrev() const { return m_pcPrev; }inline void InsertNext(CnLinkedList* pcLinkedList) {pcLinkedList->m_pcPrev = this;pcLinkedList->m_pcNext = m_pcNext;m_pcNext->m_pcPrev = pcLinkedList;m_pcNext = pcLinkedList;}inline CnLinkedList* RemoveNext() {CnLinkedList* pcNext = m_pcNext;if (this != m_pcNext) {m_pcNext = pcNext->m_pcNext;pcNext->m_pcNext->m_pcPrev = this;}pcNext->m_pcPrev = pcNext;pcNext->m_pcNext = pcNext;return pcNext;}inline CnLinkedList* GetNext() const { return m_pcNext; }void RemoveFromLinkedList() {// 无论链表长度如何,都更新前后节点的指针关系m_pcPrev->m_pcNext = m_pcNext;m_pcNext->m_pcPrev = m_pcPrev;// 将当前节点恢复为自循环状态m_pcPrev = this;m_pcNext = this;}u32 LinkedListSize() const {u32 dwSize = 1;CnLinkedList* pcTemp = m_pcNext;while (this != pcTemp) {dwSize++;pcTemp = pcTemp->m_pcNext;}return dwSize;}private:CnLinkedList* m_pcPrev;CnLinkedList* m_pcNext;
};

核心功能解析

1. 构造函数

CnLinkedList() {m_pcPrev = this;m_pcNext = this;
}

初始化时,节点的m_pcPrevm_pcNext均指向自身,形成一个单个节点的循环链表。

2. 插入操作

  • InsertPrev: 在当前节点前插入新节点

    void InsertPrev(CnLinkedList* pcLinkedList)
    
  • InsertNext: 在当前节点后插入新节点

    void InsertNext(CnLinkedList* pcLinkedList)
    

插入操作通过调整前后节点的指针关系来完成,时间复杂度为O(1)。

3. 删除操作

  • RemovePrev: 移除当前节点的前一个节点并返回

    CnLinkedList* RemovePrev()
    
  • RemoveNext: 移除当前节点的后一个节点并返回

    CnLinkedList* RemoveNext()
    
  • RemoveFromLinkedList: 当前节点主动从链表中脱离

    void RemoveFromLinkedList()
    

删除操作会将被移除的节点重置为自循环状态,避免野指针问题,时间复杂度为O(1)。

4. 辅助方法

  • GetPrev(): 获取前一个节点
  • GetNext(): 获取后一个节点
  • LinkedListSize(): 计算链表包含的节点总数,时间复杂度为O(n)

使用示例

1. 创建带数据的节点类

#include <iostream>
#include "CnLinkedList.h"// 创建一个带数据的链表节点
class DataNode : public CnLinkedList {
public:int value;DataNode(int val) : value(val) {}
};

2. 链表遍历函数

// 打印链表内容(从指定节点开始遍历)
void printList(CnLinkedList* startNode) {if (!startNode) return;CnLinkedList* current = startNode;DataNode* dataNode = static_cast<DataNode*>(current);std::cout << "链表内容: " << dataNode->value;current = current->GetNext();while (current != startNode) {dataNode = static_cast<DataNode*>(current);std::cout << " -> " << dataNode->value;current = current->GetNext();}std::cout << " (循环结束)" << std::endl;
}

3. 主要操作示例

int main() {// 1. 创建节点DataNode* node1 = new DataNode(10);DataNode* node2 = new DataNode(20);DataNode* node3 = new DataNode(30);DataNode* node4 = new DataNode(40);std::cout << "初始节点1的值: " << node1->value << ", 链表长度: " << node1->LinkedListSize() << std::endl;// 2. 插入节点node1->InsertNext(node2);  // 在node1后插入node2std::cout << "插入node2后,node1的链表长度: " << node1->LinkedListSize() << std::endl;printList(node1);node2->InsertNext(node3);  // 在node2后插入node3node1->InsertPrev(node4);  // 在node1前插入node4std::cout << "插入node3和node4后,链表长度: " << node1->LinkedListSize() << std::endl;printList(node1);// 3. 移除节点CnLinkedList* removed = node1->RemoveNext();  // 移除node1的下一个节点(node2)std::cout << "移除node2后,链表长度: " << node1->LinkedListSize() << std::endl;printList(node1);std::cout << "被移除的节点值: " << static_cast<DataNode*>(removed)->value << std::endl;// 4. 节点自移除node4->RemoveFromLinkedList();  // node4主动从链表中移除std::cout << "node4自移除后,链表长度: " << node1->LinkedListSize() << std::endl;printList(node1);// 5. 遍历链表(从node3开始)std::cout << "从node3开始遍历: ";printList(node3);// 清理内存delete node1;delete node2;delete node3;delete node4;return 0;
}

4. 预期输出

初始节点1的值: 10, 链表长度: 1
插入node2后,node1的链表长度: 2
链表内容: 10 -> 20 (循环结束)
插入node3和node4后,链表长度: 4
链表内容: 10 -> 20 -> 30 -> 40 (循环结束)
移除node2后,链表长度: 3
链表内容: 10 -> 30 -> 40 (循环结束)
被移除的节点值: 20
node4自移除后,链表长度: 2
链表内容: 10 -> 30 (循环结束)
从node3开始遍历: 链表内容: 30 -> 10 (循环结束)

适用场景

  • 需要频繁在任意位置插入/删除节点的场景(如游戏对象管理、事件队列)
  • 需支持双向遍历的链表结构
  • 内存受限环境(无额外链表管理对象,节点自包含)

使用建议

  1. 通过继承CnLinkedList实现具体的数据节点类
  2. 遍历链表时,可从任意节点出发,通过GetNext()循环访问,直到回到起点
  3. 节点销毁前建议调用RemoveFromLinkedList(),避免链表结构被破坏
  4. 对于大型链表,LinkedListSize()方法效率较低,可考虑维护一个单独的长度计数器

CnLinkedList以极简的代码提供了双向循环链表的核心功能,适合对性能和内存使用有要求的场景。

http://www.lryc.cn/news/619188.html

相关文章:

  • Visual Studio中VC++目录、C/C++和链接器配置的区别与最佳实践
  • 无人机智能返航模块技术分析
  • 【前端Vue】如何在log-viewer组件中添加搜索定位功能
  • C语言中关于普通变量和指针变量、结构体包含子结构体或包含结构体指针的一些思考
  • 调整UOS在VMware中的分辨率
  • 广东省省考备考(第七十四天8.12)——资料分析、数量关系(40%-70%正确率的题目)
  • MySQL 数据库表操作与查询实战案例
  • 猫头虎AI分享|智谱直播开源其最新视觉模型:GLM-4.5V,多模态,支持图像、视频输入
  • 一个删掉360安全卫士的方法——Win+R
  • 【代码随想录day 17】 力扣 98.验证二叉搜索树
  • 计算机视觉(6)-自动驾驶感知方案对比
  • 偶遇冰狐智能辅助的录音
  • 【oracle闪回查询】记录字段短时间被修改的记录
  • 【Allegro SKILL代码解析】添加Pin Number
  • Web 安全之互联网暴露面管理
  • 零售业CRM实战:如何打通线上线下客户数据?
  • word——照片自适应框大小【主要针对需要插入证件照时使用】
  • 亚马逊优惠券视觉体系重构:颜色标签驱动的消费决策效率革命
  • DAY38打卡
  • CTO 如何从“干活的人”转变成“带方向的人”?
  • Spring Boot项目通过RestTemplate调用三方接口详细教程
  • 带宽受限信道下的数据传输速率计算:有噪声与无噪声场景
  • mysql锁+索引
  • 自然语言处理关键库解析和使用方法- FuzzyWuzzy
  • 【3】Transformers快速入门:大语言模型LLM是啥?
  • 【4】Transformers快速入门:自然语言模型 vs 统计语言模型
  • GaussDB 数据库架构师修炼(十三)安全管理(2)-数据库权限管理
  • 如何构建PHP表单页面及验证相关原理(PHP基础)
  • 前后端分离项目中Spring MVC的请求执行流程
  • Kubernetes 资源管理全解析:从基础到企业级实践