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

bidirectional circular linked list:双向循环链表

建议使用带头结点,而非头指针的双向循环链表。

1. 双向链表

双向链表的每个数据结点中都有两个指针,分别指向直接后继 (next) 和直接前驱 (prev) 。

2. 双向循环链表

本节图片参考 https://www.cnblogs.com/skywang12345/p/3561803.html

双向链表和单链表都是由节点组成,双向链表的每个数据结点中都有两个指针,分别指向直接后继 (next) 和直接前驱 (prev) 。

双向循环链表最后一个结点的直接后继 (next) 指向表头 (head) 结点,而不像双向链表置为 NULL。

在判断是否到达表尾时,判断该结点直接后继 (next) 是否是表头结点,当直接后继 (next) 等于表头指针时,说明已到表尾。而不像双向链表那样判断直接后继 (next) 是否为 NULL。

双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

头节点 (非头指针) 双向循环链表示例图

表头 head 为空,head 的后继节点 (next) 为节点 10 (数据为 10 的节点);节点 10 的后继节点 (next) 是节点 20 (数据为 20 的节点),节点 20 的前继节点 (prev) 是节点 10;节点 20 的后继节点 (next) 是节点 30,节点 30 的前继节点 (prev) 是节点 20;…;末尾节点的后继节点 (next) 是表头 head。

2.1 头节点 (非头指针) 双向循环链表删除节点

头节点 (非头指针) 双向循环链表删除节点示例图

删除节点 30 (数据为 30 的节点)
删除之前:节点 20 的后继节点 (next) 为节点 30,节点 30 的前继节点 (prev) 为节点 20。节点 30 的后继节点 (next) 为节点 40,节点 40 的前继节点 (prev) 为节点 30。
删除之后:节点 20 的后继节点 (next) 为节点 40,节点 40 的前继节点 (prev) 为节点 20。

2.2 头节点 (非头指针) 双向循环链添加节点

头节点 (非头指针) 双向循环链表添加节点示例图

