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日

相关文章

  • Java矢量队列Vector使用示例

    Java矢量队列Vector使用示例 Java中的Vector是一个可调整大小的数组实现,与ArrayList类似,但是可以支持同步。在需要线程安全时,可以使用Vector代替ArrayList。 Vector的创建 使用Vector需要先导入Java.util.Vector类,然后可以使用以下代码创建一个Vector: Vector<Object&g…

    数据结构 2023年5月17日
    00
  • Java数据结构之单链表详解

    下面是单链表攻略的详细讲解。 什么是单链表? 单链表是一种线性数据结构,它由一系列结点组成,每个结点包含数据域和指针域。数据域用于存储数据,指针域用于指向下一个结点。单链表的优点是插入和删除操作的时间复杂度为O(1),缺点是随机访问的时间复杂度为O(n)。 单链表的基本操作 单链表的基本操作包括插入操作、删除操作、查找操作和遍历操作。下面将分别介绍这些操作。…

    数据结构 2023年5月17日
    00
  • Java数据结构之单链表的实现与面试题汇总

    Java数据结构之单链表的实现与面试题汇总 一、前言 单链表是数据结构中最基础的数据结构之一,也是在面试时经常会考察的一个知识点。本文将详细介绍单链表的实现过程,并对常见的单链表面试题进行总结,帮助大家深入了解单链表的原理和应用。 二、单链表的实现 单链表是由一些列节点构成的,每个节点包括一个数据和一个指向下一个节点的指针。下面我们将实现一个简单的单链表,并…

    数据结构 2023年5月17日
    00
  • Java数据结构之对象比较详解

    Java数据结构之对象比较详解 在Java中,比较两个对象的内容是否相等一直是程序员们比较困惑的问题。本文将详细探讨Java中对象比较的几种方式,并给出相应的示例。 基本类型比较 在Java中,比较基本类型的值可以使用双等号(==)进行判断。例如: int a = 1; int b = 1; boolean result = a == b; System.o…

    数据结构 2023年5月17日
    00
  • Go select使用与底层原理讲解

    标题:Go select使用与底层原理讲解 标准库提供的go语言引擎的选择器select语法是并发编程中常用的语法之一,它允许协程同时等待多个IO操作的完成,通常会和通道配合使用。在本文中,我们将详细讲解Go select的使用和底层原理。 Go select的使用 基本语法 在Go语言中,select语法的基本语法如下: select { case &lt…

    数据结构 2023年5月17日
    00
  • nginx内存池源码解析

    Nginx内存池源码解析 Nginx是一个高性能、高并发的Web服务器。为了提高其性能和速度,Nginx采用了特殊的内存管理机制,即内存池。 什么是内存池? 内存池是一种高效的内存分配和管理机制。它将一块内存划分成多个大小相等的块,并按需分配给系统。当内存块不再使用时,它并不被立即释放,而是留在内存池中待重复利用。 Nginx内存池结构 Nginx内存池主要…

    数据结构 2023年5月17日
    00
  • C语言数据结构之顺序数组的实现

    C语言数据结构之顺序数组的实现 前言 顺序数组是数据结构的一个重要部分,它代表着一种基本的数据结构,能够在数据存储与访问方面发挥极大的作用。本文将详细讲解如何在C语言中实现顺序数组。 简介 顺序数组是在物理内存中顺序存储的一组元素数据,可以通过下标访问任意一个元素。通常情况下,顺序数组的数据类型是相同的,而且每一个元素的大小也是相同的。 实现 实现顺序数组主…

    数据结构 2023年5月17日
    00
  • C语言数据结构之算法的时间复杂度

    关于C语言数据结构之算法的时间复杂度,需要先了解一些基本概念。 什么是时间复杂度 时间复杂度是算法的一种衡量标准,用于评估算法的执行效率。表示代码执行的时间和数据量之间的关系,通常用大O符号来表示,称为“大O记法”。 时间复杂度的分类 时间复杂度可分为以下几类: 常数阶:O(1) 对数阶:O(log n) 线性阶:O(n) 线性对数阶:O(n log n) …

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