【数据结构】超详细之单向链表(C语言实现)

news2024/12/28 8:00:01

文章目录

  • 前言
  • 一、单向链表是什么?
  • 二、单向链表实现步骤
    • 1.打印链表数据以及实现链表头插
    • 2.实现链表尾插
    • 3.实现链表头删尾删
    • 4.实现链表查找
    • 5.实现链表在pos之前/之后插入
    • 6.实现链表删除pos位置的值
    • 7.实现链表删除pos之后位置的值
  • 总结


前言

今天我要介绍单向链表,单向链表与之前我们学的顺序表作用相同,但与顺序表相比,单向链表使用起来更加灵活,效率更高,是一种非常常见且实用的数据结构.


一、单向链表是什么?

1.顾名思义,单向表是用单向结构去实现功能

2.表有很多种,但常用的是单向

3.单向表的存储数据方式是一块一块独立的空间,与顺序表是有区别的

4.单向表比顺序表更适合实现增删改查的功能

5.单向链表是一种存储结构上非连续、非顺序的存储结构

二、单向链表实现步骤

1.打印链表数据以及实现链表头插

.h文件
#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int Typen;//类型自定义名字,使数据灵活改变
typedef struct ChainedList
{
	Typen data;//存放的数据
	struct ChainedList* next;//用于存放下一个空间的地址
}CList;
//打印数据
void ChainedListprint(CList* phead);
//头插
void ChainedListPushFront(CList** pphead, Typen x);

.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include"ChainedList.h"

//打印数据
void ChainedListprint(CList* phead)
{
	CList* ps = phead;
	while (ps != NULL)
	{
		printf("%d->", ps->data);
		ps = ps->next;
	}
	printf("NULL\n");
}

//动态申请一个结点
CList* CListBuy(Typen x)
{
	CList* p = (CList*)malloc(sizeof(CList));
	p->data = x;
	p->next = NULL;
	return p;
}
//头插
//这里需要注意,传参必须使用双指针
//因为当我们要改变头指针指向的地址时,我们需要用地址的指针
void ChainedListPushFront(CList** pphead, Typen x)
{
	assert(pphead);
	CList* ps = CListBuy(x);
	ps->next = *pphead;
	*pphead = ps;
}

.c(执行文件)
	CList* p = NULL;
	ChainedListPushFront(&p, 1);
	ChainedListPushFront(&p, 2);
	ChainedListPushFront(&p, 3);
	ChainedListprint(p);
	return 0;


2.实现链表尾插

.h文件
//尾插
void ChainedListPushBack(CList** pphead, Typen x);
.c文件
//动态申请一个结点
CList* CListBuy(Typen x)
{
	CList* p = (CList*)malloc(sizeof(CList));
	if (p == NULL)
	{
		perror("malloc:");
		return NULL;
	}
	p->data = x;
	p->next = NULL;
	return p;
}
//尾插
//形参1需要使用双指针,因为可能出现要改变头指针地址的情况
void ChainedListPushBack(CList** pphead, Typen x)
{
	assert(pphead);
	CList* ps = CListBuy(x);
	// 1、空链表
	// 2、非空链表
	if (*pphead == NULL)
	{
		*pphead = ps;
	}
	else
	{
		CList* n = *pphead;
		while (n->next != NULL)
		{
			n = n->next;
		}
		n->next = ps;
	}
}


 3.实现链表头删尾删

.h文件
//头删
void ChainedListPopFront(CList** pphead);
//尾删
void ChainedListPopBack(CList** pphead);
.c文件
//头删
void ChainedListPopFront(CList** pphead)
{
	assert(*pphead);
	CList* ps = *pphead;
	*pphead = ps->next;
	free(ps);
	ps = NULL;
}
//尾删
void ChainedListPopBack(CList** pphead)
{
	assert(*pphead);
	CList* ps = *pphead;
	//两种情况:
	// 1.一个结点
	// 2.多个结点
	if (ps->next == NULL)
	{
		*pphead = ps;
		free(ps);
	}
	else
	{
		//找到最后一个结点,next为NULL
		while (ps->next->next != NULL)
		{
			ps = ps->next;
		}
		free(ps->next);
		ps->next = NULL;
	}
}

 


 4.实现链表查找

.h文件
//单链表查找
CList* ChainedListFind(CList* phead, Typen x);
.c文件
//单链表查找
CList* ChainedListFind(CList* phead, Typen x)
{
	CList* ps = phead;
	while (ps)
	{
		if (ps->data == x)
		{
			return ps;
		}
		ps = ps->next;
	}
	return NULL;
}


5.实现链表在pos之前/之后插入