在节点 10 与 节点 20 之间添加节点 15
添加之前:节点 10 的后继节点 (next) 为节点 20,节点 20 的前继节点 (prev) 为节点 10。
添加之后:节点 10 的后继节点 (next) 为节点 15,节点 15 的前继节点 (prev) 为节点 10。节点 15 的后继节点 (next) 为节点 20,节点 20 的前继节点 (prev) 为节点 15。

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
#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;// equality: head->next->prev = node;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;next_node->prev = prev_node;
}void delete_node_v1(const Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;
}void delete_node_v2(Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;node->next = node->next = NULL;
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != head){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initialization// root.prev = &(root);// root.next = &(root);root.prev = root.next = &(root);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 != head){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);// insert 12node_array[12].data = 12;insert_first(&root, &(node_array[12]));printf("\ninsert data %d\n", 12);display(&root);/********************************* traverse function *********************************/{Node *head = &root;Node *ptr_node = head->prev;Node *tmp_node;while (ptr_node != head){tmp_node = ptr_node->prev;if (10 == ptr_node->data) {delete_node(ptr_node);}ptr_node = tmp_node;}}/********************************* traverse function *********************************/printf("\ndelete 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: 2delete data 2
node 1: 10
node 2: 6insert data 12
node 1: 12
node 2: 10
node 3: 6delete data 10
node 1: 12
node 2: 6
请按任意键继续. . .

3.2 insert_first - delete_node_v1 - 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
#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;// equality: head->next->prev = node;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;next_node->prev = prev_node;
}void delete_node_v1(const Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;
}void delete_node_v2(Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;node->next = node->next = NULL;
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != head){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}int main()
{// 头节点 (非头指针)Node root;// initialization// root.prev = &(root);// root.next = &(root);root.prev = root.next = &(root);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 != head){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);// insert 12node_array[12].data = 12;insert_first(&root, &(node_array[12]));printf("\ninsert data %d\n", 12);display(&root);/********************************* traverse function *********************************/{Node *head = &root;Node *ptr_node = head->prev;Node *tmp_node;while (ptr_node != head){tmp_node = ptr_node->prev;if (10 == ptr_node->data) {delete_node_v1(ptr_node);}ptr_node = tmp_node;}}/********************************* traverse function *********************************/printf("\ndelete 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: 2delete data 2
node 1: 10
node 2: 6insert data 12
node 1: 12
node 2: 10
node 3: 6delete data 10
node 1: 12
node 2: 6
请按任意键继续. . .

3.3 insert_first - delete_node_v1 - display_v1

//============================================================================
// 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;// equality: head->next->prev = node;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;next_node->prev = prev_node;
}void delete_node_v1(const Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;
}void delete_node_v2(Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;node->next = node->next = NULL;
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != head){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}void display_v1(const Node *head)
{int n = 1;Node *node = head->prev;while (node != head){printf("node %d: %d\n", n, node->data);++n;node = node->prev;}
}int main()
{// 头节点 (非头指针)Node root;// initialization// root.prev = &(root);// root.next = &(root);root.prev = root.next = &(root);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_v1(&root);// delete 4delete_node_v1(&(node_array[4]));printf("\ndelete data %d\n", 4);display_v1(&root);// delete 0delete_node_v1(&(node_array[0]));printf("\ndelete data %d\n", 0);display_v1(&root);// delete 8delete_node_v1(&(node_array[8]));printf("\ndelete data %d\n", 8);display_v1(&root);// insert 10node_array[10].data = 10;insert_first(&root, &(node_array[10]));printf("\ninsert data %d\n", 10);display_v1(&root);/********************************* traverse function *********************************/{Node *head = &root;Node *ptr_node = head->next;Node *tmp_node;while (ptr_node != head){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_v1(&root);// insert 12node_array[12].data = 12;insert_first(&root, &(node_array[12]));printf("\ninsert data %d\n", 12);display_v1(&root);/********************************* traverse function *********************************/{Node *head = &root;Node *ptr_node = head->prev;Node *tmp_node;while (ptr_node != head){tmp_node = ptr_node->prev;if (10 == ptr_node->data) {delete_node_v1(ptr_node);}ptr_node = tmp_node;}}/********************************* traverse function *********************************/printf("\ndelete data %d\n", 10);display_v1(&root);return 0;
}
node 1: 0
node 2: 2
node 3: 4
node 4: 6
node 5: 8delete data 4
node 1: 0
node 2: 2
node 3: 6
node 4: 8delete data 0
node 1: 2
node 2: 6
node 3: 8delete data 8
node 1: 2
node 2: 6insert data 10
node 1: 2
node 2: 6
node 3: 10delete data 2
node 1: 6
node 2: 10insert data 12
node 1: 6
node 2: 10
node 3: 12delete data 10
node 1: 6
node 2: 12
请按任意键继续. . .

3.4 在任意节点之后插入新节点

//============================================================================
// 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;// equality: head->next->prev = node;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;next_node->prev = prev_node;
}void delete_node_v1(const Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;
}void delete_node_v2(Node *node)
{// current node - nodenode->prev->next = node->next;node->next->prev = node->prev;node->next = node->next = NULL;
}void display(const Node *head)
{int n = 1;Node *node = head->next;while (node != head){printf("node %d: %d\n", n, node->data);++n;node = node->next;}
}void display_v1(const Node *head)
{int n = 1;Node *node = head->prev;while (node != head){printf("node %d: %d\n", n, node->data);++n;node = node->prev;}
}int main()
{// 头节点 (非头指针)Node root;// initialization// root.prev = &(root);// root.next = &(root);root.prev = root.next = &(root);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);// 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->prev;Node *tmp_node;while (ptr_node != head){tmp_node = ptr_node->prev;if (8 == ptr_node->data) {// insert 24node_array[24].data = 24;insert_first(ptr_node, &(node_array[24]));}ptr_node = tmp_node;}}/********************************* traverse function *********************************/printf("\ninsert data %d\n", 24);display(&root);return 0;
}
node 1: 8
node 2: 6
node 3: 4
node 4: 2
node 5: 0insert data 10
node 1: 10
node 2: 8
node 3: 6
node 4: 4
node 5: 2
node 6: 0insert data 24
node 1: 10
node 2: 8
node 3: 24
node 4: 6
node 5: 4
node 6: 2
node 7: 0
请按任意键继续. . .

References

