C语言手撕单链表

一、链表的概念

链表是一种物理存储结构上非连续、非顺序的存储结构,也就是内存存储不是像顺序表那么连续存储,而是以结点的形式一块一块存储在堆上的(用动态内存开辟)。

既然在内存上不是连续存储,那我们如何将这一块一块单独的空间链接起来呢?

我们可以创建一个结构体充当我们的结点,里面分别存放数据(数据域)和下一个结点的地址(指针域),这样我们就可以将一块一块单独的空间链接起来了。

而单链表,顾名思义就是单向链接的链表,效果如同下图

前言:

在讲解单链表的各个接口前,很有必要讲解以下单链表的物理内存到底是如何存储的,先掌握这个,接下来的讲解就会更容易理解

头结点指向的地址就是第一个结点的地址

第一个结点的指针域指向的是第二个结点的总地址,所以分为两个地址

一个是结点的总地址,另一个是结点总地址里面的next指针存放的指针域的地址,这个指针域的地址又指向了下一个结点的总地址。

看下面的图解内存存储的数据,实际中是没有箭头的,把箭头去掉,才是内存中真正的存储模式

二、接口实现

对数据结构我们一般采用增删查改去实现。

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

typedef int SLTDataType;

typedef struct SListNode
{
	SLTDataType data;//数据域
	struct SListNode* next;//指针域
}SLTNode;

void SLTPrint(SLTNode* phead);

SLTNode* BuySListNode(SLTDataType x);

void SLTPushBack(SLTNode** phead, SLTDataType x);

void SLTPushFront(SLTNode** phead, SLTDataType x);

void SLTPopFront(SLTNode** phead);

void SLTPopBack(SLTNode** phead);

 1、遍历单链表打印函数

一般需要创建一个临时变量去接收头结点

//遍历链表肯定需要头结点
void SLTPrint(SLTNode* phead)
{
	SLTNode* cur = phead;//一般需要临时创建变量
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL");
}

2、创建单链表函数

SLTNode* BuySListNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror(malloc);
		exit(-1);
	}
	newnode->data = x;
	newnode->next = NULL;
}

3、尾插

需要分情况讨论,

  • 如果链表本身是空,直接改变头结点的指针,直接指向新建的结点
  • 若不为空,需要找到尾结点

TIP:何时用指针变量,何时用二级指针?

改变结构体本身,需要结构体指针

改变结构体指针,需要结构体指针指针(二级指针),并且要有解引用的操作

刚才第一种情况,直接将头结点的指针改变成新指针的地址,这种直接改变指针的模式,就需要二级指针,进行解引用才能达到目的。

void SLTPushBack(SLTNode** phead, SLTDataType x)
{
	//需要分情况讨论,如果链表本身是空
	if (*phead == NULL)
	{
		SLTNode* newnode = BuySListNode(x);
		//改变结构体本身,需要结构体的指针
		//改变结构体指针,需要结构体指针指针(二级指针),并且要有解引用的操作
		*phead = newnode;
	}
	else
	{
		//先找尾结点
		SLTNode* newnode = BuySListNode(x);
		SLTNode* tail = *phead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
	
}

4、头插

头插肯定需要二级指针,因为每次头插都要改变头指针指向的位置

//头插肯定需要二级指针,因为每次头插都要改变头指针指向的位置
void SLTPushFront(SLTNode** phead, SLTDataType x)
{
	SLTNode* newnode = BuySListNode(x);
	newnode->next = *phead;
	*phead = newnode;
}

5、尾删

分三种情况

  • 第一种是链表为空,需要assert断言检查
  • 第二种链表中只有一个结点,需要改变结构体指针,因此函数传参也是需要二级指针
  • 第三种链表有多于一个的结点,需要先找到尾结点。
void SLTPopBack(SLTNode** pphead)
{
	//分三种情况
	// 第一种就是链表为空
	assert(*pphead);
	// 第二种链表只有一个结点,需要改变结构体指针
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		pphead = NULL;
	}
	//第三种链表多于一个结点
	else
	{
		SLTNode* tail = *pphead;
		SLTNode* tailprev = NULL;
		while (tail->next != NULL)
		{
			tailprev = tail;
			tail = tail->next;
		}
		free(tail);
		tailprev->next = NULL;//严格要求尾指针前一个的next指向null
	}
}