.h文件
// 在pos之前插入
void ChainedListInsert(CList** pphead, CList* pos, Typen x);
// 在pos之后插入
void ChainedListInsertAfter(CList* pos, Typen x);
.c文件
// 在pos之前插入
void ChainedListInsert(CList** pphead, CList* pos, Typen x)
{
	assert(pphead);
	assert(pos);
	//一个节点时的情况
	CList* ps = *pphead;
	if (*pphead == pos)
	{
		ChainedListPushFront(pphead, x);
	}
	else
	{
		//多节点时的情况
		while (ps->next != pos)
		{
			ps = ps->next;
		}
		CList* p = CListBuy(x);
		p->next = ps->next;
		ps->next = p;
	}
}
// 在pos之后插入
void ChainedListInsertAfter(CList* pos, Typen x)
{
	assert(pos);
	CList* ps = CListBuy(x);
	ps->next = pos->next;
	pos->next = ps;
}

6.实现链表删除pos位置的值

.h文件
// 删除pos位置的值
void ChainedListErase(CList** pphead, CList* pos);
.c文件
// 删除pos位置的值
void ChainedListErase(CList** pphead, CList* pos)
{
	assert(pphead);
	assert(pos);
	//一个结点时
	if (*pphead == pos)
	{
		ChainedListPopFront(pphead);
	}
	//多节点时
	else
	{
		CList* ps = *pphead;
		while (ps->next != pos)
		{
			ps = ps->next;
		}
		ps->next = pos->next;
		free(pos);
	}
}

7.实现链表删除pos之后位置的值

.h文件
// 删除pos位置后面的值
void ChainedListEraseAfter(CList* pos);
.c文件
// 删除pos位置后面的值
void ChainedListEraseAfter(CList* pos)
{
	assert(pos);
	assert(pos->next);
	pos->next = pos->next->next;
	free(pos->next);
}

总结

以上就是今天要讲的内容,希望能帮助到大家,多多支持,非常感谢!

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

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

相关文章

可变参数列表的使用与原理

序言 我们自己编写的函数通常参数是固定的&#xff0c;这样使得某些功能不能得到我们想要的结果&#xff0c;比如我们想求出2个数的最大值的代码不能用于求处3个数的最大值&#xff0c;因此&#xff0c;C语言定义了可变参数列表来编写参数个数不确定的函数。具有可变参数列表的…

Golang每日一练(leetDay0054)

目录 157. 用 Read4 读取 N 个字符 Read-n-characters-given-read4 &#x1f31f;&#x1f31f; 158. 用 Read4 读取 N 个字符 II Read-n-characters-given-read4-ii-call-multiple-times II &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Gol…

拿捏SQL:以“统计连续登录天数超过3天的用户“为例拿捏同类型SQL需求

文章目录 [TOC](文章目录) 一、介绍案例&#xff1a;以"统计连续登录天数超过3天的用户"为需求。数据准备方案1&#xff1a;常规思路针对对数据user_id分组&#xff0c;根据用户的活动日期排序用登录日期与rn求date_sub&#xff0c;得到的差值日期如果是相等的&#…

Python非线性回归预测模型实验完整版

非线性回归预测模型 实验目的 通过非线性回归预测模型&#xff0c;掌握预测模型的建立和应用方法&#xff0c;了解非线性回归模型的基本原理 实验内容 非线性回归预测模型 实验步骤和过程 (1)第一步&#xff1a;学习非线性回归预测模型相关知识。 非线性回归预测模型是指…

Spring框架中的单例Beans是线程安全的么?

在Spring框架中&#xff0c;单例Beans默认是线程安全的。 当你在Spring框架中声明一个单例Bean并配置为默认的单例作用域时&#xff0c;Spring会确保对该Bean的并发访问是线程安全的。以下是一个简单的代码演示&#xff1a; 假设我们有一个名为 SingletonBean 的单例 Bean 类…

Mysql目录结构

一、目录结构 <1> 主要目录结构 find / -name mysql<2> 数据库文件目录 目录&#xff1a;/var/lib/mysql/ 配置方式&#xff1a;show variables like ‘datadir’; <3> 相关命令目录 目录&#xff1a;/usr/bin&#xff08;mysqla…

VMware安装CentOS7遇到的问题记录

文章目录 1、执行ifconfig后&#xff0c;ip地址不显示解决方法&#xff1a; 2、CentOS ip地址老是变动&#xff0c;配置固定ip解决方法 1、执行ifconfig后&#xff0c;ip地址不显示 问题背景&#xff1a;VMware安装centos7后&#xff0c;启动虚拟机&#xff0c;在终端中执行if…

MySQL示例数据库(MySQL Sample Databases) 之 sakila数据库

文章目录 MySQL示例数据库(MySQL Sample Databases) 之 sakila数据库官方示例数据介绍sakila数据库sakila数据库安装sakila/sakila-schema.sql的脚本内容sakila的结构参考 MySQL示例数据库(MySQL Sample Databases) 之 sakila数据库 官方示例数据介绍 MySQL 官方提供了多个示…

