【数据结构初阶】单链表

一、思路

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int SLTdataType;

typedef struct SLTNodelist
{
	SLTdataType data;
	struct SLTNodelist* next;
}SLTNode;

//打印
void SLTPrint(SLTNode* phead);
//尾插
void SLTAddBack(SLTNode** pphead, SLTdataType x);
//尾删
void SLTDelBack(SLTNode** pphead);
//头插
void SLTAddPop(SLTNode** pphead, SLTdataType x);
//头删
void SLTDelPop(SLTNode** pphead);
//查找
SLTNode* SLTFindlist(SLTNode* phead, SLTdataType x);
//指定位置后插入
void SLTAddPoint(SLTNode** pphead, SLTNode* pos, SLTdataType x);
//指定位置后删除
void SLDelPoint(SLTNode** pphead, SLTNode* pos);
//链表的销毁
void SLTDestroy(SLTNode** pphead);


>>>>>>>>>>>>过程<<<<<<<<<<<<<<<

1.打印

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

}

1.这个打印函数需要断言吗?
不需要,即使结构体为空,也能打印,只不过是没有数据而已,这是打印出来的就是空的。如果能打印出来,但是却断言报错,不太合适。

2.怎么打印?
用一个指针cur指向结构体,用while循环打印出来,当cur指向的结构体为空时,停止打印。

3.while的判断条件可以是while(cur->next)吗?
不可以,因为这样最后一个的数据就打印不出来了。

4.在while循环中,让cur指向下一个结构体,可以用cur++吗?
不可以,不同于顺序表,顺序表的数据是存储在一个连续的空间里的,链表它是链接起来的结构体地址。

2.尾插

SLTNode*Buynewnode(SLTDataTap x)
{
	SLTNode*newnode=(SLTNode*)malloc(sizeof(SLTNode));
	if(newnode==NULL)
	{
		perror("malloc failed");
		return NULL;
	}
	newnode->Data=x;
	newnode->next=NULL;

	return newnode;
}
void SLTAddPop(SLTNode**pphead,SLTDataTap x)
{
	//开辟空间
	SLTNode*newnode=Buynewnode(x);
	if(newnode==NULL)
	{
		return;
	}
	//找尾
	//情况一:pphead为空
	if(*pphead==NULL)
	{
		*pphead=newnode;
	}
	//情况二:pphead不为空
	SLTNode*tail=pphead;
	else
	{
		while(tail->next)
		{
			tail=tail->next;
		}
		tail->next=newnode;
	}
}

1.为什么void SLTAddPop(SLTNode**pphead,SLTDataTap)这不能用一级指针接收?

2.怎么进行尾插?
在插入一个数据之前,首先得为这个结构体开辟一个结点,用malloc开辟,由于插入数据时我们都要进行开辟一个结的操作,所以我们可以打包成一个函数SLTNode*Buynewnode(SLTDataTap x)
进行尾插那么就是要找到尾,找尾分两种情况:1. 当*pphead本身为空时,就直接将newnode插入就可以了;2. *pphead本身不为空时,只要找到tail->next为空的,那个就是结构体的尾了
在这里插入图片描述

3.当pphead不为空时,找尾while循环的判断条件可以写成这样tail!=NULL与插入结点时tail=newnode吗?
不可以,因为这样就无法保持链接状态了。

3.尾删

void SLTDelBack(SLTNode**pphead)
{
	assert(*pphead);
	//情况一:只有一个数据
	if((*pphead)->next==NULL)
	{
		free(*pphead);
		*pphead=NULL;
	}
	
	//情况二:不止一个数据
	SLTNode*tail=*pphead;
	SLTNode*pre=*pphead;
	while(tail->next)
	{
		pre=tail;
		tail=tail->next;
	}
	free(tail);
	tail=NULL;
	pre->next=NULL;
}

1.尾删需要断言吗?
需要,因为如果链表为空,是删不了的;
2.尾删的思路
尾删分三种讨论:

1.如果链表为空,删不了,我们这里断言判断一下
2.链表中只有一个数据
3.链表中的数据为一个以上

4.头插

void SLTAddPop(SLTNode** pphead, SLTdataType x)
{
	assert(pphead);
	SLTNode* newnode = Buynewnode(x);
	if (newnode == NULL)
	{
		return;
	}

	newnode->next = *pphead;
	*pphead = newnode;
}

1.头插需要断言吗?
因为pphead永远不能为空,所以要断言;但是当链表为空的时候,可以插入数据,*pphead是不需要断言的。
2.头插的思路
首先先要创建一个结点,将结点的next与链表的第一个指针链接起来。最后要注意把链表的头给改成newnode。

5.头删

void SLTDelPop(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);

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

1.头删需要断言吗?
因为pphead永远不能为空,所以要断言;且空链表不能删除,所以*pphead也需要断言。
2.头删的思路
在这里插入图片描述

6.查找

