双向链表

有关链表的知识可以点击我上篇文章这里就不再赘述LinkedList



  • 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

双向循环链表的可以点击我这篇文章这里就不再赘述DoubleLoopLinkList

添加

头添加

void addFirst(const T &e) {
//新建一个节点让它前驱指向头,后继指向头的后继然后再让头的后继指向新建的节点,
head->next = new Node<T>(e, head, head->next);
//把新节点的后继节点的前驱指向新节点
head->next->next->prev = head->next;
++size;
}

指定节点添加

void add(const int index, const T &e) {
assert(index >= 0 && index <= size);
Node<T> *prevNode = head;
for (int i = 0; i < index; ++i) {
prevNode = prevNode->next;
}
prevNode->next = new Node<T>(e, prevNode, prevNode->next);
prevNode->next->next->prev = prevNode->next;
++size;
}

尾添加

void addLast(const T &e) {
//
tail->prev = new Node<T>(e, tail->prev, tail);
tail->prev->prev->next = tail->prev;
++size;
}

删除

头删除

 T removeFirst() {
return remove(0);//调不调都是O(1),就这吧。
}

指定节点删除

T remove(int index) {
assert(index >= 0 && index < size);
//找到待删除节点的前一节点
Node<T> *prevNode = head;
for (int i = 0; i < index; ++i) {
prevNode = prevNode->next;
}
//暂存要删除的节点
Node<T> *retNode = prevNode->next;
T temp = retNode->e;
//前一节点的后继指向待删除节点的后继
prevNode->next = retNode->next;
//后一节点的前驱指向待删除节点的前驱
retNode->next->prev = retNode->prev;
retNode->next = nullptr;
retNode->prev = nullptr;
--size;
delete retNode;
retNode = nullptr;
return temp;
}

尾删除

T removeLast() {
//先暂存要删除的节点
Node<T> *retNode = tail->prev;
T temp = retNode->e;
//尾指针的前驱指向待删除的前驱
tail->prev = retNode->prev;
待删除节点前面一节点的后继指向尾指针
retNode->prev->next = tail;
retNode->next = nullptr;
retNode->prev = nullptr;
delete retNode;
retNode = nullptr;
--size;
return temp;
}

头尾指针版

