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日

相关文章

  • C语言线性表的顺序表示与实现实例详解

    C语言线性表的顺序表示与实现实例详解 1. 线性表的定义 线性表是一种线性结构,它是由n个数据元素(n≥0)组成的有限序列。当n=0时,我们称为一个空表。 在C语言中,我们可以通过数组来实现线性表的顺序表示,每个数据元素都存在数组的一个位置中,数组下标可以看作是该数据元素的位置。 2. 线性表的基本操作 一个线性表的基本操作有以下几种: 2.1 初始化线性表…

    数据结构 2023年5月17日
    00
  • C语言数据结构之学生信息管理系统课程设计

    C语言数据结构之学生信息管理系统课程设计 介绍 本文讲解学生信息管理系统的设计过程,包括需求分析、设计思路、实现步骤等。 需求分析 学生信息管理系统是一种常见的数据结构应用场景。通过该系统,可以实现对学生信息的有效管理和查询。在设计之前,我们需要明确系统的需求和功能,包括: 学生信息的录入、删除、修改和查询; 各类信息的统计和分析,如学生总数、男女比例等; …

    数据结构 2023年5月17日
    00
  • 第14届蓝桥杯C++B组省赛题解(A-J)(更新完毕)

    目录 A. 日期统计 题目内容 思路 代码 答案 B.01 串的熵 题目内容 思路 代码 答案 C.冶炼金属 题目内容 输入格式 输出格式 输入样例 输出样例 思路 代码 D.飞机降落 题目内容 输入格式 输出格式 输入样例 输出样例 思路 代码 E.接龙数列 题目内容 输入格式 输出格式 输入样例 输出样例 思路 代码 F.岛屿数量 题目内容 输入格式 输…

    算法与数据结构 2023年4月25日
    00
  • NTP时间同步服务器(频率同步)包含帧同步、载波同步、位同步

    NTP时间同步服务器(频率同步)包含帧同步、载波同步、位同步 NTP时间同步服务器(频率同步)包含帧同步、载波同步、位同步 京准电子科技官微——ahjzsz 同步的概念   同步技术是数字通信系统中非常重要的技术。一般来说数字通信系统要实现多种同步功能才能实现正确的数据通信任务。其技术目标是实现不同地域收发双方的同步通信互联,实现一致的信息数据交换,因此,通…

    算法与数据结构 2023年4月17日
    00
  • C语言数据结构 双向链表的建立与基本操作

    C语言数据结构 双向链表的建立与基本操作 双向链表的定义 双向链表是一种常见的线性数据结构,它由多个结点组成,每个结点有两个指针,一个指向前一个结点,一个指向后一个结点。对于一个双向链表,我们可以获得其第一个结点和最后一个结点的指针,也可以沿着链表从前往后或从后往前遍历链表的每个结点。 双向链表的建立 我们首先需要定义一个双向链表的结点类型,包括两个指针,一…

    数据结构 2023年5月17日
    00
  • 字典树的基本知识及使用C语言的相关实现

    字典树的基本知识 字典树,英文名为Trie树,又称单词查找树或键树,是一种树形数据结构,用于表示关联数组或映射。它的优点是,可以大大减少无谓的字符串比较,查询效率比哈希表高。 字典树的核心概念是节点,每个节点包含一个字符和指向子节点的指针。根节点为空字符,每个字符串以一个独立的路径插入节点。如果一个字符串是另一个字符串的前缀,那么这个字符串的节点是另一个字符…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构yocto queue队列链表代码分析

    JavaScript数据结构yocto queue队列链表代码分析 什么是队列? 队列(Queue)是一种基础的数据结构,属于线性结构,它的特点是在队列尾插入元素,同时在队列头删除元素,遵循先进先出(FIFO)的原则。队列可以简单的理解为排队,先到达的先被服务,而后到达的则等在队列尾排队等待。队列的应用非常广泛,例如排队系统、消息队列等。 队列的实现方式 队…

    数据结构 2023年5月17日
    00
  • C语言数据结构中串的模式匹配

    C语言数据结构中串的模式匹配 什么是字符串的模式匹配? 字符串的模式匹配是指在一个主字符串中查找特定的子串,找到特定的子串后输出其在主字符串中的位置。 例如有一个主串”this is a test string”,要查找的子串为”string”,则字符串的模式匹配应能输出”string”在主串中的位置为17。 如何实现字符串的模式匹配? 字符串的模式匹配可以…

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