双向链表

发布于:2025-03-31 ⋅ 阅读:(23) ⋅ 点赞:(0)

1.带头双向循环链表

 带头链表的头结点实际为“哨兵位 ”,哨兵位节点不存储任何有效元素,只是再放哨。

带头链表中,除了头结点,其他节点都存储有效得的数据。       

实际中我们用的最多的还是单链表、和双向链表(带头双向循环链表)。

双向链表的节点结构:数据+指向后面节点的指针+指向前面节点的指针

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
//双向链表的创建
typedef  int  LTdatatyp;
 typedef struct  ListNode
{
	LTdatatyp  data;
	struct ListNode* next;//指向后面
	struct ListNode* prev;//前面节点

}LTNode ;

1.1双向链表的初始化 

大家来思考一下这里的双向链表能不能为空,

答案是不能,

来猜测一下这样写是正确的吗?

 因为next 和perv都要指向一个节点所以为NULL是不可以的。这里让他们指向newnode即可

 ​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

 

 当双向链表为空的时候:只有一个节点就是头结点。

下面调试一下来看看哨兵创建成功没。

​​​​​​​​​​​​​​

 1.2双向链表的尾插

传一级   或者二级指针是要看phead是否会改变,改变传地址 用** 接收, 不改变传一直指针即可。      

 尾插大概可以这样来修改next  、prev节点

 代码大概是这样的,下面我们来测试一下

 

 1.3双向链表的头插

这里的头插不是在哨兵位头插,而是在哨兵位后面进行头插。

下面的代码就是头插,

 大概就是这样

 

 

 

1.4双向链表的打印

 

打印的结果就如下

1.5双向链表的尾删

 这里的图可以了解一下。

 上面的LTEmpty 是链表不为空

尾删后的结果如下:

 1.6双向链表的头删

 1.7 双向链表的查找

双向链表的查找和前面的单链表的查找类似,

 

 

 1.8在pos位置之后插入节点

 

下面是在3的后面插入23 

 1.9删除pos位置的结点

  

 Find 返回的值是3 ,删除的值就是3

 

 销毁链表

 

 大家可以进行调试来看看链表的销毁

 

 那么讲到这里的话我们的双向链表就结束了。加油!!

List.h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdbool.h>
//双向链表的创建

typedef  int  LTdatatyp;
 typedef struct  ListNode
{	
	 LTdatatyp data;
	struct ListNode* next;//指向后面
	struct ListNode* prev;//前面节点

}LTNode ;
 //初始化
 void ListInit(LTNode** pphead);
 //创建新的空间
 LTNode* LTBuyNode(LTdatatyp x);
 //尾插
 void LTPushback(LTNode* phead,LTdatatyp x);
 //头插
 void  LTPushFront(LTNode* phead, LTdatatyp x);
 //打印
 void LTPrint(LTNode* phead);
 //
 bool	LTEmpty(LTNode* phead);
 //尾删
 void LTPopback(LTNode* phead);
 //头删
 void LTPopFront(LTNode* phead);
 //查找数据
 LTNode* LTFind(LTNode* phead, LTdatatyp x);
 //pos后插入数据
 void LTInsert(LTNode* pos, LTdatatyp x);
 //删除pos节点
 void LTErase(LTNode* pos);
 //销毁链表
 void LTDesTroy(LTNode** pphead);

List.c

#include "List.h"
LTNode* LTBuyNode(LTdatatyp x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);

	}
	newnode->data = x;
	newnode->next = newnode->prev = newnode ;
	return newnode;
}

void ListInit(LTNode** pphead)
{
	//创建一个头节点(哨兵位)
	*pphead = LTBuyNode(-1);

}
//尾插
void LTPushback(LTNode* phead,LTdatatyp x)//这里的插入为什么不用   * *phead 呢 这是因为头结点不会改变,	 
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);
	newnode->next = phead;// newnode的next 与phead连接
	newnode->prev = phead->prev;//与 最后一个数据连接newnode的 头指针

	phead->prev->next = newnode; //插入newnode
	phead->prev = newnode;

}

void LTPushFront(LTNode* phead, LTdatatyp x)
{
	assert(phead);
	LTNode* newnode = LTBuyNode(x);
	newnode->next = phead->next;
	newnode->prev = phead;
	phead->next->prev = newnode;
	phead->next = newnode;

}

void LTPrint(LTNode* phead)
{
	assert(phead);
	LTNode* pcur = phead ->next;//这里的pcur不能等于哨兵点
	while (pcur != phead)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");

}
//判断有效数据的第一个是否为空
bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}
//尾删
void LTPopback(LTNode* phead)
{
	assert(phead);
	assert(! LTEmpty(phead));
	LTNode* del = phead->prev;
	LTNode* prev = del->prev;
	prev->next = phead;
	phead->prev = prev;
	free(del);
	del = NULL;

}
//头删
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	LTNode* del = phead->next;
	del->next->prev = phead;
	phead->next = del->next;
	free(del);
	del = NULL;

}
//查找数据
LTNode* LTFind(LTNode* phead, LTdatatyp x)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)//pcur不等于头指针
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;

	}
	return NULL;

}

//pos后插入数据
void LTInsert (LTNode* pos, LTdatatyp x)
{
	assert(pos);
	LTNode* newnode = LTBuyNode(x); 
	newnode->next = pos->next;
	newnode->prev = pos;
	pos->next = newnode;
	pos->next->prev = newnode;
}

//删除指定位置pos节点
void LTErase(LTNode* pos)
{
	assert(pos);
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;
	free(pos);
	pos =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;
}

text.c

#include "List.h"
void Listext01()
{
	LTNode* plist = NULL;
	ListInit(&plist);
	//尾插
	LTPushback(plist, 1);
	LTPushback(plist, 2);
	LTPushback(plist, 3);
	LTPushback(plist, 4);
	//头插
	/*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);*/
	//头删
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	//LTPrint(plist);
	//LTPopFront(plist);
	LTPrint(plist);
	//查找
	LTNode* Find = LTFind(plist, 4);

	//if (Find == NULL)
	//{
	//	printf("找不到了\n");
	//}
	//else
	//	printf("找到了\n");
	//指定位置后插入
	//LTInsert(Find, 23);
	//LTPrint(plist);
	//删除指定位置数据
	//LTErase(Find);
	//LTPrint(plist);
	//销毁链表
	LTDesTroy(&plist);
	LTPrint(plist);
	LTDesTroy(&plist);
	LTPrint(plist);
	LTDesTroy(&plist);
	LTPrint(plist);
	LTDesTroy(&plist);
	LTPrint(plist);



 }
int main()
{
	Listext01();

	return 0; 
}