带头结点的双向循环链表


带头结点的双向循环链表


程序代码如下:


Dlist.h

//Dlist.h

typedef int DataType;

typedef struct DListNode
{
	struct DListNode* _pNext;
	struct DListNode* _pPre;
	DataType _data;
}DListNode;


// 初始化 
void DListInit(DListNode** pHead);

// 双向链表的尾插 
void DListPushBack(DListNode* pHead, DataType data);

// 双向链表的尾删 
void DListPopBack(DListNode* pHead);

// 双向链表的头插 
void DListPushFront(DListNode* pHead, DataType data);

// 双向链表的头删 
void DListPopFront(DListNode* pHead);

// 任意位置插入 
void DListInsert(DListNode* pos, DataType data);

// 任意位置删除 
void DListErase(DListNode* pos);

// 查找值为data的结点 
DListNode* DListFind(DListNode* pHead, DataType data);

// 销毁 
void DListDestroy(DListNode** pHead);

//打印
void PrintDlist(DListNode* pHead);

Dlist.c

//Dlist.c
#include <stdio.h>
#include <assert.h>
#include "Dlist.h"

// 初始化 
void DListInit(DListNode** pHead)
{
	assert(pHead);

	(*pHead) = (DListNode*)malloc(sizeof(DListNode));
	(*pHead)->_pNext = (*pHead);
	(*pHead)->_pPre = (*pHead);
	(*pHead)->_data = 0;
}

DListNode* BuyNode(DataType d)
{
	DListNode* newNode = (DListNode*)malloc(sizeof(DListNode));

	if (NULL == newNode)
	{
		assert(0);
		return NULL;
	}

	newNode->_data = d;
	newNode->_pNext = NULL;
	newNode->_pPre = NULL;
	return newNode;
}

// 双向链表的尾插 
void DListPushBack(DListNode* pHead, DataType data)
{
	DListNode* newNode = BuyNode(data);
	DListNode* tail = pHead;
	while (pHead != tail->_pNext)
	{
		tail = tail->_pNext;
	}
	tail->_pNext = newNode;
	newNode->_pNext = pHead;
	pHead->_pPre = newNode;
	newNode->_pPre = tail;
}

// 双向链表的尾删 
void DListPopBack(DListNode* pHead)
{
	DListNode* tail = pHead;
	if (pHead == pHead->_pNext)
		return;
	while (pHead != tail->_pNext)
	{
		tail = tail->_pNext;
	}
	tail->_pNext = NULL;
	tail->_pPre->_pNext = pHead;
	tail->_pPre = NULL;
	free(tail);
	tail = NULL;
}

// 双向链表的头插 
void DListPushFront(DListNode* pHead, DataType data)
{
	DListNode* newNode = BuyNode(data);
	pHead->_pNext->_pPre = newNode;
	newNode->_pNext = pHead->_pNext;
	pHead->_pNext = newNode;
	newNode->_pPre = pHead;
}

// 双向链表的头删 
void DListPopFront(DListNode* pHead)
{
	DListNode* temp = NULL;
	if (pHead == pHead->_pNext)
		return;
	temp = pHead->_pNext;
	pHead->_pNext->_pPre = NULL;
	pHead->_pNext = pHead->_pNext->_pNext;
	pHead->_pNext->_pPre->_pNext = NULL;
	pHead->_pNext->_pPre = pHead;
	free(temp);
	temp = NULL;
}

// 任意位置插入 
void DListInsert(DListNode* pos, DataType data)
{
	if (pos == pos->_pNext)
	{
		DListPushFront(pos, data);
		return;
	}
	DListNode* newNode = BuyNode(data);
	pos->_pPre->_pNext = newNode;
	newNode->_pPre = pos->_pPre;
	newNode->_pNext = pos;
	pos->_pPre = newNode;
}

// 任意位置删除 
void DListErase(DListNode* pos)
{
	if (pos == pos->_pNext)
		return;
	pos->_pPre->_pNext = pos->_pNext;
	pos->_pNext->_pPre = pos->_pPre;
	pos->_pPre = NULL;
	pos->_pNext = NULL;
	free(pos);
	pos == NULL;
}

// 查找值为data的结点 
DListNode* DListFind(DListNode* pHead, DataType data)
{
	DListNode* cur = pHead;
	while (pHead != cur->_pNext)
	{
		if (data == cur->_data)
			return cur;
		cur = cur->_pNext;
	}
	return NULL;
}

