带头节点 (非头指针) 双向链表 (doubly linked list)

线性表是一种线性结构,它具有相同类型的 n(n≥0)n \ (n ≥ 0)n (n≥0) 个数据元素组成的有限序列。线性表:数组、单向链表、双向链表。
doubly (bidirectional) linked list:双向链表

1. 单向链表 (singly linked list)

单向链表是一种使用指针来存储值的数据结构。链表中的每个节点包含一个字段,用于指向链表的下一个节点。另外有一个独立的根指针指向链表的第 1 个节点。由于节点在创建时是采用动态分配内存的方式,所以它们可能分布于内存之中。遍历链表是根据指针进行的,所以节点的物理排列无关紧要。单向链表只能以一个方向进行遍历。

为了把一个新值插入到一个有序的单链表中,你首先必须找到链表中合适的插入位置。对于无序单链表,新值可以插入到任何位置。把一个新节点链接到链表中需要两个步骤。首先,新节点的 link 字段必须设置为指向它的目标后续节点。其次,前一个节点的 link 字段必须设置为指向这个新节点。在许多其他语言中,插入函数保存一个指向前一个节点的指针来完成第 2 个步骤。但是,这个技巧使插入到链表的起始位置成为一种特殊情况,需要单独处理。在 C 语言中,你可以通过保存一个指向必须进行修改的 link 字段的指针,而不是保存一个指向前一个节点的指针,从而消除了这个特殊情况。

2. 双向链表 (doubly linked list)

双向链表中的每个节点包含两个 link 字段:其中一个指向链表的下一个节点,另一个指向链表的前一个节点。双向链表可以设置两个根指针,分别指向第 1 个节点和最后一个节点。因此,遍历双向链表可以从任何一端开始,而且在遍历过程中可以改变方向。为了把一个新节点插入到双向链表中,我们必须修改 4 个指针。新节点的前向和后向 link 字段必须被设置,前一个节点的后向 link 字段和后一个节点的前向 link 字段也必须进行修改,使它们指向这个新节点。

将类的声明和实现分离,在头文件 (.h 文件或 .hpp) 中尽量只包含声明,而在实现文件 (.cpp 文件) 中负责实现!C++ 编译器不支持对模板的分离式编译。

3. 带头节点 (非头指针) 双向链表 (doubly linked list)

3.1 insert_first - delete_node - display

