单链表C语言实现 (不带头 带头两个版本)

news2024/12/23 16:19:58

链表就是许多节点在逻辑上串起来的数据存储方式 是通过结构体中的指针将后续的节点串联起来

typedef int SLTDataType;//数据类型
typedef struct SListNode//节点
{
	SLTDataType data;//存储的数据
	struct SListNode* next;//指向下一个节点地址的指针
}SLTNode;//结构体类型的简化

上面的代码只是声明 并没有定义 也就是没有创建结构体变量 

SListNode* pc = NULL;//定义结构体

下面开始实现链表的各个接口 让链表可以存储和删除数据

链表的打印

void SListPrint(SListNode* phead)
{
	while (phead != NULL)
	{
		printf("%d->", phead->val);
		phead = phead->next;
	}
	printf("NULL");
}

链表的插入会向内存申请空间 去创造一个新的节点 所以后续的 头部插入 尾部插入 还是任意位置的插入 都会进行相同的操作 所以这里将开辟节点这个过程单独分装为一个函数 方便后面的操作

static SListNode* CreatNode(DataType x)
{
	SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
	if (tmp == NULL)
	{
		printf("failed to allocate memory.");
		exit(-1);
	}
	tmp->val = x;
	tmp->next = NULL;
	return tmp;
}

这里使用了static将函数的作用域限制在该函数所在的项目中 在其它项目中无法访问

链表的头部插入

void SListFront(SListNode** phead, DataType x)
{
	SListNode* tmp = CreatNode(x);
	tmp->next = *phead;
	tmp->val = x;
	*phead = tmp;
}

链表的尾部插入

链表的尾部插入相比于头部插入就显得不是那么好写

因为你要考虑 链表中是否有数据 也就是*phead是否为空  并且还要考虑当链表不为空时 尾插该怎样插入  我们可以使用if语句进行判断

void SListBackPush(SListNode** phead, DataType x)
{
	SListNode* newnode = CreatNode(x);
	if (*phead == NULL)
	{
		*phead = newnode;
	}
	else
	{
		SListNode* tail = *phead;//定义一个变量去向后寻找尾部
		while (tail->next != NULL)
		{
			tail = tail->next;
		}
		tail->next = newnode;
	}
}

任意位置的插入(从1位置向后插 超出范围 将该节点插入到尾部)

当链表有数据时 尾部插入和头部插入是一样的流程 用一个临时变量tmp 向后寻找pos位置 再将该位置的下一个节点的地址给 要插入节点的指针 最后将要插入节点的地址给前一个节点的指针 这样就将该节点插进去了 

但是头部插入不太一样 因为头部之前没有节点了 就只能将头节点先给要插入的节点 再将要插入的节点作为头部 这样就完成了头部插入

void SListPosPush(SListNode** phead, DataType x , int pos)
{
	SListNode* newnode = CreatNode(x);
	if (pos == 1)
	{
		newnode->next = *phead;
		*phead = newnode;
	}
	else
	{
		SListNode* tmp = *phead;
		//如果所给的pos位置超出了链表的长度就将其插入到尾部
		while (tmp->next!=NULL && pos>2)
		{
			tmp = tmp->next;
			--pos;
		}
		newnode->next = tmp->next;
		tmp->next = newnode;
	}
}

运行结果如下 以上就是插入接口函数的实现

 删除的相关节点

头删

void SListPopFront(SListNode** phead)
{
	assert(*phead);
	SListNode* tmp = *phead;
	*phead = (*phead)->next;
	free(tmp);
	tmp = NULL;
}

尾删

尾删和头删不一样 因为当链表只有一个节点时 尾删就变成了头删 这样就和有多个数据时 尾部删除不一样 这就分情况 讨论

void SListPopBack(SListNode** phead)
{
	assert(*phead);
	if ((*phead)->next == NULL)
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		//找尾
		SListNode* tmp = *phead;//防止头节点丢失
		SListNode* str = *phead;
		while (tmp->next != NULL)
		{
			str = tmp;
			tmp = tmp->next;
		}
		free(tmp);
		tmp = NULL;
		str->next = NULL;
	}
}

上面是两个指针配合删除 下面是一个指针去完成

void SListPopBack(SListNode** phead)
{
	assert(*phead);
	if ((*phead)->next == NULL)
	{
		free(*phead);
		*phead = NULL;
	}
	else
	{
		//找尾
		SListNode* tmp = *phead;//防止头节点丢失
		SListNode* str = *phead;
		while (tmp->next->next!=NULL)
		{
			tmp = tmp->next;
		}
		free(tmp->next);
		tmp->next = NULL;
	}
}

