单链表完整版

实现单链表的头插头删,尾插尾删,中间插入,中间删除,查找

slist.h

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
typedef int slistdate;//对int重命名,只会方便把int改成double或其他数据类型

struct slistnode
{
	slistdate date;//
	struct slistnode*next;//指针地址,指向下一个节点
};
typedef struct slistnode slistnode;//方便写

//可能会改变链表的头指针就传二级指针
void slistpushback(slistnode**pphead, slistdate x);//尾插

void slistpushfront(slistnode**pphead, slistdate x);//头插
//不会改变链表的头指针,就传一级指针
void slistprint(slistnode*phead);

void slistpopback(slistnode**pphead);//尾删
void slistpopfront(slistnode**pphead);//头删

slistnode* slistnodefind(slistnode*pphead, slistdate x);//找某一个节点
void slistinsert(slistnode**pphead, slistnode* pos,slistdate x);//插入一个节点

void slisterase(slistnode**pphead, slistnode* pos, slistdate x);

slist.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include"slist.h"


void slistprint(slistnode*phead)
{
	slistnode*cur = phead;
	while (cur != NULL)//遍历是cur不等于空就往下走,走到尾部还不等于空,走到下一个节点,是空的
	{
		printf("%d->", cur->date);
		cur = cur->next;//cur指向下一个指针
	}
	printf("NULL\n");
}


//开辟节点做的事情很多次,所以直接用一个函数去做开辟节点的事情就可以了

slistnode*buynode(slistdate x)
{
	slistnode*newnode = (slistnode*)malloc(sizeof(slistnode));// 要尾插就要动态开辟一个节点出来
	newnode->date = x;//将newnode初始化
	newnode->next = NULL;//把next赋值为空
	return newnode;
}


void slistpushback(slistnode**pphead, slistdate x)
{
	slistnode*newnode = buynode(x);
	//那么我们这个时候要找尾
	//找到尾节点的指针
	if (*pphead == NULL)
	{
		*pphead = newnode;
}
	else
	{
		slistnode*tail = *pphead;//我们要让tail走到尾部去,而非走到空
		while (tail->next != NULL)
		{
			tail = tail->next;
		}//找到了尾节点,链接新节点
		tail->next=newnode;
	}
	}


void slistpushfront(slistnode**pphead, slistdate x)
{
	//头插
	//也要malloc出来一个节点
	slistnode*newnode = buynode(x);
	newnode->next = *pphead;//指向头节点,随后要让phead存第一个节点的地址
	*pphead = newnode;//phead存入newnode地址,phead作为头节点,就把newnode当作了头节点
}




//尾删要分3种情况分析
//1.没有节点
//2.一个节点
//3.多个节点
void slistpopback(slistnode**pphead)//尾删
{

	//1.想删除就找到那个节点,free掉就可以了,因为都是malloc出来的
	//但是,如果将tail找到了那个尾节点,直接free掉,那么前一个节点的指针就会变成野指针,它的指针仍有存在值,但是没有指向的目标,
	//因此,我们要找到它的前一个节点,再定义一个prev,作为尾节点找到最后一个节点,他的前一个节点
	
	//1.没有节点,即*pphead没有指向,就直接返回不用删除
	if (*pphead == NULL)
	{
		return;
	}
	//只有一个节点
	else if ((*pphead)->next == NULL)//由于*和->的优先级相同,所以为了不报错,就应该把*pphead用括号包含
	{
		//直接free掉8
		free(*pphead);
		*pphead = NULL;//再将*pphead置成空指针,防止它变成野指针
	}
	//有多个节点
	else
	{
		//先定义tail用来找尾,prev找尾前一个节点
		slistnode*tail = *pphead;
		slistnode*prev = NULL;//prev置成空指针
		//找尾节点
		while (tail->next != NULL)
		{
			prev = tail;
			tail = tail->next;
		}
		//此时prev就是尾节点
		free(tail);
		prev->next = NULL;
	}
}


void slistpopfront(slistnode**pphead)//头删
{
	//先保存它下一个指针,next
	slistnode*next = (*pphead)->next;//next保存第二个节点的地址,之后将其作为第一个节点
	//删除头节点
	free(*pphead);
	*pphead = next;
}

slistnode* slistnodefind(slistnode*pphead, slistdate x)//找某一个节点
{
	slistnode*cur = pphead;
	while (cur)
	{
		if (cur->date == x)//找到了要找的数据
		{
			return cur;//就把cur的数据返回
		}
		cur = cur->next;
	}
	return NULL;//找节点,节点是slistnode*的数据,因此返回值也应该要是slistnode*来接收,没找到,就返回空指针
}

void slistinsert(slistnode**pphead, slistnode* pos, slistdate x)//插入一个节点//插入一个节点
	{
		//要插入一个节点,首先就是要先malloc一个节点
	//有头插的可能如果pos指向第一个节点,又要插入一个节点,就相当于头插,
	if (pos == *pphead)
	{
		slistpushfront(pphead, 30);
	}

	slistnode *newnode = buynode(30);
		//pos的前一个节点的next指向newnode,newnode—>next=pos
		//要用一个prev来找到pos的前一个
		slistnode*prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		//找到了
		prev->next = newnode;
		newnode->next = pos;
	}

//删除pos处的位置,要让前一个指向后一个,
void slisterase(slistnode**pphead, slistnode* pos, slistdate x)
{
	slistnode* prev = *pphead;
	//假如pos是在头部,那么就找不到它的前一个

	if (pos == *pphead)
	{
		//相当于头删
		slistpopfront(pphead);
	 }
	//也要找到前一个,前一个的next指向后一个
	else
	{
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

test.c 

#define _CRT_SECURE_NO_WARNINGS 1
#include"slist.h"
//链表的概念及结构
//链表是一种物理存储结构上非连续,非顺序的存储结构,数据元素的逻辑结构是通过链表中的指针来链接


void testslist()
{
	slistnode*plist = NULL;//一开始定义一个指针,但啥都没有,所以先赋值空指针,作为头节点,存入第一个节点的地址
	slistpushback(&plist, 1);//尾插//也要传地址才可以,实参传给形参,形参是实参的临时拷贝
	slistpushback(&plist, 2);
	slistpushback(&plist, 3);
	slistpushback(&plist, 4);
	slistpushfront(&plist, 0);//头插
	slistpopback(&plist);
	slistpopfront(&plist);//头删
	slistnodefind(plist, 3);//找某一个节点
	slistnode*pos = slistnodefind(plist, 3);//把要插入到位置找出来,pos就是现在指向的位置
	if (pos)//pos不等于空才会进入这个里面
	{
		slistinsert(&plist, pos, 32);//在pos指向的位置插入数据为30的节点
	}
	slistnode*p = slistnodefind(plist, 2);
	if (p)
	{
		slisterase(&plist, p, 2);
	}

	slistprint(plist);
}
int main()
{
	//需要定义一个指针指向头部
	testslist();

	return 0;
}

  • 15
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zevin~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值