//============================================================================
// Name        : doubly linked list
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#define MAX_NODE_LEN 401#include <stdio.h>typedef struct NODE {int data;struct NODE *prev;struct NODE *next;
} Node;Node node_array[MAX_NODE_LEN];
int node_array_idx = 0;void insert_first(Node *head, Node *node)
{node->next = head->next;node->prev = head;// if (head->next != nullptr)if (node->next != nullptr){node->next->prev = node;}head->next = node;
}void delete_node(const Node *node)
{Node *prev_node = node->prev;Node *next_node = node->next;// current node - nodeprev_node->next = next_node;// if (node->next != nullptr)if (next_node != nullptr){next_node->prev = prev_node;}
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != nullptr){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initializationroot.prev = nullptr;root.next = nullptr;root.data = 0;for (int i = 0; i < MAX_NODE_LEN; ++i){node_array[i].prev = nullptr;node_array[i].next = nullptr;node_array[i].data = 0;}// insert 0node_array[0].data = 0;insert_first(&root, &(node_array[0]));// insert 2node_array[2].data = 2;insert_first(&root, &(node_array[2]));// insert 4node_array[4].data = 4;insert_first(&root, &(node_array[4]));// insert 6node_array[6].data = 6;insert_first(&root, &(node_array[6]));// insert 8node_array[8].data = 8;insert_first(&root, &(node_array[8]));display(&root);// delete 4delete_node(&(node_array[4]));printf("\ndelete data %d\n", 4);display(&root);// delete 0delete_node(&(node_array[0]));printf("\ndelete data %d\n", 0);display(&root);// delete 8delete_node(&(node_array[8]));printf("\ndelete data %d\n", 8);display(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0delete data 0
node 1: 8
node 2: 6
node 3: 2delete data 8
node 1: 6
node 2: 2insert data 10
node 1: 10
node 2: 6
node 3: 2
请按任意键继续. . .

3.2 insert_first - delete_node - display - traverse function

//============================================================================
// Name        : doubly linked list
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#define MAX_NODE_LEN 401
#define NULL 0#include <stdio.h>typedef struct NODE {int data;struct NODE *prev;struct NODE *next;
} Node;Node node_array[MAX_NODE_LEN];
int node_array_idx = 0;void insert_first(Node *head, Node *node)
{node->next = head->next;node->prev = head;// if (head->next != NULL)if (node->next != NULL){node->next->prev = node;}head->next = node;
}void delete_node(const Node *node)
{Node *prev_node = node->prev;Node *next_node = node->next;// current node - nodeprev_node->next = next_node;// if (node->next != NULL)if (next_node != NULL){next_node->prev = prev_node;}
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != NULL){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initializationroot.prev = NULL;root.next = NULL;root.data = 0;for (int i = 0; i < MAX_NODE_LEN; ++i){node_array[i].prev = NULL;node_array[i].next = NULL;node_array[i].data = 0;}// insert 0node_array[0].data = 0;insert_first(&root, &(node_array[0]));// insert 2node_array[2].data = 2;insert_first(&root, &(node_array[2]));// insert 4node_array[4].data = 4;insert_first(&root, &(node_array[4]));// insert 6node_array[6].data = 6;insert_first(&root, &(node_array[6]));// insert 8node_array[8].data = 8;insert_first(&root, &(node_array[8]));display(&root);// delete 4delete_node(&(node_array[4]));printf("\ndelete data %d\n", 4);display(&root);// delete 0delete_node(&(node_array[0]));printf("\ndelete data %d\n", 0);display(&root);// delete 8delete_node(&(node_array[8]));printf("\ndelete data %d\n", 8);display(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display(&root);/********************************* traverse function *********************************/Node *head = &root;Node *ptr_node = head->next;Node *tmp_node;while (ptr_node != NULL){tmp_node = ptr_node->next;if (2 == ptr_node->data) {delete_node(ptr_node);}ptr_node = tmp_node;}/********************************* traverse function *********************************/printf("\ndelete data %d\n", 2);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0delete data 0
node 1: 8
node 2: 6
node 3: 2delete data 8
node 1: 6
node 2: 2insert data 10
node 1: 10
node 2: 6
node 3: 2delete data 2
node 1: 10
node 2: 6
请按任意键继续. . .

3.3 insert_first - delete_node - display - traverse function

//============================================================================
// Name        : doubly linked list
// Author      : Yongqiang Cheng
// Version     : Version 1.0.0
// Copyright   : Copyright (c) 2019 Yongqiang Cheng
// Description : Hello World in C++, Ansi-style
//============================================================================#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif#define MAX_NODE_LEN 401
#define NULL 0#include <stdio.h>typedef struct NODE {int data;struct NODE *prev;struct NODE *next;
} Node;Node node_array[MAX_NODE_LEN];
int node_array_idx = 0;void insert_first(Node *head, Node *node)
{node->next = head->next;node->prev = head;// if (head->next != NULL)if (node->next != NULL){node->next->prev = node;}head->next = node;
}void delete_node(const Node *node)
{Node *prev_node = node->prev;Node *next_node = node->next;// current node - nodeprev_node->next = next_node;// if (node->next != NULL)if (next_node != NULL){next_node->prev = prev_node;}
}void delete_node_v1(const Node *node)
{// current node - nodenode->prev->next = node->next;// if (node->next != NULL)if (node->next != NULL){node->next->prev = node->prev;}
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != NULL){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initializationroot.prev = NULL;root.next = NULL;root.data = 0;for (int i = 0; i < MAX_NODE_LEN; ++i){node_array[i].prev = NULL;node_array[i].next = NULL;node_array[i].data = 0;}// insert 0node_array[0].data = 0;insert_first(&root, &(node_array[0]));// insert 2node_array[2].data = 2;insert_first(&root, &(node_array[2]));// insert 4node_array[4].data = 4;insert_first(&root, &(node_array[4]));// insert 6node_array[6].data = 6;insert_first(&root, &(node_array[6]));// insert 8node_array[8].data = 8;insert_first(&root, &(node_array[8]));display(&root);// delete 4delete_node_v1(&(node_array[4]));printf("\ndelete data %d\n", 4);display(&root);// delete 0delete_node_v1(&(node_array[0]));printf("\ndelete data %d\n", 0);display(&root);// delete 8delete_node_v1(&(node_array[8]));printf("\ndelete data %d\n", 8);display(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display(&root);/********************************* traverse function *********************************/Node *head = &root;Node *ptr_node = head->next;Node *tmp_node;while (ptr_node != NULL){tmp_node = ptr_node->next;if (2 == ptr_node->data) {delete_node_v1(ptr_node);}ptr_node = tmp_node;}/********************************* traverse function *********************************/printf("\ndelete data %d\n", 2);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0delete data 0
node 1: 8
node 2: 6
node 3: 2delete data 8
node 1: 6
node 2: 2insert data 10
node 1: 10
node 2: 6
node 3: 2delete data 2
node 1: 10
node 2: 6
请按任意键继续. . .

References

https://www.thecrazyprogrammer.com/2015/09/doubly-linked-list-in-c-and-cpp.html
https://www.alphacodingskills.com/ds/doubly-linked-list.php

带头节点 (非头指针) 双向链表 (doubly linked list)相关推荐

  1. 双向链表(Doubly Linked List)

    双向链表(Doubly Linked List) 1. 双向链表的概念 1.1 双向链表的定义 双向链表又称为双链表,是链表的一种. 1.2 双向链表的结点结构 双向链表的结点包括三个部分:前驱指针域 ...

  2. C语言实现双向链表Doubly Linked List(附完整源码)

    双向链表Doubly Linked List list结构体 实现以下6个接口 双向链表Doubly Linked List完整源码(定义,实现,main函数测试) list结构体 typedef s ...

  3. 【头结点】【头指针】【首元结点】

    2022 -1-14 文章目录 2022 -1-14 1. 定义: 2. 哨兵(头结点) 3. 有无头结点的单链表的创建 3.1 有头结点 3.1.1 头插法: 3.1.2 尾插法: 3.2 无头结点 ...

  4. c语言链表不带头节点的排序,不带头结点的单向链表排序——插入排序(C语言)...

    LinkList* LinkListInsertSort(LinkList* pHead) { LinkList *pFirst = (LinkList *)NULL; /* 原链表剩下未排序节点的头 ...

  5. 软考题目之头结点、头指针和首元节点

    遇到一个让人迷惑的题目. 以下关于线性表采用链式存储时删除节点运算的描述,正确的是() A.带头结点的线性链表删除结点时,不需要更改头指针. B.带头结点的线性链表删除第一个结点时,需要更改头指针. ...

  6. 带头结点单链表、不带头结点单链表(头指针单链表)

    1.头结点和头指针的区别 1.1区别: 头指针表明了链表的结点,可以唯一确定一个单链表. 头指针指向链表的第一个结点,其记录第一个存储数据的结点的地址. 头结点是点链表的第一个结点,若单链表有头结点, ...

  7. 怎么样让指针指向尾结点C语言,带头结点头指针与带头结点尾指针的学习

    单循环链表 对于单链表而言,如果每次在遍历到单链表中间处时需要遍历整个链表,此时只能往后遍历,前方的指针便会丢失.如图1所示,此时若链表遍历到a2处依旧可以通过尾结点循环到a1处,这是单链表所不能解决 ...

  8. C++Doubly Linked List双向链表(附完整源码)

    C++AVL树自平衡二叉查找树 node结构体定义 实现了以下几个接口 Doubly Linked List双向链表算法的完整源码(定义,实现,main函数测试) node结构体定义 struct n ...

  9. C++之链表中头指针、头节点、首元结点的

    头指针:顾名思义是一个指针,指向链表的开始地址: 头结点:第一个节点,该节点只有地址信息,改地址指向下一个结点,数据域无信息: 首元结点:含第一个元素的结点,为链表的实际开始位置,数据域包含第一个数据 ...

  10. 头指针为head的带头结点的单链表判空条件head->next==null?

    由于考研需求,又乖乖滚回来捧起数据结构了,一年没碰书,忘得都差不多了,还得捡回来,哭死了. 进入正题,为何头指针为head的带头结点的单链表判空条件head->next==null?其实一开始这 ...

最新文章

  1. Oracle 树操作(select…start with…connect by…prior)
  2. python 3d大数据可视化软件_十大顶级大数据可视化工具推荐
  3. centos 6.5网卡dhcp不能获得网关
  4. Python数据可视化之Excel气泡图
  5. Real-Time Rendering 3 彩图
  6. Linux 命令(65)—— ld 命令
  7. php 判断是否是机器人,如何用PHP检测搜索引擎机器人?
  8. CheckedListBoxControl 实现复选框的单选与多选功能
  9. Centos7配置ThinkPHP5.0完整过程(二)
  10. HDU 2054 大数比较
  11. 1.1.2 Greedy Gift Givers 贪婪的送礼者
  12. 使用mergeAssets对Android的assets文件在构建的时候进行修改处理
  13. 一个学计算机的打字速度慢,电脑打字速度慢怎么办
  14. 大觉山漂流,男人的欢笑女人的尖叫
  15. DS线性表—多项式相加
  16. 4、如果体彩中了500万,我买房、买车、资助希望工程、去欧洲旅游;如果没中,我买下一期体彩,继续烧高香。
  17. warnings模块
  18. RxJava操作符学习APP
  19. HTML常用标签、文本格式化标签:加粗、倾斜、删除线、下划线等
  20. CSS3选择器-属性选择器

热门文章

  1. 一个算法面试题的5种不同解法
  2. asp、php、asp.net、jsp介绍及优缺点比较
  3. asp.net 视频教程
  4. crt图形显示装置_CRT消防控制室图形显示装置图形显示装置_使用说明书_V1.0.doc...
  5. 【安全知识分享】重磅|消防控制室培训.ppt(附下载)
  6. python cryptography key加密_python加密解密库cryptography使用openSSL生成的密匙加密解密...
  7. Cisco(思科)远程登录交换机
  8. 思科里服务器的dns配置文件,cisco设置dns
  9. UE5实现HTC Vive VR功能
  10. 基于PHP的华为手机商城系统(完整前后台)