不带头单向不循环链表的实现

发布时间:2024年01月22日

前言

不带头单向不循环链表是一种数据结构,它由一系列的节点组成,每个节点包含两部分:数据域和指针域。在这种类型的链表中:

  • 不带头(无头结点):意味着链表的第一个节点直接存储数据,并没有一个额外的空节点作为链表的起始点。
  • 单向:表示每个节点只有一个指针域,且该指针仅能指向下一个节点,不能回溯到前一个节点。
  • 不循环:表示链表的最后一个节点并不连接回第一个节点形成闭环。换句话说,最后一个元素的指针域为空(通常用 NULL 或 None 表示),标志着链表结束。

这种类型的数据结构被广泛应用于需要顺序访问、插入或删除操作场景中。例如,在编程语言库、操作系统内核以及算法设计等领域都有大量应用案例。

代码实现

接下来给出不带头单向不循环链表的简单实现ovo

SLTList.h

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

typedef int SLDataType;

//定义节点结构体
typedef struct SListNode
{
	SLDataType data;
	struct SListNode* next;
}SLNode;

//打印链表
void SLPrint(SLNode* phead);

//头部插入
void SLPushFront(SLNode** pphead, SLDataType x);

//尾部插入
void SLPushBack(SLNode** pphead, SLDataType x);

//头部删除
void SLPopFront(SLNode** pphead);

//尾部删除
void SLPopBack(SLNode** pphead);

//查找
SLNode* SLFind(SLNode** pphead, SLDataType x);

//在指定位置之前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x);

//指定位置之后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x);

//删除pos节点
void SLErase(SLNode** pphead, SLNode* pos);

//删除pos之后的节点
void SLEraseAfter(SLNode* pos);

//销毁链表
void SLDestroy(SLNode** pphead);

SLTList.c

#include "SLTlist.h"
void SLPrint(SLNode* phead)
{
	SLNode* pcur = phead;
	while (pcur)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("\n");
}

//创建新节点的函数
SLNode* SLBuyNode(SLDataType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	newnode->next= NULL;
	return newnode;//返回新创建节点的地址
}

//尾插函数
void SLPushBack(SLNode** pphead, SLDataType x)
{
	assert(pphead);//一级指针的地址不能为0
	SLNode* newnode = SLBuyNode(x);
	//链表为空,新节点就作为头节点
	if (*pphead == NULL)
	{
		*pphead = newnode;
		return;
	}

	//链表不为空,要找尾节点
	SLNode* ptail = *pphead;//尾节点初始值为头节点
	while (ptail->next)
	{
		ptail = ptail->next;
	}
	//出了循环后,ptail放的就是尾节点地址
	ptail->next = newnode;
}

//头插函数
void SLPushFront(SLNode** pphead, SLDataType x)
{
	assert(pphead);//一级指针地址不为空
	SLNode* newnode = SLBuyNode(x);
	newnode->next = *pphead;
	*pphead = newnode;
}

//尾删函数
void SLPopBack(SLNode** pphead)
{
	assert(pphead);//一级指针的地址不为空
	assert(*pphead);//链表不能为空
	//链表只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	SLNode* ptail = *pphead;

	SLNode* prev = NULL;
	while(ptail->next)
	{
		prev = ptail;
		ptail = ptail->next;
	}//出循环代表找到了尾节点
	prev->next = NULL;//销毁尾节点
	free(ptail);
	ptail = NULL;
}

//头部删除
void SLPopFront(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SLNode* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

//查找
SLNode* SLFind(SLNode** pphead, SLDataType x)
{
	assert(pphead);
	SLNode* pcur = *pphead;
	while (pcur)
	{
		if (pcur->data == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

//在指定位置之前插入数据
void SLInsert(SLNode** pphead, SLNode* pos, SLDataType x)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);
	SLNode* newnode = SLBuyNode(x);
	//如果pos刚好是头节点,直接调用头插
	if (pos == *pphead)
	{
		SLPushFront(pphead, x);
		return;
	}
	//pos不是头节点,需要找前序节点
	SLNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	//出了循环以后找到了pos的前一个节点
	prev->next = newnode;
	newnode->next = pos;
}

//指定位置之后插入数据
void SLInsertAfter(SLNode* pos, SLDataType x)
{
	assert(pos);
	SLNode* newnode = SLBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}


//删除pos节点
void SLErase(SLNode** pphead, SLNode* pos)
{
	assert(pphead);
	assert(*pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPopFront(pphead);
		return;
	}
	//pos不是头节点,需要去找前序节点
	SLNode* prev = *pphead;
	while (prev->next != pos)
	{
		prev = prev->next;
	}
	prev->next = pos->next;
	free(pos);
	pos = NULL;
}

//删除pos之后的节点
void SLEraseAfter(SLNode* pos)
{
	assert(pos);
	assert(pos->next);
	SLNode* del = pos->next;
	pos->next = pos->next->next;
	free(del);
	del = NULL;
}

//销毁链表
void SLDestroy(SLNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SLNode* pcur = *pphead;
	while (pcur)
	{
		SLNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
}

test.c

#include "SLTlist.h"
int main()
{
	SLNode* plist = NULL;
	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);
	SLPushBack(&plist, 5);
	SLPrint(plist);

	SLPushFront(&plist, 6);
	SLPushFront(&plist, 7);
	SLPrint(plist);

	SLPopBack(&plist);
	SLPopFront(&plist);
	SLPrint(plist);

	SLNode* ret =SLFind(&plist, 1);
	SLInsertAfter(ret, 100);
	SLPrint(plist);

	SLEraseAfter(ret);
	SLPrint(plist);

	SLErase(&plist, ret);
	SLPrint(plist);
	return 0;
}

以上就是该链表的简单实现啦!大家有什么疑惑可以在下方评论或私信我哦~

文章来源:https://blog.csdn.net/W1118_/article/details/135731341
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。