6、头删

不需要分类讨论,直接改变头节点的指针指向,但是需要一个临时变量存储结点,便于后面的操作

void SLTPopFront(SLTNode** phead)
{
	assert(*phead);
	SLTNode* newnode = (*phead)->next;
	free(*phead);
	*phead = newnode;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

第28天-Kubernetes架构,集群部署,Ingress,项目部署,Dashboard

1.K8S集群部署 1.1.k8s快速入门 1.1.1.简介 Kubernetes简称k8s&#xff0c;是用于自动部署&#xff0c;扩展和管理容器化应用程序的开源系统。 中文官网&#xff1a;https://kubernetes.io/zh/中文社区&#xff1a;https://www.kubernetes.org.cn/官方文档&#xff1a;https…

保护模式中段选择子权限校验逻辑详解

保护模式中段选择子权限校验逻辑详解 CPLRPLDPL权限校验逻辑测试 CPL CPL是当前进程的权限级别(Current Privilege Level)&#xff0c;是当前正在执行的代码所在的段的特权级&#xff0c;存在于cs段选择子的后两位的低两位。 段选择子可见部分的数据结构如下&#xff1a; 举例…

基于SpringBoot+Vue的漫画网站设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

智能指针shared_ptr:自定义删除器

重点&#xff1a; 1.普通指针转化成智能指针。 2.智能指针创建的时候&#xff0c;第二个参数是自定义删除器&#xff0c;默认情况下&#xff0c;shared_ptr调用delete()函数。 class A { public:void Get() { cout << b << endl; }; private:int b{ 10 }; };clas…

在排序数组中查找元素的第一个和最后一个位置——力扣34

文章目录 题目描述法一 二分查找 题目描述 法一 二分查找 int bsearch_1(int l, int r) {while (l < r){int mid (l r)/2;if (check(mid)) r mid;else l mid 1;}return l; }int bsearch_2(int l, int r) {while (l < r){int mid ( l r 1 ) /2;if (check(mid)) l …

MobPush iOS SDK iOS实时活动

开发工具&#xff1a;Xcode 功能需要: SwiftUI实现UI页面&#xff0c;iOS16.1以上系统使用 功能使用: 需应用为启动状态 功能说明 iOS16.1 系统支持实时活动功能&#xff0c;可以在锁定屏幕上实时获知各种事情的进展&#xff0c;MobPushSDK iOS 4.0.3版本已完成适配&#xf…

序列建模简史(DIN/DIEN/DSIN/BST/MIMN/SIM/ETA/SDIM/TWIN)

序列建模简史(DIN/DIEN/DSIN/BST/MIMN/SIM/ETA/SDIM/TWIN) 史前史 在用户序列专门用于建模之前&#xff0c;一般对序列的建模的处理就是将所有序列行为进行sum/avg pooling操作&#xff0c;将用户的多个序列行为简单聚合成一个Embedding&#xff0c;然后和其他特征一起拼接。…

ansible-playbook roles模块编写lnmp剧本

目录 一&#xff1a;集中式编写lnmp剧本 二&#xff1a;分布式安装lnmp 1、nginx 配置 2、mysql配置 3、php配置 4、运行剧本 一&#xff1a;集中式编写lnmp剧本 vim /etc/ansible/lnmp.yml- name: lnmp playhosts: dbserversremote_user: roottasks:- name: perpare condif…

谷歌云 | 电子商务 | 如何更好地管理客户身份以支持最佳的用户体验

【本文由Cloud Ace整理发布。Cloud Ace是谷歌云全球战略合作伙伴&#xff0c;拥有 300 多名工程师&#xff0c;也是谷歌最高级别合作伙伴&#xff0c;多次获得 Google Cloud 合作伙伴奖。作为谷歌托管服务商&#xff0c;我们提供谷歌云、谷歌地图、谷歌办公套件、谷歌云认证培训…

嵌入式开发学习(STC51-10-直流电机)

内容 直流电机工作约5S后停止 直流电机简介 直流电机是指能将直流电能转换成机械能&#xff08;直流电动机&#xff09;或将机械能转换成直流电能&#xff08;直流发电机&#xff09;的旋转电机&#xff1b; 直流电机的结构应由定子和转子两大部分组成&#xff1b; 直流电…

k8s概念-pv和pvc

回到目录 kubernetes存储卷的分类太丰富了,每种类型都要写相应的接口与参数才行&#xff0c;这就让维护与管理难度加大。 persistenvolume(PV) 是配置好的一段存储(可以是任意类型的存储卷) 也就是说将网络存储共享出来,配置定义成PV。 PersistentVolumeClaim(PVC)是用户pod使…

麦肯锡战略思维四大原则

麦肯锡战略思维四大原则 曾任职麦肯锡、安永等国家国际知名咨询机构的周正元&#xff0c;在其著作《麦肯锡结构化战略思维》将其系统的整理呈现出来&#xff0c;便于学习和使用。 模型介绍 工作中的你&#xff0c;是不是经常遇到复杂问题&#xff0c;六神无主&#xff1f; 专业…

【树形DP+换根思想】2022牛客多校加赛 H

登录—专业IT笔试面试备考平台_牛客网 题意&#xff1a; 思路&#xff1a; 这个虽然是树形DP&#xff0c;却用了换根的思想.... 首先&#xff0c;后缀0的个数可以转化成min(cnt2,cnt5)&#xff0c;其中cnt2为2的因子个数&#xff0c;cnt5为5的因子个数 然后进行DP 设dp[u]…

openGauss学习笔记-31 openGauss 高级数据管理-索引

文章目录 openGauss学习笔记-31 openGauss 高级数据管理-索引31.1 语法格式31.2 参数说明31.3 示例 openGauss学习笔记-31 openGauss 高级数据管理-索引 索引是一个指向表中数据的指针。一个数据库中的索引与一本书的索引目录是非常相似的。 索引可以用来提高数据库查询性能&…

解决:树莓派VNC连接屏幕显示不全

目录 前导&#xff1a;我在重新烧录玩树莓派系统&#xff0c;开启完VNC并连接后&#xff0c;发现我的树莓派远程桌面屏幕显示不全&#xff0c;看着很难受&#xff01; PS&#xff1a;开启VNC服务的过程 问题如下现象&#xff1a; 问题分析&#xff1a;当树莓派通过VNC连接时&…

ThreadLocal原理

ThreadLocal原理 ThreadLocal对象new出来存放到堆中&#xff0c;ThreadLocal引用是存放在栈里 Thread 类有个 ThreadLocalMap 成员变量&#xff0c;Map的key是Threadlocal 对象&#xff0c;value是你要存放的线程局部变量。 public void set(T value) {//获取当前线程Thread&…

springboot+vue农业技术信息管理系统_9927h

随着信息时代的发展&#xff0c;计算机迅速普及&#xff0c;传统的农业信息管理方式显得不够快捷&#xff0c;这时我们就需要创造更加便利的管理方法&#xff0c;对农业信息进行统计&#xff0c;便于统一管理。将传统管理方式转变为信息、智能化显得尤为重要&#xff0c;农业信…

web开发中的安全和防御入门——csp (content-security-policy内容安全策略)

偶然碰到iframe跨域加载被拒绝的问题&#xff0c;原因是父页面默认不允许加载跨域的子页面&#xff0c;也就是的content-security-policy中没有设置允许跨域加载。 简单地说&#xff0c;content-security-policy能限制页面允许和不允许加载的所有资源&#xff0c;常见的包括&a…

【万字长文】SpringBoot整合Atomikos实现多数据源分布式事务(提供Gitee源码)

前言&#xff1a;在最近的实际开发的过程中&#xff0c;遇到了在多数据源的情况下要保证原子性的问题&#xff0c;这个问题当时遇到了也是思考了一段时间&#xff0c;后来通过搜集大量资料与学习&#xff0c;最后是采用了分布式事务来解决这个问题&#xff0c;在讲解之前&#…

睿讯微带你深度了解汽车交流充电桩

这几年随着新能源汽车的普及&#xff0c;充电桩也越来越多的出现在我们的视野中。新能源纯电汽车就好比一种大号的电子产品&#xff0c;而充电桩则是它不可缺少的子系统&#xff0c;是新能源车主们的必要选择。 汽车充电桩分为直流和交流两种&#xff0c;2022年底全国公共充电桩…