C++数据结构之双向链表

C++数据结构之双向链表完整攻略

1. 什么是双向链表

双向链表是一种特殊的链表结构,每个节点拥有两个指针域,分别指向前继和后继节点。

双向链表不需要像单向链表那样从头到尾遍历整个链表,可以通过前后指针直接访问前后节点,提高了查找、删除、插入等操作的效率。

双向链表有一些常用的操作,如插入节点、删除节点、查找节点等。

2. 双向链表的实现

2.1 节点定义

template <typename T>
struct DListNode {
    T data;
    DListNode<T> *prev; // 指向前继节点指针
    DListNode<T> *next; // 指向后继节点指针
};

2.2 双向链表类定义

template <typename T>
class DLinkedList {
public:
    DLinkedList() : _head(nullptr), _tail(nullptr), _size(0) {}
    ~DLinkedList() {}

    // 插入操作
    void insertFront(T value);          // 在头部插入节点
    void insertBack(T value);           // 在尾部插入节点
    void insertAt(DListNode<T> *node, T value); // 在指定位置之后插入节点

    // 删除操作
    void deleteFront();  // 删除头部节点
    void deleteBack();   // 删除尾部节点
    void deleteAt(DListNode<T> *node); // 删除单个节点

    // 查找操作
    DListNode<T> *find(T value); // 根据值查找节点
    DListNode<T> *findAt(int index); // 根据下标查找节点

    // 判空操作
    bool empty() { return _head == nullptr; }

    // 返回链表长度
    int size() { return _size; }

    // 输出链表
    void print();

private:
    DListNode<T> *_head; // 头指针
    DListNode<T> *_tail; // 尾指针
    int _size;           // 链表长度
};

2.3 插入节点操作

在头部插入节点,实现如下:

template <typename T>
void DLinkedList<T>::insertFront(T value) {
    DListNode<T> *newNode = new DListNode<T>();
    newNode->data = value;

    if (empty()) {
        _tail = newNode; // 如果链表为空,插入后的节点即为尾节点
    } else {
        _head->prev = newNode;
    }

    newNode->next = _head;
    _head = newNode;
    ++_size;
}

在尾部插入节点,实现如下:

template <typename T>
void DLinkedList<T>::insertBack(T value) {
    DListNode<T> *newNode = new DListNode<T>();
    newNode->data = value;

    if (empty()) {
        _head = newNode; // 如果链表为空,插入后的节点即为头节点
    } else {
        _tail->next = newNode;
    }

    newNode->prev = _tail;
    _tail = newNode;
    ++_size;
}

在指定位置插入节点,实现如下:

template <typename T>
void DLinkedList<T>::insertAt(DListNode<T> *node, T value) {
    DListNode<T> *newNode = new DListNode<T>();
    newNode->data = value;

    newNode->prev = node;
    newNode->next = node->next;
    node->next = newNode;

    if (node == _tail) {
        _tail = newNode;
    } else {
        newNode->next->prev = newNode;
    }

    ++_size;
}

2.4 删除节点操作

删除头部节点,实现如下:

template <typename T>
void DLinkedList<T>::deleteFront() {
    if (empty()) {
        return;
    }

    DListNode<T> *node = _head;

    _head = node->next;
    if (_head != nullptr) {
        _head->prev = nullptr;
    } else {
        _tail = nullptr;
    }

    delete node;
    --_size;
}

删除尾部节点,实现如下:

template <typename T>
void DLinkedList<T>::deleteBack() {
    if (empty()) {
        return;
    }

    DListNode<T> *node = _tail;
    _tail = node->prev;
    if (_tail != nullptr) {
        _tail->next = nullptr;
    } else {
        _head = nullptr;
    }

    delete node;
    --_size;
}

删除任意节点,实现如下:

template <typename T>
void DLinkedList<T>::deleteAt(DListNode<T> *node) {
    if (node == nullptr) {
        return;
    }

    if (node->prev == nullptr) {
        deleteFront();
    } else if (node->next == nullptr) {
        deleteBack();
    } else {
        node->prev->next = node->next;
        node->next->prev = node->prev;
        delete node;
        --_size;
    }
}

2.5 查找节点操作

根据值查找节点,实现如下:

template <typename T>
DListNode<T> *DLinkedList<T>::find(T value) {
    DListNode<T> *node = _head;

    while (node != nullptr) {
        if (node->data == value) {
            return node;
        }
        node = node->next;
    }

    return nullptr;
}

根据下标查找节点,实现如下:

template <typename T>
DListNode<T> *DLinkedList<T>::findAt(int index) {
    if (index >= size()) {
        return nullptr;
    }

    DListNode<T> *node = _head;
    int i = 0;

    while (node != nullptr && i < index) {
        node = node->next;
        ++i;
    }

    return node;
}

2.6 输出链表操作

template <typename T>
void DLinkedList<T>::print() {
    DListNode<T> *node = _head;
    while (node != nullptr) {
        cout << node->data << " ";
        node = node->next;
    }
    cout << endl;
}

3. 示例说明

3.1 实现双向链表并遍历