SLTNode* SLTFindlist(SLTNode* phead, SLTdataType x)
{
	
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

1.查找需要断言吗?
不需要,链表为空就返回NULL;
2.查找的思路
当链表的cur不为空,就继续逐一比对,找到了就返回cur,没找到就指向下一个;直到cur指向空,如果还没找到,就返回NULL;

7.指定位置后插入

void SLTAddPoint(SLTNode** pphead, SLTNode* pos, SLTdataType x)
{
	assert(pos);
	assert(pphead);

	SLTNode* newnode = Buynewnode(x);
	if (newnode == NULL)
	{
		return;
	}
	//
	newnode->next = pos->next;
	pos->next = newnode;
	
}

1.需要断言吗?
因为pphead永远不能为空,所以要断言;指定的位置pos不能为空,所以需要断言;
2.思路
创建一个新结点newnode,然后先让newnode->next = pos->next;让newnode的后面链接起来,在让pos和newnode链接起来pos->next = newnode;;反过来写的话,由于pos->next已经被改了,所以不能是pos与newnode链接,插入就会失败;

8.指定位置后删除

void SLDelPoint(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);
	assert(pphead);
	assert(*pphead);

	if ((*pphead)->next == NULL&&pos->next==NULL)
	{
		return;
	}
	else
	{
		SLTNode* cur = pos->next;
		pos->next = cur->next;
		free(cur);
		cur = NULL;
	}
}

1.需要断言吗?
因为pphead永远不能为空,所以要断言;因为如果链表为空,是删不了的,所以*phead需要断言,指定的位置pos不能为空,所以需要断言;

9.链表的销毁

void SLTDestroy(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SLTNode* cur = *pphead;
	SLTNode* pre = cur;

	while (cur)
	{
		pre = cur->next;
		free(cur);
		cur = pre;
	}
	*pphead = cur;
}

2.思路
结点逐一free,最后记得把*pphead改为最后的cur。

二、整个程序

1.SLTlist.c

#define _CRT_SECURE_NO_WARNINGS 1

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

typedef int SLTdataType;

typedef struct SLTNodelist
{
	SLTdataType data;
	struct SLTNodelist* next;
}SLTNode;

//打印
void SLTPrint(SLTNode* phead);
//尾插
void SLTAddBack(SLTNode** pphead, SLTdataType x);
//尾删
void SLTDelBack(SLTNode** pphead);
//头插
void SLTAddPop(SLTNode** pphead, SLTdataType x);
//头删
void SLTDelPop(SLTNode** pphead);
//查找
SLTNode* SLTFindlist(SLTNode* phead, SLTdataType x);
//指定位置后插入
void SLTAddPoint(SLTNode** pphead, SLTNode* pos, SLTdataType x);
//指定位置后删除
void SLDelPoint(SLTNode** pphead, SLTNode* pos);
//链表的销毁
void SLTDestroy(SLTNode** pphead);

2.SLTlist.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"SLTlist.h"

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

	printf("NULL\n");
}


SLTNode* Buynewnode(SLTdataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

void SLTAddBack(SLTNode** pphead, SLTdataType x)
{
	assert(pphead);
	SLTNode* newnode = Buynewnode(x);
	if (newnode == NULL)
	{
		return;
	}


	//情况1:pphead为空
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	//情况2:pphead不为空
	//找尾
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;

	}
}

void SLTDelBack(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);

	//情况1:链表中只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	//情况2:链表中只有一个节点
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}
		SLTNode* pre = tail->next;
		free(pre);
		tail->next = NULL;
		
	}


}

void SLTAddPop(SLTNode** pphead, SLTdataType x)
{
	assert(pphead);
	SLTNode* newnode = Buynewnode(x);
	if (newnode == NULL)
	{
		return;
	}

	newnode->next = *pphead;
	*pphead = newnode;
}

void SLTDelPop(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);

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

SLTNode* SLTFindlist(SLTNode* phead, SLTdataType x)
{
	
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

void SLTAddPoint(SLTNode** pphead, SLTNode* pos, SLTdataType x)
{
	assert(pos);
	assert(pphead);

	SLTNode* newnode = Buynewnode(x);
	if (newnode == NULL)
	{
		return;
	}
	//
	newnode->next = pos->next;
	pos->next = newnode;
	
}

void SLDelPoint(SLTNode** pphead, SLTNode* pos)
{
	assert(pos);
	assert(pphead);
	assert(*pphead);

	if ((*pphead)->next == NULL&&pos->next==NULL)
	{
		return;
	}
	else
	{
		SLTNode* cur = pos->next;
		pos->next = cur->next;
		free(cur);
		cur = NULL;
	}
}

void SLTDestroy(SLTNode** pphead)
{
	assert(pphead);
	assert(*pphead);
	SLTNode* cur = *pphead;
	SLTNode* pre = cur;

	while (cur)
	{
		pre = cur->next;
		free(cur);
		cur = pre;
	}
	*pphead = cur;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吃不胖的熊猫

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

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

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

打赏作者

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

抵扣说明:

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

余额充值