Mysql存储json格式数据需要掌握的

目录 一、前言二、什么是 JSON三、Mysql当中json函数四、JSON值部分更新4.1.使用 Partial Updates 的条件4.2.如何在 binlog 中开启 Partial Updates4.3.关于 Partial Updates 的性能测试 五、如何对 JSON 字段创建索引六、mybatis取json类型的数据七、总结 一、前言 最近做的一…

[实训] 实验1-SPI数据传输基础实验(上)

目 录​​​​​​​ 一、实验目的 二、实验仪器及器件 三、实验内容及原理 四、实验步骤​​​​​​​ 五、实验测试数据表格记录 六、实验数据分析及处理 七、实验结论与感悟 一、实验目的 使用FPGA/ARM实现SPI数据传输实验&#xff1b;实现数据传输程序的编写、下载…

【项目原理】多点触摸屏驱动原理

一、屏幕介绍 ATK-7016 这款屏幕其实是由 TFT LCD触摸屏组合起来的。底下是 LCD 面板&#xff0c;上面是触摸面板&#xff0c;将两个封装到一起就成了带有触摸屏的 LCD 屏幕。电容触摸屏也是需要一个驱动 IC的&#xff0c;驱动 IC 一般会提供一个 I2C 接口给主控制器&#xff…

[实训] 实验1-SPI数据传输基础实验(下)

目录 五、实验测试数据表格记录 六、实验数据分析及处理 七、实验结论与感悟 五、实验测试数据表格记录 实验现象数码管显示见第四节图4.4&#xff0c;示波器测量结果见下列图片。 图5.1 RST、MOSI/MISO波形测量结果 图5.2 SCLK、MOSI/MISO波形测量结果 仅调整示波器波…

C生万物 | 剖析函数指针经典应用 —— 回调函数

不懂函数指针的老铁可以先看看这篇文章【指针函数与函数指针】&#xff0c;上车&#xff0c;准备出发&#x1f697; 文章目录 一、回调函数的概念二、为什么要使用回调函数&#xff1f;三、回调函数使用场景场景一&#xff1a;模拟计算器的加减乘除场景二&#xff1a;模拟qsort…

MySQL集群方案总结与方案原理

前言 在给自己做着玩的一个项目准备数据库集群&#xff0c;顺带自己大致系统复习并记录一下。 单节点mysql存在的常见问题 当数据量和并发量上去后&#xff0c;单节点数据库无法满足大并发时性能上的要求。单节点的MySQL无法满足高可用&#xff0c;数据库宕机或者意外中断等故障…

数据结构学习分享之双向链表详解

数据结构第四课 1.前言2. 结构分析3. 双链表的实现3.1 初始化结构3.2 初始化函数3.3 尾插函数3.4 尾删函数3.5 头插函数3.6 头删函数3.7 销毁链表3.8 其他函数 4. 缓存利用率5. 总结 1.前言 &#x1f493;博主CSDN:杭电码农-NEO&#x1f493;&#x1f389;&#x1f389;&#x…

Python(一) 基础二(语句、文件读写)

1.语句 1.1.if…elif…else 类似于java的if…else if…else语句 1.1.1.判断条件 比较运算符: 、>、<、<、>、!、is、is not、in、not in 1.1.2.和is的区别 list_1 [aaa, bbb] list_2 [aaa, bbb] print(list_1 list_2) #结果:True print(list_1 is list_2)…

async await

async await async await 都是修饰符&#xff0c;修饰函数的。 async/await一定是成对出现的。比如用async也没有什么太大意义。只要函数体中出现了await&#xff0c;则当前函数必须用async来修饰。 用async修饰的函数&#xff0c;相当于用promise包裹起来。其实相当于把同步修…

基于jeecgboot的OA日程安排开发(一)

日程安排也是OA里的一项重要功能&#xff0c;所以基于jeecgboot开发这个日程安排。 日程安排主要涉及以下几个方面&#xff1a; 1、数据库方面&#xff0c;主要是分日历与日程 日历可以分个人日历与工作日历&#xff0c;一般情况下&#xff0c;个人日历只给自己查看&#xff0…

2023-05-02 动态规划简介

动态规划简介 1 动态规划的基本概念 阶段、状态、决策、策略、状态转移方程 1) 阶段和阶段变量 将问题的全过程恰当地分成若干个相互联系的阶段闫氏DP分析法&#xff1a;对应f[i][j]的ij遍历时形成的所有f[i][j]阶段的划分一般根据时间和空间的自然特征去划分阶段的划分便于把…

Nginx原理解析

master和worker 当linux启动的时候&#xff0c;会有两个和nginx相关的进程&#xff0c;一个是master,一个是worker。 master如何工作 当客户端发送请求到nginx之后&#xff0c;master会接收到这个请求&#xff0c;然后通知所有的worker进程&#xff0c;此时&#xff0c;work…