【详细图解加源代码和测试截图】单链表的一系列操作合集

在这里插入图片描述

文章目录

🌟前言

🌟SList.h头文件
🌟SList.c文件
🌟text.c测试文件
🌟部分测试截图


🌟前言

单链表虽然不经常使用,但是在找offer的时候很多面试笔试考试都有考单链表的一些操作,虽然本章不直接涉及笔试考题,但都是做单链表考题的基础,很多考题就是在基础上进行变形
所以想找offer学会单链表的基本操作是必不可少的!!

下面我们可以直接看到牛客网和Leecode上单链表的题目就能知道它的重要性

在这里插入图片描述在这里插入图片描述

下面才是本章的重点开始,先简单的看一个我们最终要写的操作功能

功能菜单>

在这里插入图片描述

SList.h为工程头文件(头文件和函数声明)
SList.c为工程的函数实现文件
text.c为工程测试代码文件


🌟单链表建立和初始化

单链表创建有两类型:
第一种是带哨兵位(带头)的链表
第二种是不带哨兵位(不带头)的
在这里插入图片描述

带头的链表在函数传参时比较方便
不带头的话函数传参时如果函数没有返回就要修改链表是要传二级指针的,下面所有涉及链表的修改都需要传二级指针,像打印,查找这些不用修改链表的就不用传二级指针
下面图示先带你回忆一下传值和传址的区别,为后文传二级指针做好准备

在这里插入图片描述在这里插入图片描述

本章使用的是不带哨兵位的链表

单链表节点创建>

typedef int SLDateType;
typedef struct SList
{
	SLDateType data;
	struct SList* next;
}SLNode;

无哨兵位初始化就直接将结构体值空即可

SLNode* list=NULL


🌟尾插和尾删

尾插:唯一要注意的就是链表为空时的尾插方式
代码实现>

//尾插
void SListPushBack(SLNode** pphead,SLDateType x)
{
	//创建新节点
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	newnode->next = NULL;

	SLNode* tail = *pphead;
	//如果链表为空,则直接把新的节点给pphead
	if (*pphead==NULL)
	{
		*pphead = newnode;
	}
	else
	{	//找尾
		while (tail->next)
		{
			tail = tail->next;
		}
		
		tail->next = newnode;
	}

}

尾删:要注意的是删之前要把要删的前一个节点地址保存下来,因为单链表无法找到前一个节点,就无法将前一个节点的next置空,这就是为什么往后引出了双链表的原因
代码实现>

//尾删
void SListPopBack(SLNode** pphead)
{
	SLNode* tail = *pphead;
	//prev用来记录tail的前一个节点
	SLNode* prev = NULL;
	//只有一个节点的时候
	if (tail->next==NULL)
	{
		free(tail);
		*pphead = prev;
	}
	//两个及两个以上的节点
	else
	{
		//找尾节点
		while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
		//释放尾节点
		free(tail);
		//尾节点前一个节点的next置空
		prev->next = NULL;
	}
}


🌟头插和头删

头插:只需把pphead指向newNode,然后把newNode->next指向原来的头即可,注意的是把pphead指向新节点的前要用cur来存储原来头结点的地址

图示>在这里插入图片描述

代码实现>

//头插
void SListPushFront(SLNode** pphead, SLDateType x)
{
	//cur记录头节点位置
	SLNode* cur = *pphead;
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	//新节点的next指向头节点
	newnode->next = cur;
	//newnode作为新的头节点
	*pphead = newnode;
}

头删 :头删先也是要把下一个节点地址存储起来,然后free掉头结点,最后把pphead指向下一个节点

图示>在这里插入图片描述

代码实现>

//头删
void SListPopFront(SLNode** pphead)
{
	//链表为空就报错
	assert((*pphead) != NULL);
	SLNode* cur = *pphead;
	SLNode* latter = cur->next;	//用latter存储头结点的后一个节点
	free(cur);
	*pphead = latter;	//设置新头节点
}



🌟查找

查找的话,只能遍历链表,我这里就定义成:找到返回x地址,找不到返回NULL

查找功能是和接下来要介绍的插入功能进行搭配使用的

代码实现>

//查找,找到返回x地址,找不到返回NULL
SLNode* SListFind(SLNode* plist, SLDateType x)
{
	SLNode* cur = plist;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}


🌟插入

插入 :我这定义的是传链表pos节点的指针,然后再它后面插入(当然你也可以自行定义成其他方式)

我这样传指针定义是为了能与查找功能搭配使用,把查找出来的pos位置可以直接传给插入函数,搭配性比较高

在这里插入图片描述

