双向循环链表讲解及实现

一.带头双向循环链表

带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个链表虽然结构复杂,但是使用代码实现以后会发现能带来很多优势.

二.实现

Lish.h中部分声明

typedef int LTDataType;
typedef struct ListNode
{
	struct ListNode* prev;
	struct ListNode* next;
	LTDataType data;
}ListNode;

prev为结点中的指向前一个结点的指针 , next 为指针中的指向后一个结点的指针 , data为结点中的数据

(1).动态申请一个结点

动态申请一个大小为sizeof(ListNode)的结点

// 动态申请一个结点
ListNode*BuyListNode(LTDataType x)
{
	ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
	if(newNode == NULL)
	{
		printf("分配内存失败\n");
		exit(-1);
	}
	newNode->prev = newNode->next = NULL;
	newNode->data = x;
	return newNode;
}

(2).创建头结点进行初始化

因为为带头的双向循环链表,因此初始化头结点时,头结点的prev,next指针都指向自已

// 创建头结点进行初始化
ListNode* ListInit()
{
	ListNode* plist = BuyListNode(0); // 头结点中的数据初始化为 0
	plist->prev = plist->next = plist;
	return plist;
}

(3).尾插

通过头结点的prev指针可以找到尾结点tail,tail->next指向待插入的结点,待插入结点的prev指针指向tail,头结点的prev指针指向待插入结点,待插入结点的next指向头结点

// 尾插
void ListPushBack(ListNode* plist,LTDataType x)
{
	assert(plist);
	ListNode* newNode = BuyListNode(x);
	ListNode* tail = plist->prev;
	tail->next = newNode;
	newNode->prev = tail;
	newNode->next = plist;
	plist->prev = newNode;
}

(4).尾删

通过头结点的prev指针找到尾结点tail,通过tail的prev指针找到 tailPrev结点

要使tailPrev成为尾结点,将tailPrev结点和plist头结点连接到一起

// 尾删
void ListPopBack(ListNode* plist)
{
	assert(plist);
	assert(plist->next != plist);
	ListNode* tail = plist->prev;
	ListNode* tailPrev = tail->prev;
	tailPrev->next = plist;
	plsit->prev = tailPrev;
	free(tail);
	tail = NULL;
}

(5).头插

动态申请一个结点newNode,通过plist->next找到当前的第一个结点(first),newNode结点要插入到plist头结点和first结点之间

// 头插
void ListPushFront(ListNode* plist,LTDataType x)
{
	assert(plist);
	ListNode* newNode = BuyListNode(x);
	ListNode* first = plist->next;
	plist->next = newNode;
	newNode->prev = plist;
	newNode->next = first;
	first->prev = newNode;
}

(6).头删

通过plist->next找到第一个结点(first),first->next找到第二个结点(second),将plist头结点和second结点连接到一起,释放掉第一个结点(first)

// 头删
void ListPopFront(ListNode* plist)
{
	assert(plist);
	assert(plist->next != plist);
	ListNode* first = plist->next;
	ListNode* second = first->next;
	plist->next = second;
	second->prev = plist;
	free(first);
	first = NULL;
}

(7).查找元素

遍历一次链表,终止条件为 cur != plist ,因为 cur = plist 说明已经循环了一遍

// 查找
ListNode* ListFind(ListNode* plist, LTDataType x)
{
	assert(plist);
	ListNode* cur = plist->next;
	while (cur != plist)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}

(8).在pos位置之前进行插入

动态申请一个结点 ,找到pos位置的前一个结点(posPrev),将pos,posPrev,newNode结点连接到一起

// 在pos位置前插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* newNode = BuyListNode(x);
	ListNode* posPrev = pos->prev;
	posPrev->next = newNode;
	newNode->prev = posPrev;
	newNode->next = pos;
	pos->prev = newNode;
}

(9).删除pos位置的结点

找到pos的前一个结点(posPrev)和后一个结点(posNext),将posPrev,posNext结点连接到一起,删除掉pos结点

// 删除pos位置的结点
void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* PosPrev = pos->prev;
	ListNode* PosNext = pos->next;
	PosPrev->next = PosNext;
	PosNext->prev = PosPrev;
	free(pos);
	pos = NULL;
}

(10).打印数据

遍历一次链表,终止条件为 cur != plist ,因为 cur = plist 说明已经循环了一遍

// 打印
void Listprint(ListNode* plist)
{
	assert(plist);
	ListNode* cur = plist->next;
	while (cur != plist)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

三.代码实现

List.h文件

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int LTDataType;
typedef struct ListNode
{
	struct ListNode* prev;
	struct ListNode* next;
	LTDataType data;
}ListNode;
// 初始化创建头结点
ListNode* ListInit();
// 动态申请一个结点
ListNode* BuyListNode(LTDataType x);
// 打印
void Listprint(ListNode* plist);
// 尾插
void ListPushBack(ListNode* plist, LTDataType x);
// 尾删
void ListPopBack(ListNode* plist);
// 头插
void ListPushFront(ListNode* plist, LTDataType x);
// 头删
void ListPopFront(ListNode* plist);
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x);
// 在pos前插入
void ListInsert(ListNode* pos, LTDataType x);
// 删除pos位置的结点
void ListErase(ListNode* pos);

Lish.c文件

#include"List.h"
// 初始化创建头结点
ListNode* ListInit()
{
	ListNode* phead = BuyListNode(0);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}
// 动态申请一个结点
ListNode* BuyListNode(LTDataType x)
{
	ListNode* NewNode = (ListNode*)malloc(sizeof(ListNode));
	if (NewNode == NULL)
	{
		printf("分配内存失败\n");
		exit(-1);
	}
	NewNode->prev = NewNode->next = NULL;
	NewNode->data = x;
	return NewNode;
}
// 打印
void Listprint(ListNode* plist)
{
	assert(plist);
	ListNode* cur = plist->next;
	while (cur != plist)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}
