链表续-8种链表(数据结构)

news2024/11/19 12:29:31

了解链表

由于之前已经有一篇文章介绍链表,本次直接上八种链表的代码

具体前一篇文章阅读此处链表介绍

八种链表代码

单向链表

节点当中存放数据以及指向下一个节点的指针

代码:

#define _CRT_SECURE_NO_WARINGS 1

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

typedef int DataType;

//创建单链表结构
typedef struct SListNode
{
	DataType data;
	struct SListNode* next;
}SLTNode;


//打印
void SLTPrint(SLTNode* phead)
{
	//断言指针
	//assert(phead);

	SLTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//开辟空间
SLTNode* SLTSpace(DataType x)
{
	//开辟空间
	SLTNode* p = (SLTNode*)malloc(sizeof(SLTNode));
	if (p == NULL)
	{
		perror("Space malloc fail");
		return NULL;
	}
	p->data = x;
	p->next = NULL;
	return p;
}

//头插
void SLPushFront(SLTNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);
	//创建节点
	SLTNode* newNode = SLTSpace(x);

	//无节点的情况下直接插入
	if (*pphead == NULL)
	{
		*pphead = newNode;
		return;
	}
	//节点存在的情况下插入
	newNode->next = *pphead;
	*pphead = newNode;

}

//头删
void SLPopFront(SLTNode** pphead)
{
	//断言指针
	assert(pphead);
	assert(*pphead);
	//只有一个节点的情况下
	if ((*pphead)->next == NULL)
	{
		//直接进行删除释放
		(*pphead)->data = 0;
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//有多个节点的情况下
	SLTNode* cur = *pphead;
	SLTNode* tail = *pphead;
	//tail表示头节点的下一个节点
	tail = cur->next;
	//释放头节点
	cur->data = 0;
	free(cur);
	*pphead = tail;
	//将tail置NULL 避免野指针
	tail = NULL;
}

//尾插
void SLPushBank(SLTNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);
	//assert(*pphead);无节点的情况不能断言

	//开辟新节点
	SLTNode* newNode = SLTSpace(x);

	//没有节点的情况
	if (*pphead == NULL)
	{
		//直接插入
		*pphead = newNode;
		return;
	}

	//存在节点的时候
	//循环遍历找尾
	//找尾进行尾插
	SLTNode* cur = *pphead;
	while (cur->next)
	{
		cur = cur->next;
	}
	//尾插链接
	cur->next = newNode;
}

//尾删
void SLPopBank(SLTNode** pphead)
{
	//断言指针
	assert(pphead);
	assert(*pphead);

	//只有一个节点的情况
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}

	//进行找尾
	SLTNode* cur = *pphead;
	SLTNode* tail = *pphead;
	while (tail->next)
	{
		//cur表示最后一个节点的前一个节点
		cur = tail;
		tail = tail->next;
	}
	free(tail);
	tail = NULL;
	cur->next = NULL;
}

//查找
SLTNode* SLFind(SLTNode* phead, DataType x)
{
	//断言指针
	assert(phead);

	//循环遍历查找
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	//找不见的时候返回NULL
	return NULL;
}

//销毁
void SLDestroy(SLTNode** pphead)
{
	//断言指针
	assert(*pphead);

	//循环遍历销毁节点
	SLTNode* cur = *pphead;
	SLTNode* tail = *pphead;
	while (cur)
	{
		tail = cur;
		cur = cur->next;
		tail->data = 0;
		free(tail);
	}
	*pphead = NULL;
}

//在pos位置前插入
void SLInsert(SLTNode** pphead, SLTNode* pos, DataType x)
{
	//断言指针
	assert(pphead);
	//申请节点
	SLTNode* newnode = SLTSpace(x);

	//pos为NULL
	if (pos == NULL)
	{
		// *pphead也为NULL,直接插入
		if ((*pphead) == NULL)
		{
			*pphead = newnode;
			newnode->next = pos;
			return;
		}
		//pos为NULL 且*pphead不为空的情况
		//说明最后一个节点的下一个节点就是尾插
		SLPushBank(pphead, x);
		return;
	}

	//pos是头节点的情况,直接进行头插
	if (pos == (*pphead))
	{
		//头插
		SLPushFront(pphead, x);
		return;
	}

	//pos不为空且不是头节点的情况
	SLTNode* cur = *pphead;
	SLTNode* prev = *pphead;
	while (cur)
	{
		if (cur == pos)
		{
			prev->next = newnode;
			newnode->next = pos;
			return;
		}
		prev = cur;
		cur = cur->next;
	}
	perror("pos Does not exist");
}

//在pos位置前删除
void SLErase(SLTNode** pphead, SLTNode* pos)
{
	//pos为空其实就是尾删(以上函数已经实现)
	//pos和为头节点无法删除,头节点前无任何节点
	//pos为头节点且都为NULL ,无节点无法删除
	//即pos不为头节点,且pos不能为空

	//断言指针
	assert(pphead);
	assert(*pphead);//头节点不能为空,无法删除
	assert(pos);

	//若pos为第二个节点,删除pos的前一个节点就是头删
	if ((*pphead)->next == pos)
	{
		//头删
		SLPopFront(pphead);
		return;
	}

	//pos为头节点无法删除,头节点前无任何节点
	if (pos == (*pphead))
	{
		perror("pos == phead");
		return;
	}

	//不是头删以及不是头的情况
	SLTNode* cur = *pphead;
	SLTNode* pevr = *pphead;
	SLTNode* ppevr = *pphead;
	while (cur)
	{
		if (cur == pos)
		{
			free(pevr);
			pevr = NULL;
			ppevr->next = cur;
			return;
		}
		ppevr = pevr;
		pevr = cur;
		cur = cur->next;
	}
	perror("pos Does not exist");
}

//在pos位置后插入
void SLInsertAfter(SLTNode* pos, DataType x)
{
	//pos为空的情况下,无法插入
	assert(pos);

	//创建节点
	SLTNode* newnode = SLTSpace(x);

	SLTNode* plast = pos->next;
	pos->next = newnode;
	newnode->next = plast;
}

//在pos位置后删除
void SLEraseAfter(SLTNode* pos)
{
	//pos不能为NULL,为NULL无法删除
	assert(pos);
	//pos后一个节点为NULL的情况,无法删除
	assert(pos->next);

	SLTNode* cur = pos->next;
	SLTNode* plast = pos->next->next;

	free(cur);
	cur = NULL;
	pos->next = plast;
}


int main()
{
	//创建变量
	SLTNode* sl = NULL;
	SLPushFront(&sl, 1);//头插
	SLTPrint(sl);//打印

	SLPushFront(&sl, 2);//头插
	SLPushFront(&sl, 3);//头插
	SLTPrint(sl);//打印

	SLPopFront(&sl);//头删
	SLPopFront(&sl);//头删
	SLTPrint(sl);//打印

	SLPopFront(&sl);//头删
	SLTPrint(sl);//打印

	SLPushBank(&sl, 6);//尾插
	SLPushBank(&sl, 7);//尾插
	SLPushBank(&sl, 8);//尾插
	SLTPrint(sl);//打印

	SLPopBank(&sl);//尾删
	SLTPrint(sl);//打印

	SLTNode* ret = SLFind(sl, 7);//查找
	printf("%d\n", ret->data);

	SLInsert(&sl, ret, 8);//在pos位置前插入
	SLTPrint(sl);//打印

	SLErase(&sl, ret);//在pos位置前删除
	SLTPrint(sl);//打印

	SLInsertAfter(ret, 9);//在pos位置后插入
	SLTPrint(sl);//打印

	SLEraseAfter(ret);//在pos位置后删除
	SLTPrint(sl);//打印

	SLDestroy(&sl);//销毁
	SLTPrint(sl);//打印

	return 0;
}

单向带头链表

节点中存放数据以及指向下一个节点的指针,且会单独开一个哨兵位的头节点,该头节点一般不存放有效数据。

代码:

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int DataType;

//定义结构
typedef struct HSTNode
{
	DataType data;
	struct HSTNode* next;
}HSTNode;


//初始化头节点(创建哨兵位的头节点)
void HSTInit(HSTNode** pphead, DataType x)
{
	//开辟空间,带头节点
	assert(pphead);
	HSTNode* cur = (HSTNode*)malloc(sizeof(HSTNode));
	if (cur == NULL)
	{
		perror("head malloc fail");
		return;
	}
	cur->data = x;
	cur->next = NULL;
	*pphead = cur;
}