https://www.cnblogs.com/skywang12345/p/3561803.html
https://www.alphacodingskills.com/ds/circular-doubly-linked-list.php

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

  1. 双向循环链表:鸿蒙轻内核中数据的“驿站”

    本文分享自华为云社区<鸿蒙轻内核M核源码分析系列二 数据结构-双向循环链表>,原文作者:zhushy . 在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用. ...

  2. 【数据结构】双向链表(带头双向循环链表)——超详细代码

    文章目录 1. 双链表 1.1 前言 1.2 带头双向循环链表 2. 带头双向循环链表的实现 2.1 双向链表的定义声明 2.2 双向链表的初始化 2.3 释放双向链表 2.4 打印双向链表 2.5 ...

  3. 链表、头指针、头结点

    图1为线性表(ZHAO, QIAN, SUN, LI, ZHOU, WU, ZHENG, WANG)的逻辑状态.头指针 指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置.同时,由于最后一个 ...

  4. 《恋上数据结构第1季》单向循环链表、双向循环链表以及约瑟夫环问题

    循环链表(CircleList) 链表的接口设计 单向循环链表 单向循环链表完整源码 双向循环链表 双向循环链表完整源码 双向循环链表解决约瑟夫环问题 如何发挥循环链表的最大威力? 静态链表 数据结构 ...

  5. 【循环链表】数据结构——单向循环链表和双向循环链表操作笔记

    循环链表 一.单向循环链表 1.单向循环链表的节点 2.单向循环链表的结构 二.双向循环链表 1.双向循环链表示意图 2.双向循环链表节点设计 3.双向循环链表的一般性结构 4.双向循环链表头插法插入 ...

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

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

  7. 双向循环链表的插入与删除

    关于解释部分不再多说了,网上资料很多,下面就介绍具体的实现吧 //双向循环链表的插入与删除 typedef struct node{     int data;     struct node *pr ...

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

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

  9. python 双向循环链表实现_python实现双向循环链表基本结构及其基本方法

    双向循环链表是在双向链表的基础上发展的,双向链表的最后一个节点指向起始节点,起始节点的上一个节点指向最后一个节点,就得到双向循环链表. 双向循环链表比双向链表具有更多的优势,节点的增加和删除有很多优化 ...

  10. 【数据结构】带头节点双向循环链表

    目录 顺序表和链表的区别 带头双向循环链表分析 带头双向循环链表结构: 创建一个节点 哨兵位头节点 打印链表中的值 在pos前插入 删除pos位置的节点 尾插 尾删 头插: 头删 链表元素查找 总代码 ...

最新文章

  1. 敏捷软件开发实践——估算与计划02
  2. mysqldatareader获取整行数据给datarow_C# sqladapter 与sqldataReader
  3. 关于node.js和C交互的方法
  4. python方法名加__学习python中__name__方法使用
  5. cdr怎么做文字路径_整理128张图片,告诉你文字少的PPT应该怎么做?
  6. 宿命传说2之女神召唤java_热血传奇:传奇那些传说中的秘密,连骨灰级的玩家都未必知道...
  7. 面试题(Qt + 函数指针)
  8. Ubuntu 14.04 安装Octave
  9. 神经计算棒python_神经计算棒-Movidius™ Neural Compute SDK Python API
  10. 石墨文档产品,用Websocket 百万长连接技术的秘密
  11. 2008年度中国最佳MBA排行榜
  12. csdn中Markdown编辑器的使用
  13. C++——NOIP模拟题——葫芦
  14. 已成功拿下字节、腾讯、脉脉offer,这原因我服了
  15. 最全Markdown教程
  16. 小米8无法开启位置服务器,小米8 WIFI 蓝牙打不开 GPS无法使用
  17. linux创建分区大小命令,Linux使用fdisk创建分区详解
  18. html dom节点源码,HTML DOM HTML DOM 节点 - 闪电教程JSRUN
  19. 导图解文 从梦想到财富(02)你拥有最宝贵的财富是什么?
  20. 中忻嘉业:因抖音ccr指标异常的惩罚

热门文章

  1. openwrt安装GPS设备,使用GPSD获取GPS信息
  2. mdf文件和ldf文件是什么?
  3. 微信支付--预支付(统一下单)
  4. 斯特林公式 (Stirling公式)
  5. python灰色关联度分析代码_GRA灰色关联度分析学习 附python代码
  6. qt超级马里奥_探索《超级马里奥》 35周年选集
  7. 计算机基础操作知识带答案,计算机应用基础知识试题带答案
  8. 百度地图API详解之驾车导航
  9. Elasticsearch创建索引别名
  10. @Lazy注解简单理解