双循环链表

一.双链表的结构和优势

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

        与单链表不同的是,双向循环链表有两个指针,一个指向上一个节点,一个指向下一个节点.双向链表有一个头节点,这个节点不存放数据,而是作为哨兵位,指向链表尾和头。与单链表相比,双链表具有更多的灵活性,因为可以从任意一个节点开始向前或向后遍历整个链表。

相比于单链表

优点:

  1. 双向遍历: 可以从头到尾或者从尾到头遍历链表。
  2. 插入和删除更灵活: 相对于单链表,插入和删除节点时不需要像单链表那样追溯到前一个节点,可以更方便地进行操作。

缺点:

  1. 占用更多空间: 每个节点需要额外存储两个指针,因此相对于单链表来说,双链表占用更多的内存空间。
  2. 实现复杂性: 对于某些简单的应用场景,双链表可能会显得过于复杂。

二.双链表操作

1.初始化

ListNode* ListCreate()
{
	ListNode* head = (ListNode*)malloc(sizeof(ListNode));
	if (head == NULL)
	{
		perror("malloc;");
		return NULL;
	}
	head->data = 0;
	head->next = head;
	head->prev = head;
	return head;
}

创建一个头节点.使它的头和尾都指向自己,返回头节点

2.销毁

void ListDestory(ListNode* pHead)
{
	assert(pHead);
	ListNode* pHeadnext = pHead->next;
	while (pHeadnext != pHead)
	{
		ListNode* p = pHeadnext;
		pHeadnext = pHeadnext->next;
		free(p);
	}
	free(pHead);
}

遍历整个链表,释放各个节点,最后将头节点释放,

3.尾插

void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* newNode = NodeCreate(x);
	newNode->prev = pHead->prev;
	pHead->prev->next = newNode;
	newNode->next = pHead;
	pHead->prev = newNode;
}

相比与单链表,双链表对于尾插更方便,head的prev就是尾节点,然后改变指针指向即可

4.头插

void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* newNode = NodeCreate(x);
	ListNode* pHeadnext = pHead->next;
	pHead->next = newNode;
	newNode->prev = pHead;
	newNode->next = pHeadnext;
	pHeadnext->prev = newNode;
}

找到头的下一个节点,改变前后节点的prev和next即可

5.尾删

void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	ListNode* pHeadprev = pHead->prev;
	if (pHeadprev == pHead)
		return;
	pHead->prev = pHeadprev->prev;
	pHeadprev->prev->next = pHead;
	free(pHeadprev);
	pHeadprev = NULL;
}

6.头删

void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	ListNode* pHeadnext = pHead->next;
	if (pHeadnext == pHead)
		return;
	pHead->next = pHeadnext->next;
	pHeadnext->next->prev = pHead;
	free(pHeadnext);
	pHeadnext = NULL;
}

7.查找

ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* pHeadnext = pHead->next;
	while (pHeadnext != pHead)
	{
		if (pHeadnext->data == x)
			return pHeadnext;
		pHeadnext = pHeadnext->next;
	}
	return NULL;
}

遍历链表,如果找到就返回这个节点的地址,找不到返回NULL

8.插入

void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* posprev = pos->prev;
	ListNode* newNode = NodeCreate(x);
	posprev->next = newNode;
	newNode->prev = posprev;
	pos->prev = newNode;
	newNode->next = pos;
}

在pos节点前面插入,与尾插类似

9. 删除指定节点

void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* posprev = pos->prev;
	posprev->next = pos->next;
	pos->next->prev = posprev;
	free(pos);
	pos = NULL;
}

更改这个节点的前后两个节点的next和prev指向即可

  • 11
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值