数据结构入门(二)——单链表(增,删,查,改)

news2024/11/26 0:30:57

1.单链表的概念

概念:链表是一种物理存储结构非连续、非顺序的存储结构,但链表在逻辑上连续的,顺序的,而数据元素的逻辑顺序是通过链表中的指针连接次序实现的。

1.2链表的结构

我们给int重新定义一下新类型叫做SLDataType,这里我们要说明一下,如果我们想要改变数据类型在这里直接就可以改变,不需要在程序中挨个改变

 这里面SLTDataType data是储存数据用的,而*next本质是一个指针,实际储存的是下一个数据的地址,也是单链表中起到 “ 桥梁 ”的主要部分

我们实际就是这样储存的,是一个内存块内储存着下一个内存的地址


 2.单链表的实现

我们先把函数的声明给大家

#pragma once
#include<string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);//打印单链表i
void SLPushFront(SLTNode** pphead, SLTDataType x);//头插
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插

void SLPopFront(SLTNode** pphead);//头删
void SLPopBack(SLTNode** pphead);//尾删

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos位置之前插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);//在pos后面插入

void SLErase(SLTNode** pphead, SLTNode* pos);//单链表结点删除
void SLEraseAfter(SLTNode* pos);//结点后面删除

2.1内存的开辟

这里我想就不用多说了直接向内存中申请空间开辟内存块

SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

2.2尾插

我们在进行尾插的时候回有两种情况,第一个情况是你传过来的是空指针,那么我们就需要开辟一块空间来让pphead中plist来存放这个空间的地址

第二个情况:如果这里面传的不是空指针,那么我们就要创建一个tail(让tail代替pphead来一个一个的走),起到链接的作用,再让新开辟的内存地址,存放在tail的后面,让tail指向下一个结点,直达为NULL时结束

void SLPushBack(SLTNode** pphead, SLTDataType x)
{
    //申请内存
	SLTNode* newnode = BuyLTNode(x);
    
    //第一个情况
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
    
    //第二个情况
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

2.3头插

我们要实现头插思路要和尾插相反,就是让pphead的地址赋给我们新创建内存块旁边的空间里,这样我们就实现了新内存找到老内存的一个过程,之后我们在把新内存的地址赋给我们pphead让指针指向新内存块的地址,这样就形成一个头插的循环

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

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

2.4尾删

这里和前面一样,核心思想是什么?核心思想就是使指向最后一个内存块的指针为NULL,将最后一个内存块释放掉,就可以了

void SLPopBack(SLTNode** pphead)
{
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else 
	{
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}
}

2.5头删

void SLPopFront(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

2.6中间插入(pos之前)

我们这里写一个while循环首先要找到你要插入的位置,这时我们创建一个空间让你要插入位置前面的指针指向你这个新的空间,这个新空间的尾部指向你之前原本这个位置的地址,这样中间插入就完成了


void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}

}

2.7中间插入(pos之后)

我们在找到pos位置时,让他旁边的内存地址存入到新内存旁边的地址,再让新内存的地址赋给我们pos旁边的位置,这样中间插入就完成了

void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

2.8删除结点

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

	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

2.9删除后面的结点

void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

2.10打印单链表

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

3.代码总结

SList.c

#include "SList.h"

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

SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

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

void SLPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

void SLPopFront(SLTNode** pphead)
{
	assert(pphead);
	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

void SLPopBack(SLTNode** pphead)
{
	assert(*pphead);
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else 
	{
		SLTNode* tail = *pphead;
		while (tail->next->next)
		{
			tail = tail->next;
		}

		free(tail->next);
		tail->next = NULL;
	}
}

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}

}

void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

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

	if (pos == *pphead)
	{
		SLTPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		prev->next = pos->next;
		free(pos);
	}
}

void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

SList.h

#pragma once
#include<string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <assert.h>

typedef int SLTDataType;
typedef struct SListNode
{
	SLTDataType data;
	struct SListNode* next;
}SLTNode;

void SLTPrint(SLTNode* phead);//打印单链表i
void SLPushFront(SLTNode** pphead, SLTDataType x);//头插
void SLPushBack(SLTNode** pphead, SLTDataType x);//尾插

void SLPopFront(SLTNode** pphead);//头删
void SLPopBack(SLTNode** pphead);//尾删

void SLInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos位置之前插入
void SLInsertAfter(SLTNode* pos, SLTDataType x);//在pos后面插入