// 尾插
void ListPushBack(ListNode* plist, LTDataType x)
{
	assert(plist);
	ListNode* NewNode = BuyListNode(x);
	ListNode* tail = plist->prev;
	tail->next = NewNode;
	NewNode->prev = tail;
	plist->prev = NewNode;
	NewNode->next = plist;
}
// 尾删
void ListPopBack(ListNode* plist)
{
	assert(plist);
	assert(plist->next != plist);
	ListNode* tail = plist->prev;
	ListNode* tail_prev = tail->prev;
	tail_prev->next = plist;
	plist->prev = tail_prev;
	free(tail);
	tail = NULL;
}
// 头插
void ListPushFront(ListNode* plist, LTDataType x)
{
	assert(plist);
	ListNode* NewNode = BuyListNode(x);
	ListNode* first = plist->next;
	plist->next = NewNode;
	NewNode->prev = plist;
	NewNode->next = first;
	first->prev = NewNode;
}
// 头删
void ListPopFront(ListNode* plist)
{
	assert(plist);
	assert(plist->next != plist);
	ListNode* first = plist->next;
	ListNode* second = first->next;
	plist->next = second;
	second->prev = plist;
	free(first);
	first = NULL;
}
// 查找
ListNode* ListFind(ListNode* plist, LTDataType x)
{
	assert(plist);
	ListNode* cur = plist->next;
	while (cur != plist)
	{
		if (cur->data == x)
			return cur;
		cur = cur->next;
	}
	return NULL;
}
// 在pos位置前插入
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* NewNode = BuyListNode(x);
	ListNode* PosPrev = pos->prev;
	PosPrev->next = NewNode;
	NewNode->prev = PosPrev;
	NewNode->next = pos;
	pos->prev = NewNode;
}
// 删除pos位置的结点
void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* PosPrev = pos->prev;
	ListNode* PosNext = pos->next;
	PosPrev->next = PosNext;
	PosNext->prev = PosPrev;
	free(pos);
	pos = NULL;
}

TestLish.c文件

#include"List.h"
void TestList01()
{
	ListNode* plist = ListInit();
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	ListPushBack(plist, 4);
	Listprint(plist);

	ListPopBack(plist);
	ListPopBack(plist);
	ListPopBack(plist);
	ListPopBack(plist);
	// ListPopBack(plist);
	Listprint(plist);

	ListPushFront(plist, 1);
	ListPushFront(plist, 2);
	ListPushFront(plist, 3);
	ListPushFront(plist, 4);
	Listprint(plist);

	ListPopFront(plist);
	ListPopFront(plist);
	ListPopFront(plist);
	ListPopFront(plist);
	// ListPopFront(plist);
	Listprint(plist);
}
void TestList02()
{
	ListNode* plist = ListInit();
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	ListPushBack(plist, 4);

	ListNode* pos = ListFind(plist, 3);
	ListInsert(pos, 30);
	Listprint(plist);
	ListErase(pos);
	Listprint(plist);

}
int main()
{
	TestList01();
	TestList02();
}
  • 38
    点赞
  • 106
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
双向循环链表是一种常用的数据结构之一,可以在链表中进行快速的插入、删除和查找操作。以下是一种简单的C语言实现双向循环链表的代码: ``` #include <stdio.h> #include <stdlib.h> struct node { int data; struct node *prev; struct node *next; }; struct node *createNode(int data) { struct node *newNode = (struct node*)malloc(sizeof(struct node)); newNode->data = data; newNode->prev = NULL; newNode->next = NULL; return newNode; } void insertAtBegin(struct node **head, int data) { struct node *newNode = createNode(data); if (*head == NULL) { *head = newNode; (*head)->next = *head; (*head)->prev = *head; } else { struct node *last = (*head)->prev; newNode->next = *head; newNode->prev = last; last->next = newNode; (*head)->prev = newNode; *head = newNode; } } void insertAtEnd(struct node **head, int data) { struct node *newNode = createNode(data); if (*head == NULL) { *head = newNode; (*head)->next = *head; (*head)->prev = *head; } else { struct node *last = (*head)->prev; newNode->prev = last; newNode->next = *head; last->next = newNode; (*head)->prev = newNode; } } void deleteNode(struct node **head, int data) { if (*head == NULL) { printf("List is empty.\n"); return; } struct node *cur = *head; struct node *prev = NULL; while (cur->data != data && cur->next != *head) { prev = cur; cur = cur->next; } if (cur->data != data) { printf("%d not found in list.\n", data); return; } if (cur == *head && cur->next == *head) { *head = NULL; free(cur); return; } if (cur == *head) { *head = cur->next; } struct node *next = cur->next; prev->next = next; next->prev = prev; free(cur); } void displayList(struct node *head) { if (head == NULL) { printf("List is empty.\n"); return; } printf("List: "); struct node *cur = head; do { printf("%d ", cur->data); cur = cur->next; } while (cur != head); printf("\n"); } int main() { struct node *head = NULL; insertAtBegin(&head, 10); insertAtBegin(&head, 20); insertAtEnd(&head, 30); insertAtEnd(&head, 40); displayList(head); deleteNode(&head, 20); deleteNode(&head, 50); displayList(head); return 0; } ``` 在这个例子中,我们使用了一个结构体来存储每个节点的数据和指向前一个和后一个节点的指针。我们还定义了一些操作函数,如创建新节点、在链表头部和尾部插入新节点、删除节点和显示链表等。在主函数中,我们创建了一个双向循环链表并进行了一些操作,最后输出链表的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值