数据结构---链表(Linked)---循环链表(Circular Linked List)+双向链表(Doubly Linked List)+带头(head)

简介 

与单向不带头不循环链表(单链表)相比,

带头双向循环链表:

1.多了第一位的head---哨兵位,head不能少,少了就是不带头;

2.多了前驱指针prev,指向上一位的data;

3.最后一位的后继指针next不指向NULL,指向head;


实现双向循环链表 

创建List.h, List.c, test.c三个文件

初始化链表

​
typedef int LTDataType;//存储的数据类型

typedef struct ListNode
{
	LTDataType data;//数据域
	struct ListNode* prev;//前驱指针
	struct ListNode* next;//后继指针
}LTNode;

​

                                      head->prev=head      ==         head->next=head       

LTNode* LTBuyNode(LTDataType x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	//prev next
	newnode->next = newnode->prev = newnode;

	return newnode;
}

 head随便存个无效值,如-1

//为了保持接口的一致性,优化接口都为一级指针
//初始化
//void LTInit(LTNode** pphead);
LTNode* LTInit();
//初始化
//可以用二级指针
//void LTInit(LTNode** pphead)
//{
//	//创建一个头结点(哨兵位)
//	*pphead = LTBuyNode(-1);
//}
//也可以用指针传指针,保持接口都是一级指针
LTNode* LTInit()
{
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

 链表判空

bool LTEmpty(LTNode* phead);
bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}


 打印

1.创建pcur指针,指向phead的下一位,不能用phead指针遍历,会丢失头指针;

2.遍历链表打印;

3.直到pcur->next=phead;

void LTPrint(LTNode* phead);
void LTPrint(LTNode* phead)
{
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}

测试 (test.c)

void ListTest01()
{
	//创建双向链表变量
	//LTNode* plist = NULL;
	//LTInit(&plist);

	LTNode* plist = LTInit();

	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPushBack(plist, 4);
	LTPrint(plist);
	//LTPushFront(plist, 1);
	//LTPrint(plist);
	//LTPushFront(plist, 2);
	//LTPrint(plist);
	//LTPushFront(plist, 3);
	//LTPrint(plist);
	//LTPushFront(plist, 4);
	//LTPrint(plist);
	//
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopBack(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);

	//LTNode* pos = LTFind(plist, 3);
	//if (pos == NULL)
	//{
	//	printf("没有找到!\n");
	//}
	//else
	//{
	//	printf("找到了!\n");
	//}
	//LTInsert(pos, 11);
	//LTErase(pos);
	//LTPrint(plist);
	
	//LTDesTroy(&plist);
	LTDesTroy2(plist);
	plist = NULL;
}
int main()
{
	ListTest01();
	return 0;
}

插入

         尾插

        

                                                         

                                        head---------------------d3--------------------newnode

newnode->next=phead(new->head)

newnode->prev=phead->prev(new->d3)

    phead->prev->next=newnode(d3->new)    

                                           phead->prev=newnode (head->new)                                              

//插入
//第一个参传一级还是二级,要看pphead指向的节点会不会发生改变
//如果发生改变,那么pphead的改变要影响实参,传二级
//如何不发生改变,pphead不会影响实参,传一级
void LTPushBack(LTNode* phead, LTDataType x);

void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);

	LTNode* newnode = LTBuyNode(x);
	//phead phead->prev newnode
	newnode->next = phead;
	newnode->prev = phead->prev;

	phead->prev->next = newnode;
	phead->prev = newnode;
}

         头插

newnode->next=phead->next(new->d1)

newnode->prev=phead(new->head)

phead->next->prev=newnode(d1->new)

phead->next=newnode(head->new)

void LTPushFront(LTNode* phead, LTDataType x);

void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);

	//phead newnode  phead->next(d1)
	newnode->next = phead->next;
	newnode->prev = phead;

	phead->next->prev = newnode;
	phead->next = newnode;
}

         指定位置插入

//在指定位置插入结点
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);

	ListNode* before = pos->prev;//记录pos指向结点的前一个结点
	ListNode* newnode = BuyListNode(x);//申请一个结点,数据域赋值为x
	//建立新结点与before结点之间的双向关系
	before->next = newnode;
	newnode->prev = before;
	//建立新结点与pos指向结点之间的双向关系
	newnode->next = pos;
	pos->prev = newnode;
}

在指定位置之后插入

//在pos位置之后插入节点
void LTInsert(LTNode* pos, LTDataType x);
//在pos位置之后插入节点
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);

	LTNode* newnode = LTBuyNode(x);

	//pos newnode pos->next
	newnode->next = pos->next;
	newnode->prev = pos;

	pos->next->prev = newnode;
	pos->next = newnode;
}


删除

          尾删

void LTPopBack(LTNode* phead);

                        head-------------d2---------------------del

                                           *prev                             *del

                                        del->prev                        phead->prev

                             prev->next=head(d2->head)

                             phead->prev=prev(head->d2)

void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	//phead  prev(del->prev)  del(phead->prev) 
	LTNode* del = phead->prev;
	LTNode* prev = del->prev;

	prev->next = phead;
	phead->prev = prev;

	free(del);
	del = NULL;
}

          头删

head-----------------------d1-------------------------------d2

 phead                        *del                                 del->next

d2->head:del->next-prev=phead

head->d2:phead->next=del->next

void LTPopFront(LTNode* phead);
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	//phead  del(phead->next)  del->next
	LTNode* del = phead->next;
	del->next->prev = phead;
	phead->next = del->next;

	free(del);
	del = NULL;
}


          指定位置删除

head--------------------d2-----------------------d3

pos->next                  pos->prev             pos

d2->head:pos->prev->next=pos->next

head->d2:pos->next->prev=pos->prev

//删除指定位置节点
void LTErase(LTNode* pos);
//删除指定位置节点
void LTErase(LTNode* pos)
{
	assert(pos);
	// pos->prev  pos   pos->next

	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;

	free(pos);
	pos = NULL;
}

查找 

LTNode* LTFind(LTNode* phead, LTDataType x);
LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

销毁 

//销毁
void LTDesTroy(LTNode** pphead);
//或者
void LTDesTroy2(LTNode* phead);//传一级,需要手动将plist置为NULL
//销毁
void LTDesTroy(LTNode** pphead)
{
	assert(pphead && *pphead);
	LTNode* pcur = (*pphead)->next;
	while (pcur != *pphead)
	{
		LTNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	//销毁哨兵位结点
	free(*pphead);
	*pphead = NULL;
	pcur = NULL;
}
//或者
void LTDesTroy2(LTNode* phead)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		LTNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	free(phead);
	phead = pcur = NULL;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值