void SLErase(SLTNode** pphead, SLTNode* pos);//单链表结点删除
void SLEraseAfter(SLTNode* pos);//结点后面删除

这里面我就不写test.c的内容了


以上就是本次单链表的文章分享,喜欢的话请三联支持一下,感谢您的支持


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

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

相关文章

开源Stylegan人脸生成预训练模型

最近在研究Stylegan对抗式图像生成网络&#xff0c;使用了网络的一些预训练模型生成相应的图像&#xff0c;感觉非常有趣。下面开源一些我找到了预训练模型和代码&#xff0c;供大家一起玩。 Stylegan2官方给出的是TensorFlow版本的&#xff0c;费了半天劲找出了pytorch版本 这…

【五一创作】【Midjourney】Midjourney 连续性人物创作 ① ( 通过垫图方式生成类似图像 )

文章目录 一、Midjourney 生成图像二、通过垫图方式生成类似图像 一、Midjourney 生成图像 Midjourney 可以生成高质量的图像 , 但是 生成过程有很大的随机性 , 输入同样的提示词指令 , 其输出结果也存在很大的不同 ; 如果要 生成稳定的人物角色 , 场景 , 描述连贯的内容 , 这…

RMAN-03009、ORA-19566数据文件坏块报错处理方法

在备份数据库的时候&#xff0c;出现RMAN-03009、ORA-19566报错&#xff1a; RMAN-03009: backup 命令 (c3 通道上, 在 04/29/2023 10:58:11 上) 失败 ORA-19566: 超出损坏块限制 0 (文件 E:\APP\ADMINISTRATOR\ORADATA\JHSEMR\JHEMR2.DBF) 继续执行其他作业步骤, 将不重新运行…

React--》一些不常见的hook函数讲解

目录 Hook函数 useImperativeHandle useLayoutEffect和useInsertionEffect与useEffect区别 useDebugValue useDeferredValue useTransition Hook函数 关于React中的钩子函数&#xff0c;在我之间的文章中讲解完我们已经非常熟悉了&#xff0c;钩子函数的功能非常强大而它…

编译安卓系统源码时异常处理

编译安卓系统源码时异常处理 提示语法错误&#xff0c;如下所示&#xff1a; FAILED: out/target/product/generic/system-qemu.img /bin/bash -c "(export SGDISKout/host/linux-x86/bin/sgdisk SIMG2IMGout/host/linux-x86/bin/simg2img; device/generic/goldfis…

新安装的ubuntu,遇到的问题记录

镜像版本&#xff1a; https://mirror.nju.edu.cn/ubuntu-releases/22.04/ubuntu-22.04.1-live-server-amd64.iso 安装后无法切换 root 用户&#xff1a; 问题截图&#xff1a; null 解决办法&#xff1a; 解决ubuntu操作系统默认没有创建root账户&#xff1a; 1、sudo passwd …

云原生CAx软件:多租户的认证

云原生CAx软件是在设计时便将云平台作为部署、运行环境的CAx软件。通常&#xff0c;为了降低成本、方便管理&#xff0c;云原生CAx系统需要能为多个租户提供服务&#xff0c;即多租户(Multi-tenancy)&#xff0c;而实现这种多租户系统&#xff0c;关键是要处理好身份认证、权限…

PhotoShop如何使用图层之实例演示?

文章目录 0.引言1.创建简单的立体书效果图2.给人像制作逼真的影子3.用调整图层除去图像中的灰色4.制作有质感的口红颜色5.给黑白图像上色6.制作粉笔文字效果 0.引言 因科研等多场景需要进行绘图处理&#xff0c;笔者对PS进行了学习&#xff0c;本文通过《Photoshop2021入门教程…

Packet Tracer - 配置 IPv6 静态路由和默认路由

Packet Tracer - 配置 IPv6 静态路由和默认路由 IPv6 地址分配表 设备 接口 IPv6 地址/前缀 默认网关 R1 G0/0 2001:DB8:1:1::1/64 不适用 S0/0/0 2001:DB8:1:A001::1/64 不适用 R2 G0/0 2001:DB8:1:2::1/64 不适用 S0/0/0 2001:DB8:1:A001::2/64 不适用 S0…

如何将图片恢复水平位置?图片旋转矫正方法大全,ddddocr作者基于RotNet的旋转验证码深度学习识别模型Rotate-Captcha-Crack