int main() {
    DLinkedList<int> list;

    // 在头尾插入节点
    list.insertFront(1);
    list.insertBack(2);

    // 在头部插入节点,使链表变为 3 1 2
    DListNode<int> *node = list.find(1);
    list.insertAt(node, 3);

    // 删除尾部节点,使链表变为 3 1
    list.deleteBack();

    // 遍历输出链表
    list.print();

    return 0;
}

输出结果:

3 1

3.2 按下标查找节点并删除

int main() {
    DLinkedList<int> list;

    // 在头尾插入节点
    list.insertFront(1);
    list.insertBack(2);

    // 在头部插入节点,使链表变为 3 1 2
    DListNode<int> *node = list.find(1);
    list.insertAt(node, 3);

    // 删除下标为 1 的节点,即 1,使链表变为 3 2
    node = list.findAt(1);
    list.deleteAt(node);

    // 遍历输出链表
    list.print();

    return 0;
}

输出结果:

3 2

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++数据结构之双向链表 - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • mosn基于延迟负载均衡算法 — 走得更快,期待走得更稳

    前言 这篇文章主要是介绍mosn在v1.5.0中新引入的基于延迟的负载均衡算法。 对分布式系统中延迟出现的原因进行剖析 介绍mosn都通过哪些方法来降低延迟 构建来与生产环境性能分布相近的测试用例来对算法进行验证 地址:https://github.com/mosn/mosn/pull/2253 在开始聊基于延迟的负载均衡算法之前,先介绍下什么是负载均衡——…

    算法与数据结构 2023年5月8日
    00
  • 考研数据结构模板:顺序表、链表、栈、队列

    考研数据结构模板:顺序表、链表、栈、队列 前言 代码风格偏向于考研风格而非算法竞赛风格。 代码实现参考《2024数据结构王道复习指导》。 注释详细、保证看懂。 下面是已实现的数据结构模板: 顺序表SeqList 链表LinkList 双链表DLinkList 顺序栈SeqStack 循环顺序队列CircleQueue 链队列LinkQueue 顺序表SeqL…

    算法与数据结构 2023年4月17日
    00
  • C语言数据结构之队列的定义与实现

    C语言数据结构之队列的定义与实现 什么是队列 队列是一种特殊的线性数据结构,它只允许在队列的头部进行删除操作,在队列的尾部进行插入操作,这种操作方式被成为“先进先出”或“FIFO(first in first out)”。 队列的实现方式 队列可以通过数组和链表两种方式进行实现。 1. 数组实现 数组实现队列时,可以定义一个存放元素的数组,同时需要记录队列的…

    数据结构 2023年5月17日
    00
  • Java数据结构之链表相关知识总结

    Java数据结构之链表相关知识总结 链表是一种非常常用的数据结构,它有许多实际应用,比如链表可以用来实现栈、队列、散列表和图等数据结构。在Java语言中,链表的实现方式主要有单向链表、双向链表和循环链表。 单向链表 单向链表是一种链表结构,每个节点包含两个元素:节点值和一个指向下一个节点的引用。链表的头结点(第一个节点)不包含值,仅包含指向链表中第一个实际节…

    数据结构 2023年5月17日
    00
  • 如何使用C语言实现平衡二叉树数据结构算法

    使用C语言实现平衡二叉树数据结构算法可以分为以下几个步骤: 第一步:了解平衡二叉树 平衡二叉树是一种二叉搜索树,它具有以下特点: 高度平衡:每个节点的左右子树的高度差不能超过1。 有序性:对于任意一个节点,它的左子树中的所有节点都小于它,它的右子树中的所有节点都大于它。 平衡二叉树的优点在于它的查找、插入和删除操作都可以在O(log n)的时间内完成,比较快…

    数据结构 2023年5月17日
    00
  • 简单讲解哈希表

    哈希表(Hash Table),也被称为散列表,是一种高效的数据结构,它可以在O(1)的时间复杂度下完成插入、删除、查找等基本操作。哈希表是通过将关键字映射到一个固定大小的表中来实现的,这个映射函数被称为哈希函数。 什么是哈希函数 哈希函数是将任意长度的输入值(也称为“键”或“关键字”)映射为固定大小的输出值(也称为“哈希值”或“散列”)。哈希函数必须将不同…

    数据结构 2023年5月17日
    00
  • 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解

    解析从源码分析常见的基于Array的数据结构动态扩容机制的详解 什么是动态扩容机制 动态扩容机制是指,当一个数据结构达到其容量限制时,自动增加容量大小以继续存储新的数据。在动态扩容时,需要考虑到时间和空间的平衡,因为扩容需要分配新的内存空间,在处理大量数据时,需要尽可能减少空间浪费和分配内存的时间消耗。 基于Array的数据结构 Array是一种连续存储的数…

    数据结构 2023年5月17日
    00
  • Java数据结构之顺序表的实现

    下面是“Java数据结构之顺序表的实现”的完整攻略: 标题:Java数据结构之顺序表的实现 一、什么是顺序表 顺序表是一种线性表结构,其数据元素在物理位置上是连续的,通过下标访问,具有随机访问的优点。 二、顺序表的实现 使用Java语言实现顺序表,需要定义以下三个类: 1. SeqList类 构造顺序表的数据结构,并定义了一些基本操作,如插入、删除、修改等。…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部