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

本文介绍双向循环链表的基本概念及其实现细节,包括如何在链表中插入和删除节点,并提供具体的C语言代码示例。

带头节点 (非头指针) 双向循环链表 (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 - node

	prev_node->next = next_node;
	next_node->prev = prev_node;
}

void delete_node_v1(const Node *node)
{
	// current node - node

	node->prev->next = node->next;
	node->next->prev = node->prev;
}

void delete_node_v2(Node *node)
{
	// current node - node

	node->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 0
	node_array[0].data = 0;
	insert_first(&root, &(node_array[0]));

	// insert 2
	node_array[2].data = 2;
	insert_first(&root, &(node_array[2]));

	// insert 4
	node_array[4].data = 4;
	insert_first(&root, &(node_array[4]));

	// insert 6
	node_array[6].data = 6;
	insert_first(&root, &(node_array[6]));

	// insert 8
	node_array[8].data = 8;
	insert_first(&root, &(node_array[8]));

	display(&root);

	// delete 4
	delete_node_v1(&(node_array[4]));
	printf("\ndelete data %d\n", 4);
	display(&root);

	// delete 0
	delete_node_v1(&(node_array[0]));
	printf("\ndelete data %d\n", 0);
	display(&root);

	// delete 8
	delete_node_v1(&(node_array[8]));
	printf("\ndelete data %d\n", 8);
	display(&root);

	// insert 10
	node_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 12
	node_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: 0

delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0

delete data 0
node 1: 8
node 2: 6
node 3: 2

delete data 8
node 1: 6
node 2: 2

insert data 10
node 1: 10
node 2: 6
node 3: 2

delete data 2
node 1: 10
node 2: 6

insert data 12
node 1: 12
node 2: 10
node 3: 6

delete 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 - node

	prev_node->next = next_node;
	next_node->prev = prev_node;
}

void delete_node_v1(const Node *node)
{
	// current node - node

	node->prev->next = node->next;
	node->next->prev = node->prev;
}

void delete_node_v2(Node *node)
{
	// current node - node

	node->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 0
	node_array[0].data = 0;
	insert_first(&root, &(node_array[0]));

	// insert 2
	node_array[2].data = 2;
	insert_first(&root, &(node_array[2]));

	// insert 4
	node_array[4].data = 4;
	insert_first(&root, &(node_array[4]));

	// insert 6
	node_array[6].data = 6;
	insert_first(&root, &(node_array[6]));

	// insert 8
	node_array[8].data = 8;
	insert_first(&root, &(node_array[8]));

	display(&root);

	// delete 4
	delete_node_v1(&(node_array[4]));
	printf("\ndelete data %d\n", 4);
	display(&root);

	// delete 0
	delete_node_v1(&(node_array[0]));
	printf("\ndelete data %d\n", 0);
	display(&root);

	// delete 8
	delete_node_v1(&(node_array[8]));
	printf("\ndelete data %d\n", 8);
	display(&root);

	// insert 10
	node_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 12
	node_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: 0

delete data 4
node 1: 8
node 2: 6
node 3: 2
node 4: 0

delete data 0
node 1: 8
node 2: 6
node 3: 2

delete data 8
node 1: 6
node 2: 2

insert data 10
node 1: 10
node 2: 6
node 3: 2

delete data 2
node 1: 10
node 2: 6

insert data 12
node 1: 12
node 2: 10
node 3: 6

delete 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 - node

	prev_node->next = next_node;
	next_node->prev = prev_node;
}

void delete_node_v1(const Node *node)
{
	// current node - node

	node->prev->next = node->next;
	node->next->prev = node->prev;
}

void delete_node_v2(Node *node)
{
	// current node - node

	node->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 0
	node_array[0].data = 0;
	insert_first(&root, &(node_array[0]));

	// insert 2
	node_array[2].data = 2;
	insert_first(&root, &(node_array[2]));

	// insert 4
	node_array[4].data = 4;
	insert_first(&root, &(node_array[4]));

	// insert 6
	node_array[6].data = 6;
	insert_first(&root, &(node_array[6]));

	// insert 8
	node_array[8].data = 8;
	insert_first(&root, &(node_array[8]));

	display_v1(&root);

	// delete 4
	delete_node_v1(&(node_array[4]));
	printf("\ndelete data %d\n", 4);
	display_v1(&root);

	// delete 0
	delete_node_v1(&(node_array[0]));
	printf("\ndelete data %d\n", 0);
	display_v1(&root);

	// delete 8
	delete_node_v1(&(node_array[8]));
	printf("\ndelete data %d\n", 8);
	display_v1(&root);

	// insert 10
	node_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 12
	node_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: 8

delete data 4
node 1: 0
node 2: 2
node 3: 6
node 4: 8

delete data 0
node 1: 2
node 2: 6
node 3: 8

delete data 8
node 1: 2
node 2: 6

insert data 10
node 1: 2
node 2: 6
node 3: 10

delete data 2
node 1: 6
node 2: 10

insert data 12
node 1: 6
node 2: 10
node 3: 12

delete 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 - node

	prev_node->next = next_node;
	next_node->prev = prev_node;
}

void delete_node_v1(const Node *node)
{
	// current node - node

	node->prev->next = node->next;
	node->next->prev = node->prev;
}

void delete_node_v2(Node *node)
{
	// current node - node

	node->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 0
	node_array[0].data = 0;
	insert_first(&root, &(node_array[0]));

	// insert 2
	node_array[2].data = 2;
	insert_first(&root, &(node_array[2]));

	// insert 4
	node_array[4].data = 4;
	insert_first(&root, &(node_array[4]));

	// insert 6
	node_array[6].data = 6;
	insert_first(&root, &(node_array[6]));

	// insert 8
	node_array[8].data = 8;
	insert_first(&root, &(node_array[8]));

	display(&root);

	// insert 10
	node_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 24
				node_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: 0

insert data 10
node 1: 10
node 2: 8
node 3: 6
node 4: 4
node 5: 2
node 6: 0

insert 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

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yongqiang Cheng

梦想不是浮躁,而是沉淀和积累。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值