基于边缘检测的图像旋转校正模型&#xff1a; 该模型首先使用边缘检测算法对图像进行边缘检测&#xff0c;然后找到边缘上的直线&#xff0c;并计算直线的角度。最后通过旋转图像来校正图像的角度。 import cv2 import numpy as np# 加载图像 img cv2.imread(skewed_image.j…

【chatgpt】学习开源项目chatgpt-web,搭建自己的chatgpt服务,功能非常丰富有打字效果

目录 前言1&#xff0c;开源的chatgpt项目2&#xff0c;项目可以直接使用docker-compose跑起来3&#xff0c;关于打字模式SSE&#xff0c; octet-stream &#xff08;打字特效&#xff09;4&#xff0c;关于内容存储5&#xff0c;总结 前言 本文的原文连接是: https://blog.csd…

自动控制原理笔记-根轨迹法

目录 一&#xff0c;根轨迹的基本概念 1.根轨迹的基本概念 2.根轨迹方程 3.根轨迹方程的应用 二&#xff0c;根轨迹的绘制规则 【规则一】根轨迹有n条分支&#xff1a; 【规则二】根轨迹对称于实轴&#xff1a; 【规则三】根轨迹的起点和终点&#xff1a; 【规则四】…

BUUCTF-Web-[极客大挑战 2019]Upload

打开后可以看到是一个可以进行文件上传的页面&#xff0c;如下图所示 查看页面源代码&#xff0c;如下图所示&#xff0c;可以看到有js代码&#xff0c;说明存在前端验证的可能性 上传一个php文件&#xff0c;此处上传shell.php后页面如下图所示&#xff0c;显示不是图片 用bur…

前端存储 Cookie、Web Storage(localStorage 与 sessionStorage)

cookie 由来&#xff1a;cookie 最初的目的是为了维持前端存储的临时状态而产生的。原理&#xff1a; 浏览器发出无状态请求服务器返回响应&#xff0c;携带 cookie 信息浏览器发出接口请求&#xff0c;携带 cookie 信息之后就是前端与服务器建立完成连接后的接口返回了 生成机…

Qt 实现简单的tcp网络通信

文章目录 成品效果图&#xff1a;代码&#xff1a;工具头文件tool.hUI文件代码 ui_widget.h:窗口头文件 widget.h&#xff1a;窗口源文件widget.cpp: 相关代码说明&#xff1a;Qt获取本机ip:Qt 打开&#xff0c;监视服务端端口&#xff1a;Qt 客户端连接服务端&#xff1a;Qt 服…

自建小网站——在idea中如何运行一个vue项目完整过程

这些天Darren洋计划筹建一个属于自己的个人博客空间小网站&#xff0c;其中选择的就是vue项目类型的网站&#xff0c;因为在运行vue项目途中不是特别顺利&#xff0c;现整理了一下流程供大家参考学习。 一、从git上pull一个vue项目 先登录git官网&#xff0c;pull一个vue项目包…

【ElasticSearch】HTTP调用API

文章目录 数据格式HTTP操作索引操作映射操作文档操作(添加数据)高级查询定义数据查询所有文档匹配查询多字段匹配查询关键字精确查询多关键字精确查询指定查询字段过滤字段组合查询范围查询模糊查询*单字段排序多字段排序高亮查询分页查询聚合查询对某个字段取最大值 max对某个…

Channel Distillation: Channel-Wise Attention for Knowledge Distillation 原理与代码解析

paper&#xff1a;Channel Distillation: Channel-Wise Attention for Knowledge Distillation official implementation&#xff1a;https://github.com/zhouzaida/channel-distillation 存在的问题 教师模型传递的知识不够好&#xff0c;学生模型无法准确地从教师模型学习…

java基础语法总复习思维导图 + 重难点+面试题

前言 小亭子正在努力的学习编程&#xff0c;接下来将开启javaEE的学习~~ 分享的文章都是学习的笔记和感悟&#xff0c;如有不妥之处希望大佬们批评指正~~ 同时如果本文对你有帮助的话&#xff0c;烦请点赞关注支持一波, 感激不尽~~ 【需要可修改的思维导图可以私信我&#xff0…

Packet Tracer - 静态路由故障排除

Packet Tracer - 静态路由故障排除 地址分配表 设备 接口 IPv4 地址 子网掩码 默认网关 R1 G0/0 172.31.1.1 255.255.255.128 不适用 S0/0/0 172.31.1.194 255.255.255.252 不适用 R2 G0/0 172.31.0.1 255.255.255.0 不适用 S0/0/0 172.31.1.193 255.255…