带头节点 (非头指针) 双向循环链表 (doubly linked list)
带头节点 (非头指针) 双向循环链表 (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)相关推荐
- 双向循环链表:鸿蒙轻内核中数据的“驿站”
本文分享自华为云社区<鸿蒙轻内核M核源码分析系列二 数据结构-双向循环链表>,原文作者:zhushy . 在学习OpenHarmony鸿蒙轻内核源代码的时候,常常会遇到一些数据结构的使用. ...
- 【数据结构】双向链表(带头双向循环链表)——超详细代码
文章目录 1. 双链表 1.1 前言 1.2 带头双向循环链表 2. 带头双向循环链表的实现 2.1 双向链表的定义声明 2.2 双向链表的初始化 2.3 释放双向链表 2.4 打印双向链表 2.5 ...
- 链表、头指针、头结点
图1为线性表(ZHAO, QIAN, SUN, LI, ZHOU, WU, ZHENG, WANG)的逻辑状态.头指针 指示链表中第一个结点(即第一个数据元素的存储映像)的存储位置.同时,由于最后一个 ...
- 《恋上数据结构第1季》单向循环链表、双向循环链表以及约瑟夫环问题
循环链表(CircleList) 链表的接口设计 单向循环链表 单向循环链表完整源码 双向循环链表 双向循环链表完整源码 双向循环链表解决约瑟夫环问题 如何发挥循环链表的最大威力? 静态链表 数据结构 ...
- 【循环链表】数据结构——单向循环链表和双向循环链表操作笔记
循环链表 一.单向循环链表 1.单向循环链表的节点 2.单向循环链表的结构 二.双向循环链表 1.双向循环链表示意图 2.双向循环链表节点设计 3.双向循环链表的一般性结构 4.双向循环链表头插法插入 ...
- 【头结点】【头指针】【首元结点】
2022 -1-14 文章目录 2022 -1-14 1. 定义: 2. 哨兵(头结点) 3. 有无头结点的单链表的创建 3.1 有头结点 3.1.1 头插法: 3.1.2 尾插法: 3.2 无头结点 ...
- 双向循环链表的插入与删除
关于解释部分不再多说了,网上资料很多,下面就介绍具体的实现吧 //双向循环链表的插入与删除 typedef struct node{ int data; struct node *pr ...
- c语言链表不带头节点的排序,不带头结点的单向链表排序——插入排序(C语言)...
LinkList* LinkListInsertSort(LinkList* pHead) { LinkList *pFirst = (LinkList *)NULL; /* 原链表剩下未排序节点的头 ...
- python 双向循环链表实现_python实现双向循环链表基本结构及其基本方法
双向循环链表是在双向链表的基础上发展的,双向链表的最后一个节点指向起始节点,起始节点的上一个节点指向最后一个节点,就得到双向循环链表. 双向循环链表比双向链表具有更多的优势,节点的增加和删除有很多优化 ...
- 【数据结构】带头节点双向循环链表
目录 顺序表和链表的区别 带头双向循环链表分析 带头双向循环链表结构: 创建一个节点 哨兵位头节点 打印链表中的值 在pos前插入 删除pos位置的节点 尾插 尾删 头插: 头删 链表元素查找 总代码 ...
最新文章
- 敏捷软件开发实践——估算与计划02
- mysqldatareader获取整行数据给datarow_C# sqladapter 与sqldataReader
- 关于node.js和C交互的方法
- python方法名加__学习python中__name__方法使用
- cdr怎么做文字路径_整理128张图片,告诉你文字少的PPT应该怎么做?
- 宿命传说2之女神召唤java_热血传奇:传奇那些传说中的秘密,连骨灰级的玩家都未必知道...
- 面试题(Qt + 函数指针)
- Ubuntu 14.04 安装Octave
- 神经计算棒python_神经计算棒-Movidius™ Neural Compute SDK Python API
- 石墨文档产品,用Websocket 百万长连接技术的秘密
- 2008年度中国最佳MBA排行榜
- csdn中Markdown编辑器的使用
- C++——NOIP模拟题——葫芦
- 已成功拿下字节、腾讯、脉脉offer,这原因我服了
- 最全Markdown教程
- 小米8无法开启位置服务器,小米8 WIFI 蓝牙打不开 GPS无法使用
- linux创建分区大小命令,Linux使用fdisk创建分区详解
- html dom节点源码,HTML DOM HTML DOM 节点 - 闪电教程JSRUN
- 导图解文 从梦想到财富(02)你拥有最宝贵的财富是什么?
- 中忻嘉业:因抖音ccr指标异常的惩罚