//在pos位置后面插入
void SListInsertAfter(SLNode* pos, SLDateType x)
{
	assert(pos != NULL);
	//创建新节点
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	newnode->next = NULL;
	//在pos后插入
	SLNode* tem = pos->next;
		pos->next = newnode;
		newnode->next = tem;

}

🌟打印链表

打印链表没有坑,单链表的尾标志就是NULL,直接看代码

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


🌟删除和销毁链表

删除要注意的是要删pos下一个结点, 所以要把pos下一个节点的下一个节点存储起来防止链表断开

//删除pos位置后一个
void SListEraseAfter(SLNode* pos)
{
	//判断要删的节点是否为空,为空就报错
	assert(pos->next != NULL);
	//存储下一个节点地址
	SLNode* latterTwo = pos->next->next;
	free(pos->next);
	pos->next = latterTwo;

}

销毁就迭代往后逐个释放内存即可
代码实现>

销毁链表
void SListDestroy(SLNode** pphead)
{
	SLNode* cur = *pphead;
	while (cur)
	{
		cur = cur->next;
		free(*pphead);
		*pphead = cur;
	}
}



在这里插入图片描述


🌟SList.h头文件

SList.h为工程头文件(头文件和函数声明)
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>

typedef int SLDateType;
typedef struct SList
{
	SLDateType data;
	struct SList* next;
}SLNode;


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

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

//尾插
void SListPushBack(SLNode** pphead,SLDateType x);

//尾删
void SListPopBack(SLNode** pphead);

//头插
void SListPushFront(SLNode** pphead, SLDateType x);

//头删
void SListPopFront(SLNode** pphead);

//查找,找到了返回x地址,找不到返回NULL
SLNode* SListFind(SLNode* plist, SLDateType x);

//在pos位置后面插入
void SListInsertAfter(SLNode* pos, SLDateType x);

//删除pos位置后一个
void SListEraseAfter(SLNode* pos);

🌟SList.c

SList.c为工程的函数实现文件
#define _CRT_SECURE_NO_WARNINGS
#include"SList.h"

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


//销毁链表
void SListDestroy(SLNode** pphead)
{
	SLNode* cur = *pphead;
	while (cur)
	{
		cur = cur->next;
		free(*pphead);
		*pphead = cur;
	}
}


//尾插
void SListPushBack(SLNode** pphead,SLDateType x)
{
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	newnode->next = NULL;

	SLNode* tail = *pphead;
	//如果链表为空,则直接把新的节点给pphead
	if (*pphead==NULL)
	{
		*pphead = newnode;
	}
	else
	{	
		while (tail->next)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}

}


//尾删
void SListPopBack(SLNode** pphead)
{
	SLNode* tail = *pphead;
	//prev用来记录tail的前一个节点
	SLNode* prev = NULL;
	//只有一个节点的时候
	if (tail->next==NULL)
	{
		free(tail);
		*pphead = prev;
	}
	//两个及两个以上的节点
	else
	{
		//找尾节点
		while (tail->next)
		{
			prev = tail;
			tail = tail->next;
		}
		//释放尾节点
		free(tail);
		//尾节点前一个节点的next置空
		prev->next = NULL;
	}
}


//头插
void SListPushFront(SLNode** pphead, SLDateType x)
{
	//cur记录头节点位置
	SLNode* cur = *pphead;
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	//新节点的next指向头节点
	newnode->next = cur;
	//newnode作为新的头节点
	*pphead = newnode;
}


//头删
void SListPopFront(SLNode** pphead)
{
	//链表为空就报错
	assert((*pphead) != NULL);
	SLNode* cur = *pphead;
	SLNode* latter = cur->next;	//用latter存储头结点的后一个节点
	free(cur);
	*pphead = latter;	//设置新头节点
}