//开空间
HSTNode* HSTSpace(DataType x)
{
	HSTNode* newnode = (HSTNode*)malloc(sizeof(HSTNode));
	if (newnode == NULL)
	{
		perror("head malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

//打印
void HSTPrint(HSTNode* phead)
{
	//必须存在哨兵位的头节点
	assert(phead);
	HSTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//头插(插到哨兵位头节点的后面)
void HSTPushFront(HSTNode** pphead, DataType x)
{
	//必须存在头节点,断言头节点
	assert(pphead);
	assert(*pphead);

	//开辟空间
	HSTNode* newnode = HSTSpace(x);

	//直接插入
	HSTNode* cur = (*pphead)->next;
	(*pphead)->next = newnode;
	newnode->next = cur;
}

//头删
void HSTPopFront(HSTNode** pphead)
{
	//带哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//只有哨兵位头节点一个节点的情况不能删除
	if ((*pphead)->next == NULL)
	{
		perror("is NULL");
		return;
	}

	HSTNode* cur = (*pphead)->next->next;
	HSTNode* pevr = (*pphead)->next;
	free(pevr);
	pevr = NULL;
	(*pphead)->next = cur;
}

//尾插
void HSTPushBank(HSTNode** pphead, DataType x)
{
	//哨兵位的头节点不能为空
	assert(pphead);
	assert(*pphead);

	//开辟节点空间
	HSTNode* newnode = HSTSpace(x);

	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur)
	{
		pevr = cur;
		cur = cur->next;
	}
	pevr->next = newnode;
}

//尾删
void HSTPopBank(HSTNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//没有数据的时候无法删除(仅有哨兵位的头节点)
	if ((*pphead)->next == NULL)
	{
		perror("is NULL");
		return;
	}

	//存在数据找尾释放
	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur->next)
	{
		pevr = cur;
		cur = cur->next;
	}
	free(cur);
	cur = NULL;
	pevr->next = NULL;
}

//查找
HSTNode* HSTFind(HSTNode* phead, DataType x)
{
	//保证哨兵位的头节点存在
	assert(phead);

	//遍历查找
	HSTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos位置前插入
void SHTInsert(HSTNode** pphead, HSTNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos不能为哨兵位的头节点
	if ((*pphead) == pos)
	{
		perror("(*pphead) == pos");
		return;
	}
	//pos为空,表示pos为最后一个节点的下一个节点
	//在pos前插入实际上是尾插
	if (pos == NULL)
	{
		//尾插
		HSTPushBank(pphead, x);
		return;
	}

	//获取节点
	HSTNode* newnode = HSTSpace(x);

	//进行插入
	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur)
	{
		if (cur == pos)
		{
			pevr->next = newnode;
			newnode->next = pos;
			return;
		}
		pevr = cur;
		cur = cur->next;
	}
	perror("pos Does not exist");
}

//在pos位置前删除
void SHTErase(HSTNode** pphead, HSTNode* pos)
{
	//保证哨兵位的头节点必须存在
	assert(*pphead);
	assert(pphead);
	//若只有头或pos为哨兵位头节点的下一个节点情况下不能删除
	if ((*pphead)->next == pos)
	{
		perror("*pphead->next==pos");
		return;
	}
	//pos为哨兵位的头节点的情况下不能删除
	if ((*pphead) == pos)
	{
		perror("(*pphead) == pos");
		return;
	}

	//pos既不为哨兵位头节点,也不是头节点的下一个节点
	//若pos为空,则是尾删
	//以及pos不为空的情况
	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur)
	{
		if (cur->next == pos)
		{
			free(cur);
			pevr->next = pos;
			cur = NULL;
			return;
		}
		pevr = cur;
		cur = cur->next;
	}
	perror("pos Does not exist");
}

//在pos位置后插入
void SHTInsertAfert(HSTNode* pos, DataType x)
{
	//pos为空不能插入
	//保证头节点存在
	assert(pos);

	//获取节点
	HSTNode* newnode = HSTSpace(x);
	//直接插入
	HSTNode* cur = pos->next;
	pos->next = newnode;
	newnode->next = cur;
}

//在pos位置后删除
void SHTEraseAfert(HSTNode* pos)
{
	//pos为空不能删除
	assert(pos);

	//pos的下一个元素为NULL,不能删除
	if (pos->next == NULL)
	{
		perror("pos->next == NULL");
		return;
	}

	//进行删除
	HSTNode* perv = pos->next;
	HSTNode* cur = pos->next->next;

	free(perv);
	perv = NULL;
	pos->next = cur;

}

//销毁
void HSTDestroy(HSTNode** pphead)
{
	//哨兵位的头节点也进行销毁
	//手心断定哨兵位的头节点时存在的
	assert(pphead);
	assert(*pphead);

	//循环遍历销毁
	HSTNode* cur = *pphead;
	HSTNode* next = *pphead;
	while (cur)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	//销毁后将哨兵位的头节点置空,避免野指针
	*pphead = NULL;
}


int main()
{
	HSTNode* sl = NULL;
	//初始化头节点(创建哨兵位的头节点)
	HSTInit(&sl, 0);
	HSTPrint(sl);//打印

	//头插
	HSTPushFront(&sl, 1);
	HSTPushFront(&sl, 2);
	HSTPushFront(&sl, 3);
	HSTPushFront(&sl, 4);
	HSTPrint(sl);//打印

	//头删
	HSTPopFront(&sl);
	HSTPopFront(&sl);
	HSTPopFront(&sl);
	HSTPopFront(&sl);
	HSTPrint(sl);//打印

	//尾插
	HSTPushBank(&sl, 7);
	HSTPushBank(&sl, 8);
	HSTPushBank(&sl, 9);
	HSTPrint(sl);//打印

	//尾删
	HSTPopBank(&sl);
	HSTPopBank(&sl);
	HSTPrint(sl);//打印

	//查找
	HSTNode* ret = HSTFind(sl, 7);
	printf("%d\n", ret->data);

	//在pos位置前插入
	SHTInsert(&sl, ret, 1);
	SHTInsert(&sl, NULL, 3);
	HSTPrint(sl);//打印

   //在pos位置前删除
	SHTErase(&sl, ret);
	SHTErase(&sl, NULL);
	HSTPrint(sl);//打印

	//在pos位置后插入
	SHTInsertAfert(ret, 6);
	SHTInsertAfert(sl, 9);
	HSTPrint(sl);//打印

	//在pos位置后删除
	SHTEraseAfert(ret);
	SHTEraseAfert(sl);
	HSTPrint(sl);//打印

	//销毁
	HSTDestroy(&sl);
	//销毁之后无法打印
	//HSTPrint(sl);//打印

	return 0;
}

单向循环链表

节点中存放数据以及指向下一个节点的指针,且尾节点中存放的指向下一个节点的指针为头节点的地址,形成尾首相连为一个循环。

代码:

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int DataType;

//定义结构
typedef struct HSTNode
{
	DataType data;
	struct HSTNode* next;
}HSTNode;


//初始化头节点(创建哨兵位的头节点)
void HSTInit(HSTNode** pphead, DataType x)
{
	//开辟空间,带头节点
	assert(pphead);
	HSTNode* cur = (HSTNode*)malloc(sizeof(HSTNode));
	if (cur == NULL)
	{
		perror("head malloc fail");
		return;
	}
	cur->data = x;
	cur->next = NULL;
	*pphead = cur;
}

//开空间
HSTNode* HSTSpace(DataType x)
{
	HSTNode* newnode = (HSTNode*)malloc(sizeof(HSTNode));
	if (newnode == NULL)
	{
		perror("head malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}

//打印
void HSTPrint(HSTNode* phead)
{
	//必须存在哨兵位的头节点
	assert(phead);
	HSTNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//头插(插到哨兵位头节点的后面)
void HSTPushFront(HSTNode** pphead, DataType x)
{
	//必须存在头节点,断言头节点
	assert(pphead);
	assert(*pphead);

	//开辟空间
	HSTNode* newnode = HSTSpace(x);

	//直接插入
	HSTNode* cur = (*pphead)->next;
	(*pphead)->next = newnode;
	newnode->next = cur;
}

//头删
void HSTPopFront(HSTNode** pphead)
{
	//带哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//只有哨兵位头节点一个节点的情况不能删除
	if ((*pphead)->next == NULL)
	{
		perror("is NULL");
		return;
	}

	HSTNode* cur = (*pphead)->next->next;
	HSTNode* pevr = (*pphead)->next;
	free(pevr);
	pevr = NULL;
	(*pphead)->next = cur;
}

//尾插
void HSTPushBank(HSTNode** pphead, DataType x)
{
	//哨兵位的头节点不能为空
	assert(pphead);
	assert(*pphead);

	//开辟节点空间
	HSTNode* newnode = HSTSpace(x);

	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur)
	{
		pevr = cur;
		cur = cur->next;
	}
	pevr->next = newnode;
}

//尾删
void HSTPopBank(HSTNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//没有数据的时候无法删除(仅有哨兵位的头节点)
	if ((*pphead)->next == NULL)
	{
		perror("is NULL");
		return;
	}

	//存在数据找尾释放
	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur->next)
	{
		pevr = cur;
		cur = cur->next;
	}
	free(cur);
	cur = NULL;
	pevr->next = NULL;
}

//查找
HSTNode* HSTFind(HSTNode* phead, DataType x)
{
	//保证哨兵位的头节点存在
	assert(phead);

	//遍历查找
	HSTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos位置前插入
void SHTInsert(HSTNode** pphead, HSTNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos不能为哨兵位的头节点
	if ((*pphead) == pos)
	{
		perror("(*pphead) == pos");
		return;
	}
	//pos为空,表示pos为最后一个节点的下一个节点
	//在pos前插入实际上是尾插
	if (pos == NULL)
	{
		//尾插
		HSTPushBank(pphead, x);
		return;
	}

	//获取节点
	HSTNode* newnode = HSTSpace(x);

	//进行插入
	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur)
	{
		if (cur == pos)
		{
			pevr->next = newnode;
			newnode->next = pos;
			return;
		}
		pevr = cur;
		cur = cur->next;
	}
	perror("pos Does not exist");
}

//在pos位置前删除
void SHTErase(HSTNode** pphead, HSTNode* pos)
{
	//保证哨兵位的头节点必须存在
	assert(*pphead);
	assert(pphead);
	//若只有头或pos为哨兵位头节点的下一个节点情况下不能删除
	if ((*pphead)->next == pos)
	{
		perror("*pphead->next==pos");
		return;
	}
	//pos为哨兵位的头节点的情况下不能删除
	if ((*pphead) == pos)
	{
		perror("(*pphead) == pos");
		return;
	}

	//pos既不为哨兵位头节点,也不是头节点的下一个节点
	//若pos为空,则是尾删
	//以及pos不为空的情况
	HSTNode* cur = *pphead;
	HSTNode* pevr = *pphead;
	while (cur)
	{
		if (cur->next == pos)
		{
			free(cur);
			pevr->next = pos;
			cur = NULL;
			return;
		}
		pevr = cur;
		cur = cur->next;
	}
	perror("pos Does not exist");
}

//在pos位置后插入
void SHTInsertAfert(HSTNode* pos, DataType x)
{
	//pos为空不能插入
	//保证头节点存在
	assert(pos);

	//获取节点
	HSTNode* newnode = HSTSpace(x);
	//直接插入
	HSTNode* cur = pos->next;
	pos->next = newnode;
	newnode->next = cur;
}

//在pos位置后删除
void SHTEraseAfert(HSTNode* pos)
{
	//pos为空不能删除
	assert(pos);

	//pos的下一个元素为NULL,不能删除
	if (pos->next == NULL)
	{
		perror("pos->next == NULL");
		return;
	}

	//进行删除
	HSTNode* perv = pos->next;
	HSTNode* cur = pos->next->next;

	free(perv);
	perv = NULL;
	pos->next = cur;

}

//销毁
void HSTDestroy(HSTNode** pphead)
{
	//哨兵位的头节点也进行销毁
	//手心断定哨兵位的头节点时存在的
	assert(pphead);
	assert(*pphead);

	//循环遍历销毁
	HSTNode* cur = *pphead;
	HSTNode* next = *pphead;
	while (cur)
	{
		next = cur->next;
		free(cur);
		cur = next;
	}
	//销毁后将哨兵位的头节点置空,避免野指针
	*pphead = NULL;
}


int main()
{
	HSTNode* sl = NULL;
	//初始化头节点(创建哨兵位的头节点)
	HSTInit(&sl, 0);
	HSTPrint(sl);//打印

	//头插
	HSTPushFront(&sl, 1);
	HSTPushFront(&sl, 2);
	HSTPushFront(&sl, 3);
	HSTPushFront(&sl, 4);
	HSTPrint(sl);//打印

	//头删
	HSTPopFront(&sl);
	HSTPopFront(&sl);
	HSTPopFront(&sl);
	HSTPopFront(&sl);
	HSTPrint(sl);//打印

	//尾插
	HSTPushBank(&sl, 7);
	HSTPushBank(&sl, 8);
	HSTPushBank(&sl, 9);
	HSTPrint(sl);//打印

	//尾删
	HSTPopBank(&sl);
	HSTPopBank(&sl);
	HSTPrint(sl);//打印

	//查找
	HSTNode* ret = HSTFind(sl, 7);
	printf("%d\n", ret->data);

	//在pos位置前插入
	SHTInsert(&sl, ret, 1);
	SHTInsert(&sl, NULL, 3);
	HSTPrint(sl);//打印

   //在pos位置前删除
	SHTErase(&sl, ret);
	SHTErase(&sl, NULL);
	HSTPrint(sl);//打印

	//在pos位置后插入
	SHTInsertAfert(ret, 6);
	SHTInsertAfert(sl, 9);
	HSTPrint(sl);//打印

	//在pos位置后删除
	SHTEraseAfert(ret);
	SHTEraseAfert(sl);
	HSTPrint(sl);//打印

	//销毁
	HSTDestroy(&sl);
	//销毁之后无法打印
	//HSTPrint(sl);//打印

	return 0;
}

单向带头循环链表

节点中存放数据以及指向下一个节点的指针,会开辟一个节点空间用来做哨兵位的头节点,一般头节点中不存放有效数据,且尾节点中存放的指向下一个节点的指针为哨兵位头节点的地址,形成尾首相连为一个循环。

代码:

#define _CRT_SECURE_NO_WARNINGS 1

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

//创建节点
typedef int DataType;

typedef struct HPLSTNode
{
	DataType data;
	struct HPLST* next;
}HPLSTNode;


//初始化哨兵位的头节点
void HPLSTInit(HPLSTNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);

	//申请节点
	HPLSTNode* cur = (HPLSTNode*)malloc(sizeof(HPLSTNode));
	if (cur == NULL)
	{
		perror("mallc fail");
		return;
	}
	//开辟成功
	cur->next = cur;
	cur->data = x;
	*pphead = cur;
}

//创建节点
HPLSTNode* HPLSTSpace(DataType x)
{
	//开辟空间
	HPLSTNode* newnode = (HPLSTNode*)malloc(sizeof(HPLSTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->next = NULL;
	newnode->data = x;
	return newnode;
}

//打印
void HPLSTPrint(HPLSTNode* phead)
{
	if (phead == NULL)
	{
		printf("NULL\n");
		return;
	}
	//哨兵位的头节点一定存在
	printf("%d->", phead->data);
	HPLSTNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("head\n");
}

//头插
void HPLSTPushFront(HPLSTNode** pphead, DataType x)
{
	//带哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//创建节点
	HPLSTNode* newnode = HPLSTSpace(x);

	//直接插入
	HPLSTNode* next = (*pphead)->next;
	(*pphead)->next = newnode;
	newnode->next = next;
}

//头删
void HPLSTPopFront(HPLSTNode** pphead)
{
	//带哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//除了哨兵位头节点,不存在其他节点的情况下不可删除
	if ((*pphead)->next == (*pphead))
	{
		assert(NULL);
	}
	//具有其他节点的情况可以删除
	HPLSTNode* cur = (*pphead)->next;
	HPLSTNode* next = cur->next;
	cur->next = NULL;
	free(cur);
	cur = NULL;
	(*pphead)->next = next;
}

//尾插
void HPLSTPushBank(HPLSTNode** pphead, DataType x)
{
	//哨兵位的头节点必须存在(即链表不能为NULL)
	assert(pphead);
	assert(*pphead);

	//创建节点
	HPLSTNode* newnode = HPLSTSpace(x);

	//找尾进行插入
	HPLSTNode* cur = *pphead;
	while (cur->next != (*pphead))
	{
		cur = cur->next;
	}
	//插入
	HPLSTNode* next = cur->next;
	cur->next = newnode;
	newnode->next = next;
}

//尾删
void HPLSTPopBank(HPLSTNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//仅有哨兵位的头节点一个节点的时候无法删除
	if ((*pphead)->next == (*pphead))
	{
		assert(NULL);
	}

	//有两个或多个节点的情况
	//找尾删除
	HPLSTNode* cur = *pphead;
	HPLSTNode* pevr = *pphead;
	while (cur->next != (*pphead))
	{
		pevr = cur;
		cur = cur->next;
	}
	//删除
	HPLSTNode* next = cur->next;
	cur->next = NULL;
	free(cur);
	cur = NULL;
	pevr->next = next;
}

//查找
HPLSTNode* HPLSTFind(HPLSTNode** pphead, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//仅有哨兵位头节点一个节点的时候不可查找
	//头节点不存有效数据
	if ((*pphead)->next == (*pphead))
	{
		assert(NULL);
	}

	//循环遍历查找
	HPLSTNode* cur = (*pphead)->next;
	while (cur != (*pphead))
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos位置前插入
void HPLSTInster(HPLSTNode** pphead, HPLSTNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos为NULL无法插入
	assert(pos);

	//获取节点
	HPLSTNode* newnode = HPLSTSpace(x);

	//pos为哨兵位的头节点(就是尾插)
	if (pos == (*pphead))
	{
		HPLSTPushBank(pphead, x);
		return;
	}

	//pos不为头节点
	//找到pos的前一个节点进行插入操作
	HPLSTNode* cur = *pphead;
	HPLSTNode* pevr = *pphead;
	while (cur != pos)
	{
		pevr = cur;
		cur = cur->next;
	}
	pevr->next = newnode;
	newnode->next = cur;
}

//在pos位置前删除
void HPLSTErase(HPLSTNode** pphead, HPLSTNode* pos)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos为NULL无法删除
	assert(pos);

	//pos为哨兵位的头节点的下一个节点无法删除
	//因为哨兵位的头节点必须存在
	if ((*pphead)->next == pos)
	{
		assert(NULL);
		return;
	}

	//pos为哨兵位的头节点则是尾删
	if (pos == (*pphead))
	{
		//尾删
		HPLSTPopBank(pphead);
		return;
	}

	//其余情况
	HPLSTNode* cur = *pphead;
	HPLSTNode* pevr = *pphead;
	while (cur->next != pos)
	{
		pevr = cur;
		cur = cur->next;
	}
	cur->next = NULL;
	free(cur);
	cur = NULL;
	pevr->next = pos;
}

//在pos位置后插入
void HPLSTInsertAfter(HPLSTNode** pphead, HPLSTNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos为NULL不能插入
	assert(pos);

	//判断pos是否为该链表中的节点
	//…………………… 省略………………

	//存在的情况
	//创建节点
	HPLSTNode* newnode = HPLSTSpace(x);
	HPLSTNode* next = pos->next;
	//进行插入
	pos->next = newnode;
	newnode->next = next;
}

//在pos位置后删除
void HPLSTEraseAfter(HPLSTNode** pphead, HPLSTNode* pos)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos为NULL不能删除
	assert(pos);

	//仅有哨兵位头节点一个节点的情况不能删除
	if ((*pphead)->next == (*pphead))
	{
		assert(NULL);
	}

	//pos为尾节点的情况不能删除
	if (pos->next == (*pphead))
	{
		assert(NULL);
	}

	HPLSTNode* cur = pos->next;
	HPLSTNode* next = cur->next;
	cur->next = NULL;
	free(cur);
	cur = NULL;
	pos->next = next;
}

//销毁
void HPLSTDestroy(HPLSTNode** pphead)
{
	//无节点的情况下不用销毁
	assert(pphead);
	assert(*pphead);

	//开始销毁
	HPLSTNode* cur = (*pphead)->next;
	HPLSTNode* ccur = cur;
	while (cur != (*pphead))
	{
		ccur = cur->next;
		cur->next = NULL;
		free(cur);
		cur = ccur;
	}
	cur->next = NULL;
	free(cur);
	cur = NULL;
	ccur = NULL;
	*pphead = NULL;
}


int main()
{
	HPLSTNode* sl = NULL;
	//初始化哨兵位的头节点
	HPLSTInit(&sl, 0);
	HPLSTPrint(sl);//打印

	//头插
	HPLSTPushFront(&sl, 1);
	HPLSTPushFront(&sl, 2);
	HPLSTPushFront(&sl, 3);
	HPLSTPrint(sl);//打印

	//头删
	HPLSTPopFront(&sl);
	HPLSTPrint(sl);//打印
	HPLSTPopFront(&sl);
	HPLSTPrint(sl);//打印
	HPLSTPopFront(&sl);
	HPLSTPrint(sl);//打印

	//尾插
	HPLSTPushBank(&sl, 4);
	HPLSTPushBank(&sl, 5);
	HPLSTPushBank(&sl, 6);
	HPLSTPrint(sl);//打印

	//尾删
	HPLSTPopBank(&sl);
	HPLSTPrint(sl);//打印
	HPLSTPopBank(&sl);
	HPLSTPrint(sl);//打印

	//查找
	HPLSTNode* ret = HPLSTFind(&sl, 4);
	if (ret != NULL) printf("Find: %d\n", ret->data);
	else printf("Find: NULL\n");

	//在pos位置前插入
	HPLSTInster(&sl, ret, 9);
	HPLSTPrint(sl);//打印
	HPLSTInster(&sl, sl, 12);
	HPLSTPrint(sl);//打印
	HPLSTInster(&sl, sl->next, 16);
	HPLSTPrint(sl);//打印

   //查找
	ret = HPLSTFind(&sl, 4);
	if (ret != NULL) printf("Find: %d\n", ret->data);
	else printf("Find: NULL\n");

	//在pos位置前删除
	//HPLSTErase(&sl, ret->next);
	//HPLSTPrint(sl);//打印
	//HPLSTErase(&sl, NULL);
	//HPLSTPrint(sl);//打印
	//HPLSTErase(NULL, ret);
	//HPLSTPrint(sl);//打印
	HPLSTErase(&sl, ret);
	HPLSTPrint(sl);//打印
	HPLSTErase(&sl, ret);
	HPLSTPrint(sl);//打印
	//HPLSTErase(&sl, ret);
	//HPLSTPrint(sl);//打印

	//查找
	ret = HPLSTFind(&sl, 4);
	if (ret != NULL) printf("Find: %d\n", ret->data);
	else printf("Find: NULL\n");

	//在pos位置后插入
	HPLSTInsertAfter(&sl, ret->next, 45);
	HPLSTPrint(sl);//打印
	HPLSTInsertAfter(&sl, ret, 45);
	HPLSTPrint(sl);//打印

	//在pos位置后删除
	HPLSTEraseAfter(&sl, ret);
	HPLSTPrint(sl);//打印
	HPLSTEraseAfter(&sl, ret);
	HPLSTPrint(sl);//打印
	HPLSTEraseAfter(&sl, ret);
	HPLSTPrint(sl);//打印
	HPLSTEraseAfter(&sl, sl);
	HPLSTPrint(sl);//打印

	//销毁
	HPLSTDestroy(&sl);
	HPLSTPrint(sl);//打印

	return 0;
}

双向链表

节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针。

代码:

#define _CRT_SECURE_NO_WARNINGS 1


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

//创建结构
typedef int DataType;

typedef struct BSTLNode
{
	DataType data;
	struct BSTLNode* pevr;
	struct BSTLNode* next;
}BSTLNode;



//开辟空间(创建节点)
BSTLNode* BSTLSpace(DataType x)
{
	BSTLNode* newnode = (BSTLNode*)malloc(sizeof(BSTLNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;
	newnode->next = NULL;
	newnode->pevr = NULL;
}

//打印
void BSTLPrint(BSTLNode* phead)
{
	BSTLNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//头插
void BSTLPushFront(BSTLNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);

	//创建节点
	BSTLNode* newnode = BSTLSpace(x);
	//无节点的情况
	if (*pphead == NULL)
	{
		*pphead = newnode;
		return;
	}

	//存在节点的情况
	newnode->next = (*pphead);
	(*pphead)->pevr = newnode;
	*pphead = newnode;
}

//头删
void BSTLPopFront(BSTLNode** pphead)
{
	//无节点的情况下不能删除
	assert(*pphead);
	assert(pphead);

	//仅有一个头节点的情况下
	if ((*pphead)->next == NULL)
	{
		(*pphead)->next = NULL;
		(*pphead)->pevr = NULL;
		free(*pphead);
		*pphead = NULL;
		return;
	}
	//有节点的情况下删除
	BSTLNode* cur = (*pphead)->next;
	free(cur->pevr);
	cur->pevr = NULL;
	*pphead = cur;
}

//尾插
void BSTLPushBank(BSTLNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);

	//创建节点
	BSTLNode* newnode = BSTLSpace(x);

	//无节点的情况下直接插入
	if ((*pphead) == NULL)
	{
		//直接插入
		*pphead = newnode;
		return;
	}

	//有节点的情况下,找尾插入
	BSTLNode* cur = *pphead;
	while (cur->next)
	{
		cur = cur->next;
	}

	cur->next = newnode;
	newnode->pevr = cur;
}

//尾删
void BSTLPopBank(BSTLNode** pphead)
{
	//没有节点不能删除
	assert(pphead);
	assert(*pphead);

	//只有一个头节点的情况
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
		return;
	}

	//找尾释放删除
	BSTLNode* cur = *pphead;
	while (cur->next)
	{
		cur = cur->next;
	}
	BSTLNode* pevr = cur->pevr;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pevr->next = NULL;
}

//查找
BSTLNode* BSTLFind(BSTLNode** pphead, DataType x)
{
	//没有节点无法查找
	assert(*pphead);

	BSTLNode* cur = *pphead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
	}

	return NULL;
}

//在pos位置前插入
void BSTLInsert(BSTLNode** pphead, BSTLNode* pos, DataType x)
{
	//断言指针
	assert(pphead);
	assert(*pphead);

	//pos为空实际上是尾插
	if (pos == NULL)
	{
		BSTLPushBank(pphead, x);
		return;
	}

	//申请节点
	BSTLNode* newnode = BSTLSpace(x);

	//pos为头节点,前面插入便是头插
	if ((*pphead) == pos)
	{
		BSTLPushFront(pphead, x);
		return;
	}

	//不为头节点则直接插入
	BSTLNode* pevr = pos->pevr;
	pevr->next = newnode;
	newnode->pevr = pevr;
	newnode->next = pos;
}

//在pos位置前删除
void BSTLErase(BSTLNode** pphead, BSTLNode* pos)
{
	//头节点不能为NULL
	assert(pphead);
	assert(*pphead);

	//若为头节点则不能删除
	if ((*pphead) == pos)
	{
		perror("pos==phead");
		return;
	}

	//pos为NULL说明是尾删
	if (pos == NULL)
	{
		BSTLPopBank(pphead);
		return;
	}

	//pos为第二个节点
	if ((*pphead)->next == pos)
	{
		(*pphead)->pevr = NULL;
		(*pphead)->next = NULL;
		free(*pphead);
		pos->pevr = NULL;
		*pphead = pos;
		return;
	}

	//其余情况
	BSTLNode* pevr = pos->pevr;
	BSTLNode* ppevr = pevr->pevr;
	pevr->pevr = NULL;
	pevr->next = NULL;
	free(pevr);
	pevr = NULL;
	ppevr->next = pos;
	pos->pevr = ppevr;
}

//在pos位置后插入
void BSTLInsertAfter(BSTLNode* pos, DataType x)
{
	//pos不能为空
	assert(pos);

	//申请节点
	BSTLNode* newnode = BSTLSpace(x);

	//插入
	BSTLNode* cur = pos->next;
	pos->next = newnode;
	newnode->pevr = pos;
	newnode->next = cur;
	cur->pevr = newnode;
}

//在pos位置后删除
void BSTLEraseAfter(BSTLNode* pos)
{
	//pos不能为空,为空则不能删除
	assert(pos);
	//pos后一个为NULL 也不能删除
	assert(pos->next);

	//删除
	BSTLNode* cur = pos->next;
	BSTLNode* next = pos->next->next;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pos->next = next;
	//若next不为空则将前一个链接到pos
	if (next != NULL)
	{
		next->pevr = pos;
	}
}



int main()
{
	BSTLNode* sl = NULL;

	BSTLPushFront(&sl, 1);
	BSTLPushFront(&sl, 2);
	BSTLPushFront(&sl, 3);
	BSTLPrint(sl);//打印

	BSTLPopFront(&sl);
	BSTLPopFront(&sl);
	BSTLPopFront(&sl);
	BSTLPrint(sl);//打印

	BSTLPushBank(&sl, 5);
	BSTLPushBank(&sl, 6);
	BSTLPushBank(&sl, 7);
	BSTLPrint(sl);//打印

	BSTLPopBank(&sl);
	BSTLPopBank(&sl);
	BSTLPrint(sl);//打印

	BSTLNode* ret = BSTLFind(&sl, 5);
	printf("%d\n", ret->data);

	BSTLInsert(&sl, ret, 9);
	BSTLInsert(&sl, NULL, 8);
	BSTLInsert(&sl, sl, 7);
	BSTLPrint(sl);//打印

	BSTLErase(&sl, ret);
	BSTLPrint(sl);//打印
	//BSTLErase(&sl, NULL);
	BSTLErase(&sl, sl);
	BSTLPrint(sl);//打印

	BSTLInsertAfter(ret, 89);
	BSTLPrint(sl);//打印
	//BSTLInsertAfter(NULL, 89);
	BSTLInsertAfter(ret->pevr, 89);
	BSTLPrint(sl);//打印

	BSTLEraseAfter(ret);
	BSTLPrint(sl);//打印
	BSTLEraseAfter(ret->pevr);
	BSTLPrint(sl);//打印
	//BSTLEraseAfter(NULL);
	BSTLPrint(sl);//打印
	BSTLEraseAfter(sl);
	BSTLPrint(sl);//打印

	BSTLEraseAfter(sl);
	BSTLPrint(sl);//打印
	//BSTLEraseAfter(sl);
	BSTLPrint(sl);//打印


	return 0;
}

双向带头链表

节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针,且会单独开辟一个节点空间用来做哨兵位的头节点,一般哨兵位的头节点不存放有效数据。

代码:

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int DataType;
//创建结构
typedef struct BHSTLNode
{
	DataType data;
	struct BHSTLNode* pevr;
	struct BHSTLNode* next;
}BHSTLNode;


//初始化(创建带哨兵位的头节点)
void BHSTLInit(BHSTLNode** pphead, DataType x)
{
	BHSTLNode* cur = (BHSTLNode*)malloc(sizeof(BHSTLNode));
	if (cur == NULL)
	{
		perror("malloc fail");
		return;
	}
	//开辟成功,进行赋值
	cur->data = x;
	cur->next = NULL;
	cur->pevr = NULL;
	*pphead = cur;
}

//创建节点(开辟空间)
BHSTLNode* BHSTLSpace(DataType x)
{
	BHSTLNode* newnode = (BHSTLNode*)malloc(sizeof(BHSTLNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

	newnode->data = x;
	newnode->next = NULL;
	newnode->pevr = NULL;
	return newnode;
}

//打印
void BHSTLPrint(BHSTLNode* phead)
{
	BHSTLNode* cur = phead;
	while (cur)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//头插
void BHSTLPushFront(BHSTLNode** pphead, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//创建节点
	BHSTLNode* newnode = BHSTLSpace(x);

	//进行插入
	BHSTLNode* cur = (*pphead)->next;
	(*pphead)->next = newnode;
	newnode->pevr = (*pphead);
	newnode->next = cur;
	if (cur != NULL)
	{
		cur->pevr = newnode;
	}
}

//头删
void BHSTLPopFront(BHSTLNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//头节点的下一个节点为NULL不可删除
	assert((*pphead)->next);

	//进行删除
	BHSTLNode* head = (*pphead)->next;
	BHSTLNode* cur = head->next;
	head->next = NULL;
	head->pevr = NULL;
	free(head);
	head = NULL;
	(*pphead)->next = cur;
	if (cur != NULL)
	{
		cur->pevr = (*pphead);
	}
}

//尾插
void BHSTLPushBank(BHSTLNode** pphead, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//创建节点
	BHSTLNode* newnode = BHSTLSpace(x);

	//找尾进行插入
	BHSTLNode* cur = *pphead;
	while (cur->next)
	{
		cur = cur->next;
	}
	cur->next = newnode;
	newnode->pevr = cur;
	newnode->next = NULL;
}

//尾删
void BHSTLPopBank(BHSTLNode** pphead)
{
	//带哨兵位的头节点不能为空
	assert(pphead);
	assert(*pphead);
	//只有哨兵位的头节点一个节点的时候不能删除
	assert((*pphead)->next);

	//找尾删除
	BHSTLNode* cur = *pphead;
	while (cur->next)
	{
		cur = cur->next;
	}
	BHSTLNode* pevr = cur->pevr;
	cur->pevr = NULL;
	cur->next = NULL;
	free(cur);
	cur = NULL;
	pevr->next = NULL;
}

//查找
BHSTLNode* BHSTLFind(BHSTLNode** pphead, DataType x)
{
	//带哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	BHSTLNode* cur = (*pphead)->next;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos位置前插入
void BHSTLInsert(BHSTLNode** pphead, BHSTLNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(*pphead);
	assert(pphead);

	//pos不能为哨兵位的头节点
	if (pos == (*pphead))
	{
		perror("pos == (*pphead)");
		return;
	}

	//pos为空的情况就是尾插
	if (pos == NULL)
	{
		BHSTLPushBank(pphead, x);
		return;
	}

	//获取节点
	BHSTLNode* newnode = BHSTLSpace(x);

	//其余情况
	BHSTLNode* pevr = pos->pevr;
	pevr->next = newnode;
	newnode->pevr = pevr;
	newnode->next = pos;
	pos->pevr = newnode;
}

//在pos位置前删除
void BHSTLErase(BHSTLNode** pphead, BHSTLNode* pos)
{
	//哨兵位的头节点
	assert(pphead);
	assert(*pphead);
	//仅有哨兵位头节点一个节点时不可删除
	assert((*pphead)->next);

	//pos的前一个节点为头节点则不能删除
	if (pos->pevr == (*pphead))
	{
		perror("pos->pevr == (*pphead)");
		return;
	}

	//pos为哨兵位的头节点则不能删除前面的
	if (pos == (*pphead))
	{
		perror("pos == (*pphead)");
		exit;
	}

	//pos为哨兵位头节点的下一个节点则不能删除前一个节点
	if (pos == (*pphead)->next)
	{
		perror("pos == (*pphead)->next");
		return;
	}

	//pos为NULL就是尾删
	if (pos == NULL)
	{
		BHSTLPopBank(pphead);
		return;
	}

	//其余情况
	BHSTLNode* pevr = pos->pevr;
	BHSTLNode* ppevr = pevr->pevr;
	pevr->next = NULL;
	pevr->pevr = NULL;
	free(pevr);
	ppevr->next = pos;
}

//在pos位置后插入
void BHSTLInsertAfter(BHSTLNode* pos, DataType x)
{
	//pos为空不能插入
	assert(pos);

	//创建节点
	BHSTLNode* newnode = BHSTLSpace(x);

	//直接插入
	BHSTLNode* cur = pos->next;
	pos->next = newnode;
	newnode->next = cur;
	newnode->pevr = pos;

}

//在pos位置后删除
void BHSTLEraseAfter(BHSTLNode* pos)
{
	//pos不能为空,为空则不能删除
	assert(pos);
	//pos的下一个为NULL,则不能删除
	assert(pos->next);

	//进行删除
	BHSTLNode* cur = pos->next;
	BHSTLNode* next = pos->next->next;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pos->next = next;
	if (next != NULL)
	{
		next->pevr = pos;
	}
}

//销毁
void BHSTLDestroy(BHSTLNode** pphead)
{
	//哨兵位的头节点不能为NULL
	assert(pphead);
	assert(*pphead);

	//循环遍历销毁
	BHSTLNode* cur = *pphead;
	BHSTLNode* next = *pphead;
	while (cur)
	{
		next = cur - next;
		cur->next = NULL;
		cur->pevr = NULL;
		cur->data = 0;
		free(cur);
		cur = next;;
	}
	*pphead = NULL;
}


int main()
{
	BHSTLNode* sl;
	//头节点
	BHSTLInit(&sl, 0);
	BHSTLPrint(sl);//打印

	//头插
	BHSTLPushFront(&sl, 1);
	BHSTLPushFront(&sl, 2);
	BHSTLPushFront(&sl, 3);
	BHSTLPrint(sl);//打印

	//头删
	BHSTLPopFront(&sl);
	BHSTLPrint(sl);//打印
	BHSTLPopFront(&sl);
	BHSTLPrint(sl);//打印	
	BHSTLPopFront(&sl);
	BHSTLPrint(sl);//打印

	//尾插
	BHSTLPushBank(&sl, 6);
	BHSTLPushBank(&sl, 7);
	BHSTLPushBank(&sl, 8);
	BHSTLPrint(sl);//打印

	//尾删
	BHSTLPopBank(&sl);
	BHSTLPrint(sl);//打印
	BHSTLPopBank(&sl);
	BHSTLPrint(sl);//打印
	//BHSTLPopBank(&sl);
	//BHSTLPrint(sl);//打印
	//BHSTLPopBank(&sl);
	//BHSTLPrint(sl);//打印

	//查找
	BHSTLNode* ret = BHSTLFind(&sl, 6);
	printf("%d\n", ret->data);

	//在pos位置前插入
	BHSTLInsert(&sl, ret, 9);
	BHSTLPrint(sl);//打印
	BHSTLInsert(&sl, ret->pevr, 10);
	BHSTLPrint(sl);//打印

	//在pos位置前删除
	BHSTLErase(&sl, ret);
	BHSTLPrint(sl);//打印
	//BHSTLErase(&sl, ret->pevr);
	//BHSTLPrint(sl);//打印




	return 0;
}

双向循环链表

节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针,且尾节点中指向下一个节点的指针存放的是头节点的地址,头节点中的指向前一个节点的指针存放的是尾节点的地址。

代码:

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int DataType;

//创建结构
typedef struct BPLSTNode
{
	DataType data;
	struct BPLSTNode* pevr;
	struct BPLSTNode* next;
}BPLSTNode;


//创建节点
BPLSTNode* BPLSTSpace(DataType x)
{
	//开辟空间
	BPLSTNode* newnode = (BPLSTNode*)malloc(sizeof(BPLSTNode));
	//判断是否开辟成功
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	//开辟成功进行初始化
	newnode->data = x;
	newnode->next = NULL;
	newnode->pevr = NULL;
	return newnode;
}

//打印
void BPLSTPrint(BPLSTNode* head)
{
	if (head == NULL)
	{
		printf("NULL\n");
		return;
	}

	printf("%d->", head->data);
	BPLSTNode* cur = head->next;
	//仅有一个节点的情况
	//两个及多个的情况
	while (cur != head)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("head\n");
}

//头插
void BPLSTPushFront(BPLSTNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);

	//获取节点
	BPLSTNode* newnode = BPLSTSpace(x);
	//为空的情况下直接插入
	if ((*pphead) == NULL)
	{
		newnode->next = newnode;
		newnode->pevr = newnode;
		*pphead = newnode;
		return;
	}

	//存在节点的情况下
	BPLSTNode* cur = *pphead;
	BPLSTNode* tail = (*pphead)->pevr;
	newnode->next = cur;
	cur->pevr = newnode;
	newnode->pevr = tail;
	tail->next = newnode;
	*pphead = newnode;
}

//头删
void BPLSTPopFront(BPLSTNode** pphead)
{
	//为空的情况下不能删除
	assert(pphead);
	assert(*pphead);

	//不为空的情况下进行删除
	//仅有头节点一个节点的情况下。
	if ((*pphead)->next == (*pphead))
	{
		(*pphead)->next = NULL;
		(*pphead)->pevr = NULL;
		free(*pphead);
		*pphead = NULL;
		return;
	}

	//两个及多个节点的情况
	BPLSTNode* tail = (*pphead)->pevr;
	BPLSTNode* cur = *pphead;
	BPLSTNode* next = (*pphead)->next;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	tail->next = next;
	next->pevr = tail;
	*pphead = next;
}

//尾插
void BPLSTPushBank(BPLSTNode** pphead, DataType x)
{
	//断言指针
	assert(pphead);

	//获取节点
	BPLSTNode* newnode = BPLSTSpace(x);

	//无节点的情况下直接插入
	if ((*pphead) == NULL)
	{
		newnode->next = newnode;
		newnode->pevr = newnode;
		*pphead = newnode;
		return;
	}

	//存在节点的情况
	//尾部直接插入
	BPLSTNode* tail = (*pphead)->pevr;
	BPLSTNode* cur = *pphead;
	tail->next = newnode;
	newnode->pevr = tail;
	newnode->next = cur;
	cur->pevr = newnode;
}

//尾删
void BPLSTPopBank(BPLSTNode** pphead)
{
	//无节点的情况下不能删除
	assert(pphead);
	assert(*pphead);

	//只有头节点一个节点的情况下
	//直接释放处理
	if ((*pphead)->next == (*pphead))
	{
		(*pphead)->next = NULL;
		(*pphead)->pevr = NULL;
		free(*pphead);
		(*pphead) = NULL;
		return;
	}

	//有两个或两个以上节点的情况下进行找尾。
	BPLSTNode* cur = *pphead;
	BPLSTNode* pevr = *pphead;
	while (cur->next != (*pphead))
	{
		pevr = cur;
		cur = cur->next;
	}
	//进行释放链接
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pevr->next = (*pphead);
	(*pphead)->pevr = pevr;
}

//查找
BPLSTNode* BPLSTFand(BPLSTNode** pphead, DataType x)
{
	//没有节点的情况无法插入
	assert(pphead);
	assert(*pphead);

	//存在节点的情况下遍历查找
	if ((*pphead)->data == x)
	{
		return (*pphead);
	}
	BPLSTNode* cur = (*pphead)->next;
	while (cur != (*pphead))
	{
		if (cur->data == x)
		{
			return cur;
		}
	}
	return NULL;
}

//在pos位置前插入
void BPLSTInsert(BPLSTNode** pphead, BPLSTNode* pos, DataType x)
{
	//断言指针
	assert(pphead);

	//获取节点
	BPLSTNode* newnode = BPLSTSpace(x);

	//无节点的情况下且pos为NULL就是头插
	if ((*pphead) == NULL)
	{
		if (pos == NULL)
		{
			//头插
			BPLSTPushFront(pphead, x);
		}
		else
		{
			perror((*pphead) == NULL && pos != NULL);
		}
		return;
	}
	//存在节点的情况(头不为NULL的情况)
	if ((*pphead) != NULL && pos == NULL)
	{
		perror((*pphead) != NULL && pos == NULL);
		return;
	}

	//正常可以插入的情况
	//pos为头节点的情况下
	if ((*pphead) == pos)
	{
		//就是头插
		BPLSTPushFront(pphead, x);
		return;
	}

	//pos不为头的情况
	BPLSTNode* cur = *pphead;
	BPLSTNode* pevr = *pphead;
	while (cur != pos)
	{
		pevr = cur;
		cur = cur->next;
	}
	//插入并链接
	pevr->next = newnode;
	newnode->pevr = pevr;
	newnode->next = pos;
	pos->pevr = newnode;
}

//在pos位置前删除
void BPLSTEaser(BPLSTNode** pphead, BPLSTNode* pos)
{
	//无节点的情况下皆不可删除
	assert(pphead);
	assert(*pphead);
	//pos为空不能删除
	assert(pos);

	//查找pos是否是该链表中的节点
	//……………………省略………………

	//若pos为头节点
	if ((*pphead) == pos)
	{
		//进行尾删
		BPLSTPopBank(pphead);
		return;
	}

	//pos不为头节点的情况

	//pos是头节点的下一个节点的情况
	if ((*pphead)->next == pos)
	{
		//直接删除头
		BPLSTNode* pevr = (*pphead)->pevr;
		(*pphead)->next = NULL;
		(*pphead)->pevr = NULL;
		free(*pphead);
		pos->pevr = pevr;
		pevr->next = pos;
		*pphead = pos;
		return;
	}

	//pos即不为头节点也不是头节点的下一个节点的情况
	BPLSTNode* cur = *pphead;
	BPLSTNode* pevr = cur->pevr;

	//循环遍历找pos
	while (cur->next != pos)
	{
		pevr = cur;
		cur = cur->next;
	}
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pevr->next = pos;
	pos->pevr = pevr;
}

//在pos位置后插入
void BPLSTInsertAfter(BPLSTNode** pphead, BPLSTNode* pos, DataType x)
{
	//断言指针
	assert(pphead);
	//不存在节点的情况
	if ((*pphead) == NULL)
	{
		//pos为空的情况
		if (pos == NULL)
		{
			//尾插
			BPLSTPushBank(pphead, x);
		}
		else //pos不为空的情况
		{
			//无法插入,直接断言
			assert(pos);
		}
		return;
	}

	//存在节点的情况
		//pos为NULL 无法插入
	if (pos == NULL)
	{
		assert(pos);
		return;
	}
	//pos不为NULL的情况

	 //获取节点
	BPLSTNode* newnode = BPLSTSpace(x);
	//进行插入链接
	BPLSTNode* next = pos->next;
	pos->next = newnode;
	newnode->pevr = pos;
	newnode->next = next;
	next->pevr = newnode;
}

//在pos位置后删除
void BPLSTEaserAfter(BPLSTNode** pphead, BPLSTNode* pos)
{
	//不存在节点无法删除
	assert(pphead);
	assert(*pphead);
	//pos为空无法删除
	assert(pos);

	//pos为头节点
	if (pos == (*pphead))
	{
		//仅有头节点一个节点的情况
		if ((*pphead)->next == (*pphead))
		{
			(*pphead)->next = NULL;
			(*pphead)->pevr = NULL;
			free(*pphead);
			*pphead = NULL;
		}
		else
		{
			BPLSTNode* cur = pos->next;
			BPLSTNode* next = cur->next;
			cur->next = NULL;
			cur->pevr = NULL;
			free(cur);
			cur = NULL;
			pos->next = next;
			next->pevr = pos;
		}
		return;
	}

	//pos为尾节点的情况
	if (pos == (*pphead)->pevr)
	{
		//仅有pos和头节点两个节点的情况
		if ((*pphead)->next == pos)
		{
			(*pphead)->next = NULL;
			(*pphead)->pevr = NULL;
			free(*pphead);
			pos->next = pos;
			pos->pevr = pos;
			*pphead = pos;
		}
		else//具有三个节点的情况,且头节点的下一个节点不是pos
		{
			BPLSTNode* cur = pos->next;
			BPLSTNode* next = cur->next;
			cur->next = NULL;
			cur->pevr = NULL;
			free(cur);
			cur = NULL;
			pos->next = next;
			next->pevr = pos;
			*pphead = next;
		}
		return;
	}

	//pos不为尾的情况
	BPLSTNode* cur = pos->next;
	BPLSTNode* next = cur->next;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pos->next = next;
	next->pevr = pos;
}

int main()
{
	BPLSTNode* sl = NULL;
	//头插
	BPLSTPushFront(&sl, 1);
	BPLSTPushFront(&sl, 2);
	BPLSTPushFront(&sl, 3);
	BPLSTPrint(sl);//打印

	//头删
	BPLSTPopFront(&sl);
	BPLSTPopFront(&sl);
	BPLSTPrint(sl);//打印

	//尾插
	BPLSTPushBank(&sl, 5);
	BPLSTPushBank(&sl, 6);
	BPLSTPushBank(&sl, 7);
	BPLSTPrint(sl);//打印

	//尾删
	BPLSTPopBank(&sl);
	BPLSTPopBank(&sl);
	BPLSTPopBank(&sl);
	BPLSTPrint(sl);//打印

	//查找
	BPLSTNode* ret = BPLSTFand(&sl, 1);
	if (ret != NULL) printf("%d\n", ret->data);
	else printf("ret==NULL\n");

	//在pos位置前插入
	BPLSTInsert(&sl, ret, 5);
	BPLSTInsert(&sl, ret->pevr, 6);
	BPLSTPrint(sl);//打印

	//在pos位置前删除
	BPLSTEaser(&sl, ret->next);
	BPLSTPrint(sl);//打印

	ret = BPLSTFand(&sl, 5);
	if (ret != NULL) printf("%d\n", ret->data);
	else printf("ret==NULL\n");

	//在pos位置后插入
	BPLSTInsertAfter(&sl, ret, 7);
	BPLSTInsertAfter(&sl, ret, 8);
	BPLSTPrint(sl);//打印

	//在pos位置后删除
	BPLSTEaserAfter(&sl, ret);
	BPLSTPrint(sl);//打印

	ret = BPLSTFand(&sl, 6);
	if (ret != NULL) printf("%d\n", ret->data);
	else printf("ret==NULL\n");

	//在pos位置后删除
	BPLSTEaserAfter(&sl, ret);
	BPLSTPrint(sl);//打印
	BPLSTEaserAfter(&sl, ret);
	BPLSTPrint(sl);//打印
	BPLSTEaserAfter(&sl, ret);
	BPLSTPrint(sl);//打印
	return 0;
}

双向带头循环链表

节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针,会单独开辟一个节点空间用来做哨兵位的头节点,一般哨兵位头节点中不存放有效数据,且尾节点中指向下一个节点的指针存放的是哨兵位头节点的地址,哨兵位头节点中的指向前一个节点的指针存放的是尾节点的地址。

代码:

#define _CRT_DECURE_NO_WARNINGS 1

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

//创建结构
typedef int DataType;

typedef struct BHPSTLNode
{
	DataType data;
	struct BHPSTLNode* pevr;
	struct BHPSTLNode* next;
}BHPSTLNode;


//初始化哨兵位头节点
void BHPSTLInit(BHPSTLNode** pphead, DataType x)
{
	//申请空间
	BHPSTLNode* newnode = (BHPSTLNode*)malloc(sizeof(BHPSTLNode));
	if (newnode == NULL)
	{
		perror("malloc fail 12link");
		return;
	}
	//申请成功后进行赋值
	newnode->next = newnode;
	newnode->pevr = newnode;
	newnode->data = x;
	*pphead = newnode;
}

//打印
void BHPSTLPrint(BHPSTLNode* phead)
{
	//空链表直接打印
	if (phead == NULL)
	{
		printf("NULL\n");
		return;
	}

	//打印哨兵位的头节点
	printf("%d->", phead->data);

	BHPSTLNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("phead\n");
}

//创建节点
BHPSTLNode* BHPSTLSpace(DataType x)
{
	//创建节点
	BHPSTLNode* newnode = (BHPSTLNode*)malloc(sizeof(BHPSTLNode));
	if (newnode == NULL)
	{
		perror("malloc fail 51 link");
		return NULL;
	}
	//创建成功进行链接
	newnode->data = x;
	newnode->next = NULL;
	newnode->pevr = NULL;
	return newnode;
}

//头插
void BHPSTLPushFront(BHPSTLNode** pphead, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//创建节点
	BHPSTLNode* newnode = BHPSTLSpace(x);

	//直接进行插入
	BHPSTLNode* next = (*pphead)->next;
	(*pphead)->next = newnode;
	newnode->pevr = (*pphead);
	newnode->next = next;
	next->pevr = newnode;
}

//头删
void BHPSTLPopFront(BHPSTLNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//仅有哨兵位的头节点一个节点不能删除
	if ((*pphead)->pevr == (*pphead))
	{
		assert(NULL);
	}

	//具有两个及多个节点的情况
	//进行删除
	BHPSTLNode* cur = (*pphead)->next;
	BHPSTLNode* next = cur->next;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	(*pphead)->next = next;
	next->pevr = (*pphead);
}

//尾插
void BHPSTLPushBank(BHPSTLNode** pphead, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//创建节点
	BHPSTLNode* newnode = BHPSTLSpace(x);

	//找尾
	BHPSTLNode* tail = (*pphead)->pevr;
	//插入
	tail->next = newnode;
	newnode->pevr = tail;
	newnode->next = (*pphead);
	(*pphead)->pevr = newnode;
}

//尾删
void BHPSTLPopBank(BHPSTLNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//仅有哨兵位的头节点一个节点无法删除
	if ((*pphead)->next == (*pphead))
	{
		assert(NULL);
	}

	//找尾和尾的前一个释放链接
	BHPSTLNode* tail = (*pphead)->pevr;
	BHPSTLNode* pevr = tail->pevr;
	tail->next = NULL;
	tail->pevr = NULL;
	free(tail);
	tail = NULL;
	pevr->next = (*pphead);
	(*pphead)->pevr = pevr;
}

//查找
BHPSTLNode* BHPSTLFind(BHPSTLNode* phead, DataType x)
{
	//断言指针
	assert(phead);

	//循环遍历查找
	BHPSTLNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos位置前插入
void BHPSTLInsert(BHPSTLNode** pphead, BHPSTLNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//若pos为空无法插入
	assert(pos);

	//判断pos是否存在于该链表中
	//………… 省略 …………

	//获取节点
	BHPSTLNode* newnode = BHPSTLSpace(x);

	BHPSTLNode* pevr = pos->pevr;
	pevr->next = newnode;
	newnode->pevr = pevr;
	newnode->next = pos;
	pos->pevr = newnode;
}

//在pos位置前删除
void BHPSTLErase(BHPSTLNode** pphead, BHPSTLNode* pos)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos为空无法删除
	assert(pos);

	//判断pos是否存在于该链表中
	//………… 省略 …………

	//若pos为哨兵位头节点的下一个节点
	//无法删除(即哨兵位的头节点无法删除)
	//若pos为哨兵位的头节点
	//且仅有头节点一个节点的情况无法删除
	if ((*pphead)->next == pos)
	{
		assert(NULL);
		return;
	}

	//其余情况
	BHPSTLNode* cur = pos->pevr;
	BHPSTLNode* pevr = cur->pevr;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pevr->next = pos;
	pos->pevr = pevr;
}

//在pos位置后插入
void BHPSTLInsertAfter(BHPSTLNode** pphead, BHPSTLNode* pos, DataType x)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);
	//pos为空无法插入
	assert(pos);

	//判断pos是否存在于该链表中
	//………… 省略 …………

	//创建节点
	BHPSTLNode* newnode = BHPSTLSpace(x);
	BHPSTLNode* next = pos->next;
	pos->next = newnode;
	newnode->pevr = pos;
	newnode->next = next;
	next->pevr = newnode;
}

//在pos位置后删除
void BHPSTLEraseAfter(BHPSTLNode** pphead, BHPSTLNode* pos)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//pos为NULL不能删除
	assert(pos);

	//判断pos是否存在于该链表中
	//………… 省略 …………

	//若pos为尾节点无法删除
	//(尾节点的下一个节点是哨兵位的头节点)
	//若仅有哨兵位头节点一个节点
	//且pos为哨兵位头节点的情况无法删除
	if (pos->next == (*pphead))
	{
		assert(NULL);
	}

	//其余情况
	BHPSTLNode* cur = pos->next;
	BHPSTLNode* next = cur->next;
	cur->next = NULL;
	cur->pevr = NULL;
	free(cur);
	cur = NULL;
	pos->next = next;
	next->pevr = pos;
}

//销毁
void BHPSTLDestroy(BHPSTLNode** pphead)
{
	//哨兵位的头节点必须存在
	assert(pphead);
	assert(*pphead);

	//循环遍历销毁
	BHPSTLNode* cur = (*pphead)->next;
	BHPSTLNode* next = (*pphead)->next;
	while (cur != (*pphead))
	{
		next = cur->next;
		cur->next = NULL;
		cur->pevr = NULL;
		free(cur);
		cur = next;
	}
	cur->pevr = NULL;
	cur->next = NULL;
	free(cur);
	cur = NULL;
	(*pphead) = NULL;
}

int main()
{
	BHPSTLNode* sl = NULL;
	//初始化哨兵位头节点
	BHPSTLInit(&sl, 0);
	BHPSTLPrint(sl);//打印

	//头插
	BHPSTLPushFront(&sl, 1);
	BHPSTLPushFront(&sl, 2);
	BHPSTLPushFront(&sl, 3);
	BHPSTLPrint(sl);//打印

	//头删
	BHPSTLPopFront(&sl);
	BHPSTLPrint(sl);//打印
	BHPSTLPopFront(&sl);
	BHPSTLPrint(sl);//打印
	BHPSTLPopFront(&sl);
	BHPSTLPrint(sl);//打印

	//尾插
	BHPSTLPushBank(&sl, 5);
	BHPSTLPushBank(&sl, 6);
	BHPSTLPushBank(&sl, 7);
	BHPSTLPrint(sl);//打印

	//尾删
	BHPSTLPopBank(&sl);
	BHPSTLPrint(sl);//打印
	//BHPSTLPopBank(&sl);
	//BHPSTLPrint(sl);//打印
	//BHPSTLPopBank(&sl);
	//BHPSTLPrint(sl);//打印

	//查找
	BHPSTLNode* ret = BHPSTLFind(sl, 6);
	if (ret == NULL) printf("find: NULL\n");
	else printf("Find : %d\n", ret->data);

	//在pos位置前插入
	BHPSTLInsert(&sl, ret, 8);
	BHPSTLPrint(sl);//打印
	BHPSTLInsert(&sl, ret->pevr, 9);
	BHPSTLPrint(sl);//打印
	BHPSTLInsert(&sl, ret->pevr->pevr, 10);
	BHPSTLPrint(sl);//打印

	//在pos位置前删除
	BHPSTLErase(&sl, ret);
	BHPSTLPrint(sl);//打印
	BHPSTLErase(&sl, ret);
	BHPSTLPrint(sl);//打印
	BHPSTLErase(&sl, ret);
	BHPSTLPrint(sl);//打印
	BHPSTLErase(&sl, ret);
	BHPSTLPrint(sl);//打印
	//BHPSTLErase(&sl, sl);
	//BHPSTLPrint(sl);//打印
	//BHPSTLErase(&sl, sl);
	//BHPSTLPrint(sl);//打印

	//在pos位置后插入
	BHPSTLInsertAfter(&sl, ret, 9);
	BHPSTLPrint(sl);//打印
	BHPSTLInsertAfter(&sl, sl, 7);
	BHPSTLPrint(sl);//打印

	//在pos位置后删除
	BHPSTLEraseAfter(&sl, ret);
	BHPSTLPrint(sl);//打印
	//BHPSTLEraseAfter(&sl, ret->pevr);
	//BHPSTLPrint(sl);//打印
	BHPSTLEraseAfter(&sl, sl);
	BHPSTLPrint(sl);//打印
	BHPSTLEraseAfter(&sl, sl);
	BHPSTLPrint(sl);//打印
	//BHPSTLEraseAfter(&sl, sl);
	//BHPSTLPrint(sl);//打印

	//销毁
	BHPSTLDestroy(&sl);
	BHPSTLPrint(sl);//打印

	return 0;
}

以上为自写8种链表代码,各位铁子欢迎讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2243382.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE5 材质里面画圆锯齿严重的问题

直接这么画圆会带来锯齿&#xff0c;我们对锯齿位置进行模糊 可以用smoothstep&#xff0c;做值的平滑过渡&#xff08;虽然不是模糊&#xff0c;但是类似&#xff09;

即插即用的3D神经元注意算法!

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;编程探索专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年11月18日10点39分 神秘男子影, 秘而不宣藏。 泣意深不见, 男子自持重, 子夜独自沉。 论文连接 点击开启你的论文编制之旅…

Mac的Terminal随机主题配置

2024年8月8日 引言 对于使用Mac的朋友&#xff0c;如果你是一个程序员&#xff0c;那肯定会用到Terminal。一般来说Terminal就是一个黑框&#xff0c;但其实Terminal是有10款官方皮肤。 每个都是不一样的主题&#xff0c;颜色和字体都会有所改变。现在就有一个方法可以很平均…

《Probing the 3D Awareness of Visual Foundation Models》论文解析——单图像表面重建

一、论文简介 论文讨论了大规模预训练产生的视觉基础模型在处理任意图像时的强大能力&#xff0c;这些模型不仅能够完成训练任务&#xff0c;其中间表示还对其他视觉任务&#xff08;如检测和分割&#xff09;有用。研究者们提出了一个问题&#xff1a;这些模型是否能够表示物体…

泷羽sec学习打卡-云技术基础1-docker

声明 学习视频来自B站UP主 泷羽sec,如涉及侵权马上删除文章 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 关于云技术基础的那些事儿-Base1 一、云技术基础什么是云架构&#xff1f;什么是云服务&#xff1f;什么…

03-axios常用的请求方法、axios错误处理

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

Spring Boot 与腾讯云 MySQL 监听 Binlog 数据变化,并使用 UI 展示页面效果

引言 在现代的分布式系统和微服务架构中&#xff0c;数据同步和变更监控是保证系统一致性和实时性的核心问题之一。MySQL 数据库的 binlog&#xff08;二进制日志&#xff09;功能能够记录所有对数据库的修改操作&#xff0c;如插入&#xff08;INSERT&#xff09;、更新&…

Spring Boot汽车资讯:科技与速度的新纪元

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了汽车资讯网站的开发全过程。通过分析汽车资讯网站管理的不足&#xff0c;创建了一个计算机管理汽车资讯网站的方案。文章介绍了汽车资讯网站的系统分析部分&…

thinkphp6模板调用URL方法生成的链接异常

var uul params.url ;console.log(params.url);console.log("{:Url(UserLog/index)}");console.log("{:Url("uul")}"); 生成的链接地址 UserLog/index /jjg/index.php/Home/UserLog/index.html /jjg/index.php/Home/Index/UserLog/index.html…

NodeJS 百度智能云文本转语音(实测)

现在文本转语音的技术已经非常完善了&#xff0c;尽管网络上有许多免费的工具&#xff0c;还是测试了专业的服务&#xff0c;选择了百度的TTS服务。 于是&#xff0c;在百度智能云注册和开通了文本转语音的服务&#xff0c;尝试使用NodeJS 实现文本转语音服务。但是百度的文档实…

UML 类图讲解

UML 类图符号含义 在 UML 类图中&#xff0c;每个符号都有其特定的含义。以下是常见符号的解释&#xff1a; : Public&#xff08;公共访问权限&#xff09;-: Private&#xff08;私有访问权限&#xff09;#: Protected&#xff08;受保护访问权限&#xff09;~: Package&…

【GAT】 代码详解 (1) 运行方法【pytorch】可运行版本

GRAPH ATTENTION NETWORKS 代码详解 前言0.引言1. 环境配置2. 代码的运行2.1 报错处理2.2 运行结果展示 3.总结 前言 在前文中&#xff0c;我们已经深入探讨了图卷积神经网络和图注意力网络的理论基础。还没看的同学点这里补习下。接下来&#xff0c;将开启一个新的阶段&#…

远程控制步骤

当远在千里之外的朋友想求助你帮他找到他电脑上的文件、或者是给他安装软件时。但是你给他说了他又找不到&#xff0c;那么这时你就可以通过控制对方的电脑去做一系列的操作。 如何远程控制对方的电脑非常关键。 方法一&#xff08;Windows自带远程桌面功能&#xff09;&#…

C指针之舞——指针探秘之旅

❤博客主页&#xff1a;折枝寄北-CSDN博客 ❤专栏内容&#xff1a;C语言学习专栏https://blog.csdn.net/2303_80170533/category_12794764.html?spm1001.2014.3001.5482 指针基础学习 在之前的博客文章中&#xff0c;简单总结了指针的基础概念 我们知道了指针的概念&#xf…

前端 JS 浅拷贝与深拷贝

目录 一、问题引出 二、浅拷贝 1、通过解构重构实现浅拷贝 三、深拷贝 1、自定义实现深拷贝 2、JSON实现深拷贝 四、总结 一、问题引出 基础类型的数据存放&#xff1a; let a 100let b aconsole.log("a:" a, "b:" b)a 50console.log("a…

72项!湖北省2024年度第二批省级科技计划项目拟立项项目公示!

本期精选 SCI&EI ●IEEE 1区TOP 计算机类&#xff08;含CCF&#xff09;&#xff1b; ●EI快刊&#xff1a;最快1周录用&#xff01; 知网(CNKI)、谷歌学术期刊 ●7天录用-检索&#xff08;100%录用&#xff09;&#xff0c;1周上线&#xff1b; 免费稿件评估 免费匹配…

uniapp微信小程序转发跳转指定页面

onShareAppMessage 是微信小程序中的一个重要函数&#xff0c;用于自定义转发内容。当用户点击右上角的菜单按钮&#xff0c;并选择“转发”时&#xff0c;会触发这个函数。开发者可以在这个函数中返回一个对象&#xff0c;用于定义分享卡片的标题、图片、路径等信息。 使用场…

[N1CTF 2018]eating_cms

打开题目 只有个登录框&#xff0c;其他什么都没有&#xff0c;尝试了一下弱口令&#xff0c;没能成功 尝试访问一下register.php&#xff0c;看看能不能注册个账号 注册页面&#xff0c;随便注册个账号登陆一下 url中感觉是个注入点&#xff0c;尝试使用file伪协议读取一下us…

PMP–一、二、三模、冲刺–分类–5.范围管理–技巧–引导

文章目录 技巧一模5.范围管理--3.定义范围--工具与技术--引导--在研讨会和座谈会中使用引导技能来协调具有不同期望或不同专业知识的关键干系人&#xff0c;使他们就项目可交付成果以及项目和产品边界达成跨职能的共识。引导&#xff1a;题干关键词 “需求不同、需求差异、需求…