//
// Created by cheng on 2021/7/5.
// #ifndef LINKEDLIST_TEST_H
#define LINKEDLIST_TEST_H
#include <assert.h> template<typename T>
class Node {
public:
T e;
Node *prev;
Node *next; Node() : e(0), prev(nullptr), next(nullptr) { } Node(const T &E) : e(E), prev(nullptr), next(nullptr) { } Node(const T &E, Node<T> *Prev, Node<T> *Next) : e(E), prev(Prev), next(Next) { }
}; template<typename T>
class DoubleLinkedList {
public:
DoubleLinkedList() : size(0) {
head = new Node<T>(0, nullptr, head);
tail = new Node<T>(0, tail, nullptr);
} constexpr int getSize() const {
return size;
} constexpr bool isEmpty() const {
return size == 0;
} void add(const int index, const T &e) {
assert(index >= 0 && index <= size);
Node<T> *prevNode = head;
for (int i = 0; i < index; ++i) {
prevNode = prevNode->next;
}
prevNode->next = new Node<T>(e, prevNode, prevNode->next);
prevNode->next->next->prev = prevNode->next;
++size;
} void addFirst(const T &e) {
head->next = new Node<T>(e, head, head->next);
head->next->next->prev = head->next;
++size;
} void addLast(const T &e) {
tail->prev = new Node<T>(e, tail->prev, tail);
tail->prev->prev->next = tail->prev;
++size;
} void set(const int index, const T &e) {
assert(index >= 0 && index < size);
Node<T> *cur = head->next;
for (int i = 0; i < index; ++i) {
cur = cur->next;
}
cur->e = e;
} void setFirst(const T &e) {
head->next->e = e;
} void setLast(const T &e) {
tail->prev->e = e;
} bool contains(const T &e) const {
Node<T> *cur = head->next;
while (cur != nullptr) {
if (cur->e = e) {
return true;
}
cur = cur->next;
}
return false;
} T get(const int index) const {
assert(index >= 0 && index < size);
Node<T> *cur = head->next;
for (int i = 0; i < index; ++i) {
cur = cur->next;
}
return cur->e;
} T getFirst() const {
return head->next->e;
} T getLast() const {
return tail->prev->e;
} T remove(int index) {
assert(index >= 0 && index < size);
Node<T> *prevNode = head;
for (int i = 0; i < index; ++i) {
prevNode = prevNode->next;
}
Node<T> *retNode = prevNode->next;
prevNode->next = retNode->next;
retNode->next->prev = retNode->prev;
retNode->next = nullptr;
retNode->prev = nullptr;
--size;
T temp = retNode->e;
delete retNode;
retNode = nullptr;
return temp;
} T removeFirst() {
return remove(0);
} T removeLast() {
Node<T> *retNode = tail->prev;
T temp = retNode->e;
tail->prev = retNode->prev;
retNode->prev->next = tail;
retNode->next = nullptr;
retNode->prev = nullptr;
delete retNode;
retNode = nullptr;
--size;
return temp;
} ~DoubleLinkedList() {
Node<T> *cur = head->next;
Node<T> *temp;
while (cur != nullptr) {
temp = cur->next;
delete cur;
cur = temp;
}
head->next = nullptr;
head->prev = nullptr;
tail->prev = nullptr;
tail->next = nullptr;
delete head;
head = nullptr;
delete tail;
tail = nullptr;
} void print() {
Node<T> *prevNode = head;
std::cout << "LinkedList: size = " << size << std::endl;
std::cout << "[";
for (int i = 0; i < size; ++i) {
prevNode = prevNode->next;
std::cout << prevNode->e;
if (i < size - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
} private:
Node<T> *head, *tail;
int size;
};
#endif //LINKEDLIST_TEST_H

虚拟头节点

//
// Created by cheng on 2021/7/5.
// #ifndef LINKEDLIST_DOUBLELINKEDLIST_H
#define LINKEDLIST_DOUBLELINKEDLIST_H #include <assert.h> template<typename T>
class Node {
public:
T e;
Node *prev;
Node *next; Node() : e(0), prev(nullptr), next(nullptr) {} Node(const T &E) : e(E), prev(nullptr), next(nullptr) {} Node(const T &E, Node<T> *Prev, Node<T> *Next) : e(E), prev(Prev), next(Next) {}
}; template<typename T>
class DoubleLinkedList {
public:
DoubleLinkedList() : size(0) {
dummyHead = new Node<T>(0, nullptr, dummyHead);
} constexpr int getSize() const {
return size;
} constexpr bool isEmpty() const {
return size == 0;
} void add(const int index, const T &e) {
assert(index >= 0 && index <= size);
Node<T> *prevNode = dummyHead;
for (int i = 0; i < index; ++i) {
prevNode = prevNode->next;
}
prevNode->next = new Node<T>(e, prevNode, prevNode->next);
prevNode->next->next->prev = prevNode->next;
++size;
} void addFirst(const T &e) {
add(0, e);
} void addLast(const T &e) {
add(size, e);
} void set(const int index, const T &e) {
assert(index >= 0 && index < size);
Node<T> *cur = dummyHead->next;
for (int i = 0; i < index; ++i) {
cur = cur->next;
}
cur->e = e;
} void setFirst(const T &e) {
set(0, e);
} void setLast(const T &e) {
set(size, e);
} bool contains(const T &e) const {
Node<T> *cur = dummyHead->next;
while (cur != nullptr) {
if (cur->e = e) {
return true;
}
cur = cur->next;
}
return false;
} T get(const int index) const {
assert(index >= 0 && index < size);
Node<T> *cur = dummyHead->next;
for (int i = 0; i < index; ++i) {
cur = cur->next;
}
return cur->e;
} T getFirst() const {
return get(0);
} T getLast() const {
return get(size - 1);
} T remove(int index) {
assert(index >= 0 && index < size);
Node<T> *prevNode = dummyHead;
for (int i = 0; i < index; ++i) {
prevNode = prevNode->next;
}
Node<T> *retNode = prevNode->next;
prevNode->next = retNode->next;
retNode->next->prev = retNode->prev;
retNode->next = nullptr;
retNode->prev = nullptr;
--size;
T temp = retNode->e;
delete retNode;
retNode = nullptr;
return temp;
} T removeFirst() {
return remove(0);
} T removeLast() {
return remove(size - 1);
} ~DoubleLinkedList() {
Node<T> *cur = dummyHead->next;
Node<T> *temp;
while (cur != nullptr) {
temp = cur->next;
delete cur;
cur = temp;
}
dummyHead->next = nullptr;
dummyHead->prev = nullptr;
delete dummyHead;
dummyHead = nullptr;
} void print() {
Node<T> *prevNode = dummyHead;
std::cout << "LinkedList: size = " << size << std::endl;
std::cout << "[";
for (int i = 0; i < size; ++i) {
prevNode = prevNode->next;
std::cout << prevNode->e;
if (i < size - 1) {
std::cout << ", ";
}
}
std::cout << "]" << std::endl;
} private:
Node<T> *dummyHead;
int size;
}; #endif //LINKEDLIST_DOUBLELINKEDLIST_H

双向链表(DoubleLinkList)的更多相关文章

  1. java实现双向链表的增删改查

    双向链表的增删改查 和单链表的操作很像:https://blog.csdn.net/weixin_43304253/article/details/119758276 基本结构 1.增加操作 1.链接 ...

  2. Java 数据结构之双向链表

    一.概述: 1.什么是双向链表: 链表中的每个节点即指向前面一个节点,也指向后面一个节点,就像丢手绢游戏一样,每个人都手拉手 2.从头部插入 要对链表进行判断,如果为空则设置尾节点为新添加的节点,如果 ...

  3. c++ list双向链表管理对象

    #cat list.cc #include <cstdlib> #include <iostream> #include <stdio.h> using names ...

  4. python算法与数据结构-双向链表(40)

    一.双向链表的介绍 一种更复杂的链表是“双向链表”或“双面链表”.每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值:而另一个指向下一个节点,当此节点为最后一个节点时,指向空值. ...

  5. java数据结构——单链表、双端链表、双向链表(Linked List)

    1.继续学习单链表,终于摆脱数组的魔爪了,单链表分为数据域(前突)和引用域(指针域)(后继),还有一个头结点(就好比一辆火车,我们只关心火车头,不关心其它车厢,只需知晓车头顺藤摸瓜即可),头结点没有前 ...

  6. python实现双向链表的操作

    双向链表 双向链表又叫做双链表,每个节点有两个指针域和一个数据域.prev指针域指向前一个节点,next指针域指向下一个节点.注意,第一个节点的prev指针域指向空值,最后一个节点的next域也是指向 ...

  7. 双向链表——Java实现

    双向链表 链表是是一种重要的数据结构,有单链表和双向链表之分:本文我将重点阐述不带头结点的双向链表: 不带头结点的带链表 我将对双链表的增加和删除元素操作进行如下解析 1.增加元素(采用尾插法) (1 ...

  8. 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...

  9. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

随机推荐

  1. prometheus node-exporter增加新的自定义监控项

    项目中collector中新增加自己所需监控项即可 定义启动node-exporter是传入的参数 var ( phpEndPoint = kingpin.Flag("collector.p ...

  2. 二、Python流程控制练习题

    一.分支结构-if等 练习题: 练习1:英制单位与公制单位互换 练习2:掷骰子决定做什么 练习3:百分制成绩转等级制 练习4:输入三条边长如果能构成三角形就计算周长和面积 练习5:个人所得税计算器 练 ...

  3. [文章]Linux宕机故障分析案例

    [文章]Linux宕机故障分析案例 已采纳 收藏  0  1669 0 马化辉 2018-07-01发布 背景 在Linux系统环境下,服务器宕机发生的频率比较小,但是不少工程师或多或少都会遇到这 ...

  4. Ansible_编写Playbook文件

    一.Playbook的实施 1.Ansible playbook与临时命令概述: 临时命令可以作为一次性命令对一组目标主机运行一项简单的任务 play是针对清单中选定的主机运行的一组有序任务.play ...

  5. 文本编辑_Vim&Vi

    一.Vim.Vi文本编辑器 1️⃣:vi: Visual Interface,文本编辑器 2️⃣:文本:ASCII, Unicode 3️⃣:VIM - Vi IMproved 二.Vim.vi的特点 ...

  6. linux初级之总结复习

    一.linux命令复习 1.ls:列出当前目录下的文件 -h: -l: -d: -a: 2. man: 命令帮助手册 3. cd: 切换目录 -:  ~: ..: cd: 4. pwd: 显示当前工作 ...

  7. Git 分支基本命令

    1. 查看当前分支 (git branch) 2. 创建分支 (git branch 分支名) 3.切换分支(git checkout 分支名) 4.分支上的常规操作 5.分支的合并 (git che ...

  8. Linux 中/var/spool/postfix/maildrop目录下堆积大量小文件 如何删除

      Linux 中/var/spool/postfix/maildrop目录下堆积大量小文件 如何删除 1.先删除maildrop目录下的通知邮件文件 命令:find /var/spool/postf ...

  9. GO语言异常处理02---返回错误

    package main import ( "errors" "fmt" "math" ) /*计算圆面积,同时返回[结果-错误对]*/ f ...

  10. Kafka源码分析(三) - Server端 - 消息存储

    系列文章目录 https://zhuanlan.zhihu.com/p/367683572 目录 系列文章目录 一. 业务模型 1.1 概念梳理 1.2 文件分析 1.2.1 数据目录 1.2.2 . ...