// 销毁 
void DListDestroy(DListNode** pHead)
{
	assert(pHead);
	
	DListNode* cur1 = (*pHead)->_pNext;
	DListNode* cur2 = NULL;
	while ((*pHead) != cur1)
	{
		cur2 = cur1->_pNext;
		free(cur1);
		cur1 = cur2;
	}
	free((*pHead));
	(*pHead) = NULL;
}

//打印
void PrintDlist(DListNode* pHead)
{
	DListNode* cur = pHead;
	if (NULL == pHead)
	{
		printf("NULL\n");
		return;
	}
	while (pHead != cur->_pNext)
	{
		printf("%d-->", cur->_data);
		cur = cur->_pNext;
	}
	printf("%d-->%d\n", cur->_data,pHead->_data);
}

test.c

//test.c
#include <stdio.h>
#include <stdlib.h>
#include "Dlist.h"

Test()
{
	DListNode* pHead;
	// 初始化
	DListInit(&pHead);
	PrintDlist(pHead);

	// 双向链表的尾插
	DListPushBack(pHead, 6);
	DListPushBack(pHead, 7);
	DListPushBack(pHead, 8);
	DListPushBack(pHead, 9);
	DListPushBack(pHead, 10);
	PrintDlist(pHead);

	// 双向链表的尾删 
	DListPopBack(pHead);
	PrintDlist(pHead);

	// 双向链表的头插 
	DListPushFront(pHead, 4);
	DListPushFront(pHead, 3);
	DListPushFront(pHead, 2);
	DListPushFront(pHead, 1);
	DListPushFront(pHead, 1);
	PrintDlist(pHead);

	// 双向链表的头删 
	DListPopFront(pHead);
	PrintDlist(pHead);

	// 查找值为6的结点 
	DListNode* pos = DListFind(pHead, 6);

	// 任意位置插入 
	DListInsert(pos, 5);
	PrintDlist(pHead);

	// 查找值为7的结点
	pos = DListFind(pHead, 7);

	// 任意位置删除 
	DListErase(pos);
	PrintDlist(pHead);

	// 销毁 
	DListDestroy(&pHead);
	PrintDlist(pHead);
}

int main()
{
	Test();
	system("pause");
	return 0;
}

程序运行结果如下:


在这里插入图片描述

### 带头节点双向循环链表的操作 #### 尾部插入操作 在带头节点的双向循环链表中执行尾部插入操作时,新节点会被添加到链表的最后一位置,并保持链表的环形特性。具体来说,在完成插入之后,原先的最后一个节点应当指向新的节点,而新的节点则应指向前一个最后节点以及头部节点。 ```c void insertAtTail(Node **head, int data) { Node *newNode = (Node *)malloc(sizeof(Node)); newNode->data = data; newNode->next = *head; // 新节点的 next 指向 head newNode->prev = (*head)->prev; ((*head)->prev)->next = newNode; // 当前最后一个节点的 next 指向 new node (*head)->prev = newNode; // 更新 head 的 prev 属性为新加入的节点 } ``` 此函数接收两个参数:一个是双指针 `*head` 表示链表的第一个有效元素之前的哨兵节点;另一个是要被插入的新数据项 `data`[^2]。 #### 头部删除操作 当从带头节点的双向循环链表移除首个真实数据节点(即紧跟在头节点后的那个),需要调整前后连接关系来维持整个列表的一致性和闭合性质。如果仅剩下一个代表性的虚拟头节点,则无需做任何改变因为这表示当前为空状态下的正常情形。 ```c int deleteFromHead(Node **head) { if((*head)->next == *head) { // 如果只有头结点存在 return -1; // 返回错误码表明无法删除 } Node *temp = (*head)->next; // 获取要删除的真实首节点 int removedData = temp->data; // 记录即将被释放内存中的数值 (*head)->next = temp->next; // 修改原头结点的 next 成员使其跳过待删节点直连至下一位成员 (temp->next)->prev = *head; // 后继者的 prev 应该更新回真正的头结点而非已被标记为临时变量的对象上 free(temp); // 解放已不再使用的空间资源 return removedData; // 返回成功移除的数据值 } ``` 上述代码片段展示了如何安全有效地处理带头节点双向循环链表内的基本增减动作,确保了逻辑上的连续性与物理层面的有效管理[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值