双向循环链表

 优点:头插头删较方便时间复杂度都是O(1)。既能从前往后走又能从后往前走。

基本操作:

HDLoopList.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int LTDataType;

typedef struct ListNode
{
	LTDataType _data;
	struct ListNode* _next;
	struct ListNode* _prev;
}ListNode;

//开辟+初始化头节点
ListNode* AollocListNode(int x);
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos, ListNode* pHead);

1.开辟节点初始化

AollocListNode

ListNode* AollocListNode(LTDataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->_data = x;
	newnode->_next = newnode;
	newnode->_prev = newnode;
	return newnode;
}

 2.打印

需要用另外一个指针遍历链表,回到头结点的时候结束,如果使用pHead遍历会死循环。

ListPrint

void ListPrint(ListNode* pHead)
{
	ListNode* p = pHead->_next;//指向第一个节点
	while (p != pHead)
	{
		printf("%d->", p->_data);
		p = p->_next;
	}
	printf("NULL\n");

}

3.销毁

销毁链表,释放所有节点
循环中,先把除头节点外的所有节点删除,出了循环再删除头节点。
循环结束的条件和打印一样,当指向头节点的时候就结束

ListDestory

void ListDestory(ListNode* pHead)
{
	assert(pHead);
	while (pHead->_next != pHead)
	{
		struct ListNode* t = pHead->_next;//先记录要被释放的节点(第一个节点)
		pHead->_next = t->_next;
		t->_next->_prev = pHead;
		free(t);
	}
	free(pHead);
}

4.头插

ListPushFront

void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);

	ListNode* newnode = AollocListNode(x);
	newnode->_prev = pHead;
	newnode->_next = pHead->_next;

	pHead->_next->_prev = newnode;
	pHead->_next = newnode;
	//newnode->_next->_prev = newnode;
}

5.尾插

尾插:newnode的下一个指向的是头节点,一种是靠pHead,另一种是靠原最后一个节点去找头节点。组合方式很多不一一列举,不创建另外的变量记录原最后一个节点时,原最后一个节点改变指向之前,头节点的指向不能动。

ListPushBack

void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);

	ListNode* newnode = AollocListNode(x);
	newnode->_next = pHead;
	newnode->_prev = pHead->_prev;
	
	pHead->_prev->_next = newnode;//原最后一个节点 指向新节点
	pHead->_prev = newnode;//头节点指向新节点
}

6.头删

ListPopFront

void ListPopFront(ListNode* pHead)
{
	assert(pHead);
	ListNode* t = pHead->_next;//记录第一个节点
	pHead->_next = t->_next;
	t->_next->_prev = pHead;
	free(t);
}

7.尾删

记录最后一个节点,将倒数第二个节点和头结点互相连接再释放。

void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	ListNode* t = pHead->_prev;//记录最后一个节点
	t->_prev->_next = pHead;
	pHead->_prev = t->_prev;
	free(t);
}

8.找到对应值并返回地址

通过data找节点,再把节点的地址返回。通过这个pos执行下面两个操作。

ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* p = pHead->_next;//指向第一个节点
	while (p != pHead)
	{
		if (x == p->_data)
			return p;
		p = p->_next;
	}
	return NULL;
}

9.pos位置插入需要对pos判断一下不能为NULL

ListInsert

void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* newnode = AollocListNode(x);
	newnode->_next = pos;
	newnode->_prev = pos->_prev;

	pos->_prev->_next = newnode;
	pos->_prev = newnode;
}

10.删除pos前的节点

ListErase

void ListErase(ListNode* pos, ListNode* pHead)
{
	assert(pos);
	assert(pos->_prev != pHead);//判断pos前一个节点不为头节点

	ListNode* t = pos->_prev;//记录pos前一个节点
	t->_prev->_next = pos;
	pos->_prev = t->_prev;
	free(t);

}

总代码

HDLoopList.c

#include"HDLoopList.h"

//开辟+初始化节点
ListNode* AollocListNode(LTDataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->_data = x;
	newnode->_next = newnode;
	newnode->_prev = newnode;
	return newnode;
}
void ListPrint(ListNode* pHead)
{
	ListNode* p = pHead->_next;//指向第一个节点
	while (p != pHead)
	{
		printf("%d->", p->_data);
		p = p->_next;
	}
	printf("NULL\n");
}
void ListDestory(ListNode* pHead)
{
	assert(pHead);

	while (pHead->_next != pHead)
	{
		struct ListNode* t = pHead->_next;//先记录要被释放的节点(第一个节点)
		pHead->_next = t->_next;
		t->_next->_prev = pHead;
		free(t);
	}
	free(pHead);
}
void ListPushFront(ListNode* pHead, LTDataType x)
{
	assert(pHead);

	ListNode* newnode = AollocListNode(x);
	newnode->_prev = pHead;
	newnode->_next = pHead->_next;

	pHead->_next->_prev = newnode;
	pHead->_next = newnode;
	//newnode->_next->_prev = newnode;
}

//void ListPushFront(ListNode* pHead, LTDataType x)
//{
//	ListNode* newnode = AollocListNode(x);
//	ListNode* t = pHead->_next;
//
//	newnode->_next = t;
//	t->_prev = newnode;
//
//	pHead->_next = newnode;
//	newnode->_prev = pHead;
//}

void ListPushBack(ListNode* pHead, LTDataType x)
{
	assert(pHead);

	ListNode* newnode = AollocListNode(x);
	newnode->_next = pHead;
	newnode->_prev = pHead->_prev;
	
	pHead->_prev->_next = newnode;//原最后一个节点 指向新节点
	pHead->_prev = newnode;//头节点指向新节点
}
void ListPopFront(ListNode* pHead)
{
	assert(pHead);

	ListNode* t = pHead->_next;//记录第一个节点
	pHead->_next = t->_next;
	t->_next->_prev = pHead;
	free(t);
}
void ListPopBack(ListNode* pHead)
{
	assert(pHead);
	ListNode* t = pHead->_prev;//记录最后一个节点
	t->_prev->_next = pHead;
	pHead->_prev = t->_prev;
	free(t);
}

ListNode* ListFind(ListNode* pHead, LTDataType x)
{
	assert(pHead);
	ListNode* p = pHead->_next;//指向第一个节点
	while (p != pHead)
	{
		if (x == p->_data)
			return p;
		p = p->_next;
	}
	return NULL;
}
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* newnode = AollocListNode(x);
	newnode->_next = pos;
	newnode->_prev = pos->_prev;

	pos->_prev->_next = newnode;
	pos->_prev = newnode;
}
void ListErase(ListNode* pos, ListNode* pHead)
{
	assert(pos);
	assert(pos->_prev != pHead);//判断pos前一个节点不为头节点

	ListNode* t = pos->_prev;//记录pos前一个节点
	t->_prev->_next = pos;
	pos->_prev = t->_prev;
	free(t);

}

test.c

#include"HDLoopList.h"

int main()
{
	ListNode* phead = NULL;
	phead = AollocListNode(0);
	for (int i = 1; i < 4; i++)
	{
		//ListPushFront(phead, i);
		ListPushBack(phead, i);
	}
	//ListPrint(phead);
	//ListPopFront(phead);
	//ListPrint(phead);
	//ListPopBack(phead);
	//ListPrint(phead);

	ListPrint(phead);

	ListNode* pos = ListFind(phead, 2);
	if (pos)
		printf("找到了\n");
	else
		printf("没有找到\n");
	ListInsert(pos, 20);
	ListPrint(phead);

	ListErase(pos,phead);
	ListPrint(phead);


	ListDestory(phead);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值