链表pos位置删除

void SListPopPos(SListNode** phead, int pos)
{
	assert(*phead);//空链表就不用删除了
	if (pos == 1)
	{
		SListNode* tmp = *phead;
		*phead = (*phead)->next;
		free(tmp);
		tmp = NULL;
	}
	else
	{
		SListNode* tmp = *phead;
		SListNode* str = tmp;
		while (pos > 1 && tmp->next != NULL)
		{
			str = tmp;
			tmp = tmp->next;
			--pos;
		}
		//找到pos位置之后将 pos的下一个节点的地址给pos前面的节点的指针
		//再将pos所在的节点进行释放
		str->next = tmp->next;
		free(tmp);
		tmp = NULL;
	}
}

对链表的查找 修改 其实就是将链表遍历一遍 上面的寻找尾部 打印链表就是遍历链表 所以大家可以将其修改修改 

对单链表就介绍到这里 后续还有双向链表

带头结点的单链表  没动态开辟头节点 只是定义了一个 结构体变量 用来存储后续插入的节点 用一级指针去传参 你也可以动态开辟头节点 传二级指针 这里只是说 带头结点的很好实现链表的增删查改

头文件  函数各个接口

#pragma once

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

typedef int DataType;
typedef struct SList
{
	DataType val;
	struct SList* next;
}SListNode;


//单链表打印
void SListPrint(SListNode* pc);

//单链表的尾部插入
void SListPushBack(SListNode* pc, DataType x);

//链表的头部插入
void SListPushFront(SListNode* pc, DataType x);

//单链表头删
void SListPopFront(SListNode* pc);

//单链表尾删
void SListPopBack(SListNode* pc);


//删除pos位置
void SListPopPos(SListNode* pc, int pos);

//pos之后插入
void SListPushPos(SListNode* pc, int pos, DataType x);


//链表的查找
void SListFind(SListNode* pc, DataType x);


//链表的销毁
void SListDestroy(SListNode* pc);

函数实现 接口实现

#define _CRT_SECURE_NO_WARNINGS 1


#include"SList.h"

static SListNode* CreatNode(DataType x)
{
	SListNode* tmp = (SListNode*)malloc(sizeof(SListNode));
	if (tmp == NULL)
	{
		printf("Failed to allocate SListNode.");
		exit(-1);
	}
	tmp->next = NULL;
	tmp->val = x;
	return tmp;
}

void SListPrint(SListNode* pc)
{
	SListNode* tmp = pc->next;
	while (tmp)
	{
		printf("%d->", tmp->val);
		tmp = tmp->next;
	}
	printf("NULL\n");
}

void SListPushBack(SListNode* pc, DataType x)
{
	while (pc->next != NULL)
	{
		pc = pc->next;
	}
	pc->next = CreatNode(x);
}

void SListPushFront(SListNode* pc, DataType x)
{

	SListNode* tmp = pc->next;
	pc->next = CreatNode(x);
	pc->next->next = tmp;
}

void SListPopFront(SListNode* pc)
{
	SListNode* tmp = pc->next;
	pc->next = pc->next->next;
	free(tmp);
	tmp = NULL;
}


void SListPopBack(SListNode* pc)
{
	SListNode* tmp = pc,*cur = pc;
	while (cur->next != NULL)
	{
		tmp = cur;
		cur = cur->next;
	}
	if (cur != pc)//不释放哨兵卫
	{
		free(cur);
		cur = NULL;
	}
	tmp->next = NULL;
}


void SListPopPos(SListNode* pc, int pos)
{
	SListNode* tmp = pc->next,*str = pc;
	while (tmp->next != NULL&&pos>1)
	{
		str = tmp;
		tmp = tmp->next;
		--pos;
	}
	if (pos != 1)
	{
		printf("pos位置超出链表范围.");
		return;
	}
	str->next = tmp->next;
	free(tmp);
	tmp = NULL;
}

void SListPushPos(SListNode* pc, int pos, DataType x)
{
	SListNode* newnode = CreatNode(x);
	SListNode* tmp = pc;
	while (tmp->next != NULL&&pos>1)
	{
		tmp = tmp->next;
		--pos;
	}
	if (pos != 1)
	{
		printf("要插入的位置超出了链表的长度.\n");
		return;
	}
	newnode->next = tmp->next;
	tmp->next = newnode;
}


void SListFind(SListNode* pc, DataType x)
{
	SListNode* tmp = pc->next;
	int pos = 0;
	while (tmp)
	{
		pos++;
		if (tmp->val == x)
		{
			printf("找到了该元素在第%d个\n", pos);
			return;
		}
		tmp = tmp->next;
	}
	printf("没有找到.\n");
}

