带头双向循环链表

带头双向循环链表:带头指的是带有哨兵位,双向指的是每个元素内包含着两个指针,分别指向该元素的上一个元素和下一个元素,循环表示该链表的尾的指向下一个元素的指针指向头,头的指向上一个元素的指针指向尾;

用图表示为

用c语言实现该结构,并且可以对该结构进行增、删、查、改,其中增又包括头插,尾插,随机插入;删除包括头删、尾删,随机删除;

首先,引出所使用的头文件,及该结构

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

typedef int LTDateType;
//该链表的数据种类

typedef struct LTNode
{
	LTDateType date;
	struct LTNode* prev;
    //指向上一个元素
	struct LTNode* next;
    //指向下一个元素
}LTNode;

接下来要创建一个生成节点的函数

LTNode * BuyLTNode(LTDateType x)
{
	LTNode* newnode = malloc(sizeof(LTNode)); //开辟空间存储数据
	newnode->date = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

释放节点内存函数

void LTNodeDestory(LTNode * phead)
{
	assert(phead);//断言,如果头节点为空,则结束程序,并返回错误原因
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
	phead=NULL;
}

接着定义对该结构体进行初始化的函数

//初始化
void LTNodeInit(LTNode** pphead);

实现该函数

void LTNodeInit(LTNode** pphead)
//需要传二级指针,否则无法成功的初始化,这是由于无法改变结构体的数据
{
	LTNode* newnode = BuyLTNode(0);
   //生成哨兵位节点,其中date需要赋值
	*pphead = newnode;
	newnode->prev = *pphead;
	newnode->next = *pphead;
    //使两个指针分别指向自己
}

定义一个尾插函数

//尾插
void LTNodePushBack(LTNode * phead,LTDateType x);

实现该函数

void LTNodePushBack(LTNode * phead,LTDateType x)
{
	LTNode* newnode = BuyLTNode(x);//生成需要插入的节点

	LTNode* tail = phead->prev;//直接找到该链表的尾节点

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;//将该节点插入
	
}

定义一个头插函数

//头插
void LTNodePushFront(LTNode * phead, LTDateType x);

实现该函数

void LTNodePushFront(LTNode * phead, LTDateType x)
{
	LTNode* newnode = BuyLTNode(x);
	LTNode* first = phead->next;//直接找到头节点

	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;//将新节点变成第一个节点
	
}

定义一个尾删函数

//尾删
void LTNodeDeleBack(LTNode * phead);

实现该函数

void LTNodeDeleBack(LTNode * phead)
{
	assert(phead);
	assert(phead->next != phead);

	LTNode* end = phead->prev;
	LTNode* last = end->prev;//找到尾节点和尾节点的上上一个节点
    
	phead->prev = last;
	last->next = phead;//改变尾节点
	free(end);
	end = NULL;//释放尾节点
}

定义一个头删函数

//头删
void LTNodeDeleFront(LTNode * phead);

实现该函数

void LTNodeDeleFront(LTNode * phead)
{
	assert(phead);
	assert(phead->next != phead);

	LTNode* first = phead->next;
	LTNode* second = first->next;//找到第一和第二个节点 

	phead->next = second;
	second->prev = phead;//把第二个节点变成第一个节点
	free(first);
	first = NULL;//释放原第一个节点	
}

定义一个查找函数

//查找
LTNode * LTNodeFind(LTNode * phead, LTDateType x);

实现该函数

LTNode * LTNodeFind(LTNode * phead, LTDateType x)
{
	assert(phead);

	LTNode* cur = phead->next;//用来遍历链表
	while (cur != phead)
	{
		if (cur->date == x)
			return cur;//存在该数据,返回数据位置
		cur = cur->next;
	}
	return NULL;//不存在返回空指针
}

定义一个随机插入函数

//随机插入,在pos位置的节点之前插入一个节点
void LTNodeInsert(LTNode* pos, LTDateType x);

实现该函数

void LTNodeInsert(LTNode * pos, LTDateType x)
{
	LTNode* newnode = BuyLTNode(x);//生成新结点
	LTNode* prev = pos->prev;//找到要插入节点之前的节点

	prev->next = newnode;
	newnode->next = pos;
	newnode->prev = prev;
	pos->prev = newnode;//进行插入
}

定义一个随机删除的函数

//随机删除
void LTNodeDelete(LTNode * pos);

实现该函数

void LTNodeDelete(LTNode * pos)
{
	LTNode* prev = pos->prev;
	LTNode* next = pos->next;//找到要删除节点的上一个和下一个节点

	prev->next = next;
	next->prev = prev;//把两个节点连在一起
	free(pos);
	pos = NULL;//释放节点
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值