带头双向循环链表解析

首先创建三个文件,如下图
在这里插入图片描述

list.h包含了需要声明的头文件,当在本项目内的文件需要时,直接声明

#include "list.h"即可;

list.c文件包含了函数执行程序

test.c 文件包含main函数

头文件声明一个结构体,包含一个指向下一个节点的指针(next),一个指向上一个节点的指针(prev),一个数据的类型(data);及各个执行函数的声明

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int LTDataType;
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	LTDataType data;
}LTNode;

//malloc一个节点
LTNode* BuyListNode(LTDataType x);
//初始化
LTNode* ListInit();
//打印
void Print(LTNode* phead);
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//尾删
void LTPopBack(LTNode* phead);
//头插
void LTPushFront(LTNode* phead, LTDataType x);
//头删
void LTPopFront(LTNode* phead);
//查找
LTNode* LTFind(LTNode* phead, LTDataType x);
// 在pos前面进行插入
void LTInsert(LTNode* pos, LTDataType x);
// 删除pos位置的节点
void LTErase(LTNode* pos);
//判断是否只有一个头节点
bool LTEmpty(LTNode* phead);
//求节点长度
size_t LTSize(LTNode* phead);
//销毁
void LTDestroy(LTNode* phead);

开辟一个新的节点

LTNode* BuyListNode(LTDataType x)
{
	struct ListNode* node = (LTNode*)malloc(sizeof(LTNode));
	if (node == NULL)//若新节点等于NULL,则新节点开辟失败
	{
		perror("BuyListNode;;malloc");
		exit(-1);//退出
	}
	node->data = x;
	node->next = NULL;
	node->prev = NULL;
	return node;

}

初始化
将next指向自己
将prev指向自己
在这里插入图片描述

LTNode* ListInit()
{
	struct ListNode* guard = BuyListNode(0);
	 guard->next= guard ;
	 guard->prev= guard ;

	return guard;
}

打印节点

void Print(LTNode* phead)
{
	assert(phead);//哨兵位不能为空
	struct ListNode* cur = phead->next;//从哨兵为下一个开始打印
	
	while (cur!=phead)
	{
		printf("%d ", cur->data);
		cur=cur->next;
	}
	printf("\n");
}

头插
在这里插入图片描述

void LTPushFornt(LTNode* phead, LTDataType x)
{
	assert(phead);
	struct ListNode* newnode = BuyListNode(x);
	struct ListNode* first = phead->next;//记录头的下一个节点
	newnode->next = first;
	phead->next = newnode;
	newnode->prev = phead;
	first->prev=newnode;	
	//LTInsert(phead->next, x);
}

尾插
在这里插入图片描述

void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);
	struct ListNode* newnode = BuyListNode(x);
	struct ListNode* tail = phead->prev;

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

	//LTInsert(phead, x);

}

尾删

void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);//只有头节点不能删

	struct ListNode* tail = phead->prev;
	struct ListNode* tailPrev = tail->prev;
	tailPrev->next = phead;
	phead->prev = tailPrev;
	free(tail);

	//LTErase(phead->prev);
}

头删

void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(phead->next != phead);
	struct ListNode* second = phead->next;
	struct ListNode* cur = second;
	phead->next = second->next;
	phead->next->prev = phead;
	free(second);

	//LTErase(phead->next);//从头的下一个开始删
}

查找

LTNode* LTFind(LTNode* phead, LTDataType x)
{

	struct ListNode* cur = phead->next;//从头的下一个开始查找
	while (cur != phead)
	{
		if (cur->data == x)
		{
			printf("%d", cur->data);
			printf("\n");
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

在pos的前面插入节点

void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);
	struct ListNode* posPrev = pos->prev;
	struct ListNode* newnode = BuyListNode(x);	
	pos->prev = newnode;
	posPrev->next = newnode;
	newnode->next = pos;
	newnode->prev = posPrev;
}

删除pos位置的节点

void LTErase(LTNode* pos)
{
	assert(pos);
	struct ListNode* posPrev = pos->prev;
	struct ListNode* next = pos->next;
	free(pos);
	posPrev->next = next;
	next->prev = posPrev;	
}

判断是否为头节点

bool LTEmpty(LTNode* phead)
{
	assert(phead);
	struct ListNode* cur = phead;
	//if (cur->next == phead)
	//{
	//	return true;
	//}
	//else
	//{
	//	return false;
	//}

	return cur->next == phead;
}

求节点长度

size_t LTSize(LTNode* phead)
{
	struct ListNode* cur = phead;
	size_t count = 0;
	while (cur != phead)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

销毁链表

void LTDestroy(LTNode* phead)
{
	assert(phead);
	struct ListNode* cur = phead->next;//从头的下一个开始释放
	struct ListNode* next =cur->next;
	while (cur!=phead)//直接释放,不需要链接,记得保存下一个的地址
	{
		free(cur);
		cur = next;
		cur = cur->next;
	}
	free(phead);//最后释放头节点
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值