void SListDestroy(SListNode* pc)
{
	//所有申请的空间都要释放
	SListNode* tmp = pc->next;
	pc = pc->next->next;
	while (pc)
	{
		free(tmp);
		tmp = NULL;
		tmp = pc;
		pc = pc->next;
	}
}

测试文件

#define _CRT_SECURE_NO_WARNINGS 1


#include"SList.h"

void test1()
{
	//不是哨兵卫 就是一个结构体变量
	SListNode pc;
	pc.next = NULL;


	SListPushBack(&pc, 1);
	SListPushBack(&pc, 2);
	SListPushBack(&pc, 3);

	SListPushFront(&pc, -1);
	SListPushFront(&pc, -2);

	SListPopFront(&pc);
	SListPopBack(&pc);

	SListPushPos(&pc, 1, 5);
	SListPushPos(&pc, 5, 6);

	SListPopPos(&pc, 1);


	SListFind(&pc, 6);

	SListPrint(&pc);
	SListDestroy(&pc);
}

int main()
{
	test1();

	return 0;
}

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

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

相关文章

机器学习材料性能预测与材料基因工程应用实战

一、背景: 传统的材料研发技术是通过实验合成表征对材料进行试错和验证&#xff0c;而过去的计算手段受限于算法效率&#xff0c;无法有效求解实际工业生产中面临的复杂问题。近几年随着大数据和人工智能介入&#xff0c;通过采用支持向量机、神经网络等机器学习算法训练数据集…

Vue核心 MVVM模型 数据代理

1.6.MVVM 模型 MVVM模型 M&#xff1a;模型 Model&#xff0c;data中的数据V&#xff1a;视图 View&#xff0c;模板代码VM&#xff1a;视图模型 ViewModel&#xff0c;Vue实例 观察发现 data中所有的属性&#xff0c;最后都出现在了vm身上vm身上所有的属性及Vue原型身上所有…

用友nc6 如果用户长时间没有任何操作,如何设置会话的失效时间?

1.web应用(新开的) NC中间件环境下的web profile和NC中间件没有关系&#xff0c;NC中间件只不过是个J2EE运行环境&#xff0c;是个Container&#xff0c;当你的web项目启动后&#xff0c;NC中间件创建web容器&#xff0c;其web应用的会话超时时间由你的web部署描述符&#xff…

电脑卡顿反应慢怎么办?这几招教给你!

电脑使用时间长了&#xff0c;电脑中的各种缓存文件也会就越来越多&#xff0c;这些文件的堆积会占用电脑内存从而导致电脑变得卡顿。还有在电脑中安装了许多软件&#xff0c;若这些软件都设置为开机自启动&#xff0c;这会占用大量的电脑内存&#xff0c;影响电脑的运行速度&a…

PMP项目管理备考资料都有哪些?

当今复杂多变的项目管理环境中&#xff0c;项目管理从业者在各种各样的项目环境中工作&#xff0c;一定会采用不同的项目方法。PMP认证试图覆盖业界所有有效的项目管理方法&#xff0c;PMP考试范围会覆盖预测型生命周期&#xff08;即瀑布式开发模式&#xff09;为代表的项目管…

什么是 MVVM?MVVM和 MVC 有什么区别?什么又是 MVP ?

目录标题 一、什么是MVVM&#xff1f;二、MVC是什么&#xff1f;三、MVVM和MVC的区别&#xff1f;四、什么是MVP&#xff1f; 一、什么是MVVM&#xff1f; MVVM是 Model-View-ViewModel的缩写&#xff0c;即模型-视图-视图模型。MVVM 是一种设计思想。 模型&#xff08;Model…

PerformanceTest, monitoring command

PerformanceTest, monitoring command 1、数据库 #查看最大连接数 show variables like max_connections; #例如:查看mysql连接数 show status like Threads%; 说明: threads_cached //查看线程缓存内的线程的数量 threads_connected //查看当前打开的连接的数量(打开的…

【Linux】6、在 Linux 操作系统中安装软件

目录 一、yum 命令二、安装 wget 一、yum 命令 类似 Linux 中的应用商店 &#x1f4c3;① yum 是 RPM 软件包管理器 ✏️ Red-Hat Package Manager &#x1f4c3;② yum 用于自动化安装、配置 Linux 软件&#xff08;可自动解决依赖问题&#xff09; &#x1f4c3;③ 语法&a…

面试2个月没有一个offer?阿里技术官的800页知识宝典打破你的僵局~

