【数据结构】双向链表(Doubly Linked List)

打印 上一主题 下一主题

主题 927|帖子 927|积分 2781

双向链表(Doubly Linked List)是一种链式数据结构,它的每个节点都包含三个部门:数据、指向前一个节点的指针(prev),以及指向下一个节点的指针(next)。与单向链表不同,双向链表答应从任意节点向前或向后遍历,提供了更灵活的操纵方式。
双向链表的结构

双向链表的每个节点都有以下三个部门:

  • 数据部门:存储节点中的实际数据。
  • 前向指针 (prev):指向当前节点的前一个节点,头节点的 prev 为 nullptr。
  • 后向指针 (next):指向当前节点的下一个节点,尾节点的 next 为 nullptr。
这种双指针的结构答应我们高效地在链表中进行插入、删除等操纵。
双向链表的操纵


  • 插入操纵:在双向链表中插入一个新节点时,需要更新前后两个节点的指针,因此插入操纵比单向链表略复杂,但仍然能在 O(1) 时间内完成(假设已经找到插入点)。
  • 删除操纵:删除一个节点时,需要修改前后节点的指针,也需要处置处罚边界条件,如删除头节点或尾节点。
  • 遍历操纵:可以从任意节点开始,向前或向后遍历链表。
C++ 实现

下面是一个简单的 C++ 双向链表实现,包含插入、删除、遍历等常用操纵。
  1. #include <iostream>
  2. struct Node {
  3.     int data;
  4.     Node* prev;
  5.     Node* next;
  6.     // 构造函数
  7.     Node(int value) : data(value), prev(nullptr), next(nullptr) {}
  8. };
  9. class DoublyLinkedList {
  10. private:
  11.     Node* head;
  12. public:
  13.     // 构造函数初始化空链表
  14.     DoublyLinkedList() : head(nullptr) {}
  15.     // 在链表头插入新节点
  16.     void insertAtHead(int value) {
  17.         Node* newNode = new Node(value);
  18.         if (head != nullptr) {
  19.             newNode->next = head;
  20.             head->prev = newNode;
  21.         }
  22.         head = newNode;
  23.     }
  24.     // 在链表尾插入新节点
  25.     void insertAtTail(int value) {
  26.         Node* newNode = new Node(value);
  27.         if (head == nullptr) {
  28.             head = newNode;
  29.             return;
  30.         }
  31.         Node* temp = head;
  32.         while (temp->next != nullptr) {
  33.             temp = temp->next;
  34.         }
  35.         temp->next = newNode;
  36.         newNode->prev = temp;
  37.     }
  38.     // 删除指定值的节点
  39.     void deleteNode(int value) {
  40.         Node* temp = head;
  41.         while (temp != nullptr && temp->data != value) {
  42.             temp = temp->next;
  43.         }
  44.         if (temp == nullptr) {
  45.             std::cout << "Node with value " << value << " not found.\n";
  46.             return;
  47.         }
  48.         if (temp->prev != nullptr) {
  49.             temp->prev->next = temp->next;
  50.         } else {
  51.             head = temp->next;
  52.         }
  53.         if (temp->next != nullptr) {
  54.             temp->next->prev = temp->prev;
  55.         }
  56.         delete temp;
  57.     }
  58.     // 正向遍历链表
  59.     void traverseForward() {
  60.         Node* temp = head;
  61.         while (temp != nullptr) {
  62.             std::cout << temp->data << " ";
  63.             temp = temp->next;
  64.         }
  65.         std::cout << std::endl;
  66.     }
  67.     // 反向遍历链表
  68.     void traverseBackward() {
  69.         if (head == nullptr) return;
  70.         Node* temp = head;
  71.         while (temp->next != nullptr) {
  72.             temp = temp->next;
  73.         }
  74.         while (temp != nullptr) {
  75.             std::cout << temp->data << " ";
  76.             temp = temp->prev;
  77.         }
  78.         std::cout << std::endl;
  79.     }
  80.     // 析构函数:释放内存
  81.     ~DoublyLinkedList() {
  82.         Node* temp = head;
  83.         while (temp != nullptr) {
  84.             Node* next = temp->next;
  85.             delete temp;
  86.             temp = next;
  87.         }
  88.     }
  89. };
  90. int main() {
  91.     DoublyLinkedList dll;
  92.     dll.insertAtHead(10);
  93.     dll.insertAtHead(20);
  94.     dll.insertAtTail(30);
  95.     dll.insertAtTail(40);
  96.     std::cout << "Forward traversal: ";
  97.     dll.traverseForward(); // 输出: 20 10 30 40
  98.     std::cout << "Backward traversal: ";
  99.     dll.traverseBackward(); // 输出: 40 30 10 20
  100.     dll.deleteNode(10);
  101.     std::cout << "After deleting 10, forward traversal: ";
  102.     dll.traverseForward(); // 输出: 20 30 40
  103.     return 0;
  104. }
复制代码
代码阐明


  • Node 结构体:每个节点包含 data、prev 和 next 三个成员变量,用于存储节点的数据和链表的双向连接。
  • DoublyLinkedList 类

    • insertAtHead:在链表头插入节点,注意要更新新头节点和原头节点的指针。
    • insertAtTail:遍历链表到末端,然后在尾部插入节点。
    • deleteNode:找到目的节点,修改前后节点的指针,使链表跳过该节点。
    • traverseForward 和 traverseBackward:分别用于正向和反向遍历链表。

  • 内存管理:链表析构函数会遍历链表并释放所有节点,制止内存走漏。
应用场景

双向链表广泛应用于需要双向遍历或频繁插入、删除操纵的场景,比如:


  • 欣赏器汗青记载:答应用户前进和退却欣赏网页。
  • 音乐播放列表:可以向前或向后切换歌曲。
  • 内存管理:操纵系统的内存块分配常常利用双向链表进行管理。
通过利用双向链表,可以提高程序处置处罚数据的灵活性和效率。在 C++ 中实现双向链表,既磨练了对指针操纵的掌握,也有助于理解动态数据结构的原理。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表