//查找,找到返回x地址,找不到返回NULL
SLNode* SListFind(SLNode* plist, SLDateType x)
{
	SLNode* cur = plist;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos位置后面插入
void SListInsertAfter(SLNode* pos, SLDateType x)
{
	assert(pos != NULL);
	//创建新节点
	SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
	newnode->data = x;
	newnode->next = NULL;
	//在pos后插入
	SLNode* tem = pos->next;
		pos->next = newnode;
		newnode->next = tem;

}


//删除pos位置后一个
void SListEraseAfter(SLNode* pos)
{
	//判断要删的节点是否为空,为空就报错
	assert(pos->next != NULL);
	//因为要删pos下一个结点,所以要把pos下一个节点的下一个节点存储起来防止链表断开
	SLNode* latterTwo = pos->next->next;
	free(pos->next);
	pos->next = latterTwo;

}

🌟text.c测试文件

text.c为工程测试代码文件
#define _CRT_SECURE_NO_WARNINGS

#include"SList.h"

void menu()
{
	printf("************************************\n");
	printf("    1.头插   2.头删\n");
	printf("    3.尾插   4.尾删\n");
	printf("    5.打印   6.插入\n");
	printf("    7.查找   8.删除指定位置后一个\n");
	printf("    -1.退出\n");
	printf("************************************\n");
	printf(" 请选择>:   \n");

}

void menuText()
{
	SLNode* list = NULL;
	int input = 0;
	SLDateType x1 = 0;
	while (input != -1)
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入你要头插入的数,以-1为结束\n");
			scanf("%d", &x1);
			while (x1 != -1)
			{
				SListPushFront(&list, x1);
				scanf("%d", &x1);
			}
			printf("头插成功\n");
			break;
		case 2:
			SListPopBack(&list);
			printf("头删成功\n");
			break;
		case 3:
			printf("请输入你要尾插入的数,以-1为结束\n");
			scanf("%d", &x1);
			while (x1 != -1)
			{
				SListPushBack(&list, x1);
				scanf("%d", &x1);
			}
			printf("尾插成功\n");
			break;
		case 4:
			SListPopBack(&list);
			printf("尾删成功\n");
			break;
		case 5:
			SListPrint(list);
			break;
		case 6:
			printf("在pos位置后面插入,请输入你在哪个位置后插入\n");
				scanf("%d", &x1);
				SLNode* pos = SListFind(list, x1);
				if (pos != NULL)
				{
					printf("OK,请输入你要插入的数据\n");
					scanf("%d", &x1);
					SListInsertAfter(pos,x1);
					printf("插入成功\n");
				}
				else
				{
					printf("无此数据\n");
				}
			break;
		case 7:
			printf("你要查找哪个数据(pos)>\n");
			scanf("%d", &x1);
			int i = 1;
			pos=SListFind(list, x1);
			if (pos == NULL)
			{
				printf("无此数据\n");
			}
			while (pos)
			{
				printf("第%d个pos节点:%p->%d\n", i++, pos, pos->data);
				pos = SListFind(pos->next, x1);

			}
			break;
		case 8:
			printf("你要删除哪个位置后的数据>\n");
			scanf("%d", &x1);
			pos = SListFind(list, x1);
			if (pos != NULL)
			{
				SListEraseAfter(pos);
				printf("删除成功\n");
			}
			else
			{
				printf("无此数据\n");
			}
			break;
		case -1:
			printf("退出成功\n");
			break;
		default:
			printf("无此选项,请重新输入\n");
			break;
		}
	}
}
int main()
{
	menuText();
}

🌟部分测试截图

尾插和打印>

在这里插入图片描述
其他功能请自测!

在这里插入图片描述


  • 42
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 33
    评论
当涉及到线性回归模型的图解和代码,MATLAB 是一种非常强大和方便的工具。下面是一个简单的示例,展示了如何在 MATLAB 中构建和可视化一个线性回归模型。 首先,让我们假设我们有一组输入特征 x 和相应的目标值 y。我们的目标是根据这些数据拟合一个线性模型,其中 x 是自变量,y 是因变量。 ```matlab % 假设我们有以下样本数据 x = [1, 2, 3, 4, 5]; y = [2, 3, 4, 5, 6]; % 构建线性回归模型 model = fitlm(x, y); % 可视化数据和拟合线性模型 scatter(x, y); % 绘制散点图 hold on; plot(model); % 添标签和标题 xlabel('x'); ylabel('y'); title('Linear Regression Model'); % 显示图形 hold off; ``` 在这个示例中,我们首先定义了输入特征 x 和目标值 y。然后,我们使用 `fitlm` 函数构建了一个线性回归模型,并将其存储在变量 `model` 中。 接下来,我们使用 `scatter` 函数绘制了原始数据的散点图。然后,使用 `plot` 函数绘制了拟合的线性模型。 最后,我们使用 `xlabel`、`ylabel` 和 `title` 函数添了标签和标题。最后,使用 `hold off` 函数关闭图形绘制。 请注意,这只是一个简单的示例,实际应用中,你可能需要更多的数据处理、特征工程和模型评估步骤。此外,你还可以根据需要自定义线性回归模型的参数和设置。 希望这个示例能够帮助你开始在 MATLAB 中构建和可视化线性回归模型。如有任何问题,请随时提问!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小明的c++笔记本

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

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

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

打赏作者

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

抵扣说明:

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

余额充值