在经历了一波裁员浪潮后&#xff0c;大环境似乎有所好转&#xff0c;但对于面试者来说&#xff0c;面试愈发困难&#xff0c;现在面试官动不动就是底层原理&#xff0c;动不动就是源码分析&#xff0c;面试一定会抓你擅长的地方&#xff0c;一直问&#xff0c;问到你不会为止。…

MySQL之内置函数

目录 一 日期函数 主要实现的功能&#xff1a; 主要函数&#xff1a; 示例&#xff1a; 应用 二 字符串函数 主要实现的功能 1转换或者显示相关 2切割&#xff0c;插入&#xff0c;替换&#xff0c;连接&#xff0c;比较等功能性质的 3 其他 三 数学函数 1 运算 2 …

MySQL-运算符的使用解析

运算符的使用解析 1 运算符概述2 算数运算符3 比较运算符3.1 等于运算符&#xff08;&#xff09;3.2 安全等于运算符&#xff08;<>&#xff09;3.3 不等于运算符&#xff08;<> 或者 &#xff01;&#xff09;3.4 小于等于运算符&#xff08;<&#xff09;3.5…

Jmeter基础教程合集

环境搭建 1.安装java 8.0以上版本 2.下载jmeter并安装。安装参考网址&#xff1a;https://blog.csdn.net/wust_lh/article/details/86095924 3.打开JMeter中bin目录下面的jmeter.bat文件即可打开JMeter了&#xff0c;打开的时候会有两个窗口&#xff0c;Jmeter的命令窗口和Jme…

【数据结构】哈希表——闭散列 | 开散列(哈希桶)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《数据结构与算法》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 哈希表 &#x1f3af;哈希&#x1f94a;直接定址法&#x1f94a;除留余数法&#x1f94a;哈…

CHAPTER 3: 《A FRAMEWORK FOR SYSTEM DESIGN INTERVIEWS》第3章 《面试系统设计框架》

CHAPTER 3: A FRAMEWORK FOR SYSTEM DESIGN INTERVIEWS 你刚刚获得了梦寐以求的理想公司的现场面试机会。招聘协调员给你发送了当天的日程安排。浏览列表&#xff0c;你会感觉很好直到你的目光落在这个面试环节——系统设计面试。 系统设计面试通常很吓人。它可以像“设计一个…

【Redis】缓存同步

【Redis】缓存同步 文章目录 【Redis】缓存同步1. 数据同步策略2. 异步通知策略3. Canal3.1 Canal客户端3.2 监听器 1. 数据同步策略 缓存数据同步的常见方式有三种&#xff1a; 设置有效期&#xff1a;给缓存设置有效期&#xff0c;到期后自动删除&#xff0c;再次查询时更新…

网络系统集成实验(四)| 系统集成路由器基本配置

目录 一、前言 二、实验目的 三、实验需求 四、实验步骤与现象 &#xff08;一&#xff09;静态路由 Step1&#xff1a;构建实验拓扑如下 Step2&#xff1a;IP地址配置如下 Step3&#xff1a;配置静态路由 Step4&#xff1a;验证 &#xff08;二&#xff09;NAT配置—…

OpenPCDet复现过程记录

0、前言 OpenPCDet项目之前我就复现过&#xff0c;一个很优秀的项目&#xff0c;这几天又需要用到这个项目&#xff0c;再次复现遇到了不少问题&#xff0c;特此记录复现的流程 1、环境准备 1.1、前置条件 以下是我安装的版本 CUDA 11.3CUDNN 8.2.1 CUDA和CUDNN安装可以参考…

Yolo v1 笔记

个人不太懂的点 1.损失函数的4与5项 【论文解读】Yolo三部曲解读——Yolov1 - 知乎 https://www.youtube.com/watch?vNkFENlEb4kM&t672s 训练阶段&#xff1a; C_i 预测值&#xff1a;由网络输出出来7*7*30中第一个bbox和第二个bbox的置信度confidence C_i^hat 标签值…

(六)大数据实战——hadoop集群实现免密登录和文件互传

前言 本节内容我们主要介绍一下hadoop集群服务器之间实现免密登录和文件互传的功能&#xff0c;这样更加方便我们使用hadoop服务器实现服务器之间的相互登录和文件的相互传输。集群之间的访问不在需要授权就可以实现相互访问。 正文 SSH免密登录 ①分别在hadoop101、hadoop1…

后台管理系统之登录方案记录

需求&#xff1a;根据当前环境的不同&#xff0c;请求不同的 BaseUrl 解决&#xff1a;在根目录中新建.env.development与.env.production连个文件&#xff0c;进行配置&#xff1a; # .env.production ENV production# base api VUE_APP_BASE_API /prod-api# .env.develop…