数据结构-手撕单链表+代码详解

news2024/11/15 20:03:47

⭐️ 往期相关文章

✨ 链接1:数据结构-手撕顺序表(动态版)+代码详解
✨ 链接2:数据结构和算法的概念以及时间复杂度空间复杂度详解


⭐️ 链表

🌠 什么是链表?

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针域来指向下一个结点的地址来实现的。

🌠 为什么会有链表?

链表是因为顺序表的缺陷而产生的。那么顺序表有哪些缺陷呢?

  • 中间/头部的插入删除,需要挪动数据,时间复杂度为 O ( N ) O(N) O(N)
  • 增容需要申请新的空间,也就面临着效率问题,如果扩容的位置后续的位置够新的空间,那么则在尾部进行扩容。若后续位置不足新的空间,那么会找一片足够的空间,在把原来的数据拷贝过去,释放旧空间。
  • 增容多了势必就有空间上的浪费,增容少了就会有频繁的增容,导致效率不够高。

而链表中的结点都是按需申请内存,不会存在浪费和频繁的扩容。而效率也根据链表的分类不同,时间复杂度也有一定的区别。而单链表,相对于其他类型的链表有很多的缺陷,所以也是面试的重点。

🌠 链表的分类

实际中链表的结构非常多样。

  • 单向带头循环链表
  • 单向不带头循环链表
  • 单向带头不循环链表
  • 单向不带头不循环链表
  • 双向带头循环链表
  • 双向不带头循环链表
  • 双向带头不循环链表
  • 双向不带头不循环链表

本期主要讲解的是单向不带头不循环链表也称单链表。

单链表示意图:
在这里插入图片描述
单链表的结构主要分为:数据域、指针域。数据域用来存放数据。指针域用来存放下一个结点的指针。最后一个结点的指针域存放 NULL

🌠 手撕单链表

单链表的结构:

// 相关头文件
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

// 单链表的类型
typedef int SingleListType;

typedef struct SingleList {
	SingleListType data;		// 数据域
	struct SingleList* next;	// 指针域
}SingleList;

typedef int SingleListType; 单链表的类型不能写死,因为可能存储的数据是 chardoubleint...的其他类型。

单链表的接口实现

// 单链表的打印
void SingleListPrint(SingleList* phead);
// 创建新结点
SingleList* SingleListCreateNode(SingleListType node);
// 单链表的尾插
void SingleListPushBack(SingleList** pphead , SingleListType node);
// 单链表的头插
void SingleListPushFront(SingleList** pphead , SingleListType node);
// 单链表的头删
void SingleListPopFront(SingleList** pphead);
// 单链表的尾删
void SingleListPopBack(SingleList** pphead);
// 单链表的查找
SingleList* SingleListFind(SingleList* phead , SingleListType node);
// 单链表 pos 位置前插入
void SingleListInsert(SingleList** pphead , SingleList* pos , SingleListType node);
// 单链表对应位置删除
void SingleListErase(SingleList** pphead, SingleList* pos);
// 单链表 pos 位置后插入
void SingleListInsertAfter(SingleList* pos, SingleListType node);
// 单链表 pos 位置后删除
void SingleListEraseAfter(SingleList* pos);

⭕️ 单链表的打印

void SingleListPrint(SingleList* phead) {
	SingleList* cur = phead;

	while (cur != NULL) {
		printf("%d->", cur->data);
		cur = cur->next;
	}

	printf("NULL\n");
}

⭕️ 创建新结点

SingleList* SingleListCreateNode(SingleListType node) {
	SingleList* newNode = (SingleList*)malloc(sizeof(SingleList));
	assert(newNode);
	newNode->data = node;
	newNode->next = NULL;

	return newNode;
}

⭕️ 单链表的尾插

void SingleListPushBack(SingleList** pphead, SingleListType node) {
	assert(pphead);

	// 创建新结点
	SingleList* newNode = SingleListCreateNode(node);

	// 空链表的情况
	if (*pphead == NULL) {
		*pphead = newNode;
	}
	else {
		// 非空链表的情况
		SingleList* tail = *pphead;
		while (tail->next != NULL) {
			tail = tail->next;
		}

		tail->next = newNode;
	}
}

⭕️ 单链表的头插

void SingleListPushFront(SingleList** pphead, SingleListType node) {

	assert(pphead);

	// 创建新结点
	SingleList* newNode = SingleListCreateNode(node);

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

⭕️ 单链表的头删

void SingleListPopFront(SingleList** pphead) {
	assert(pphead);

	// 空链表
	assert(*pphead);

	SingleList* next = (*pphead)->next;
	free(*pphead);
	*pphead = next;
}

⭕️ 单链表的尾删

void SingleListPopBack(SingleList** pphead) {
	assert(pphead);
	
	// 空链表
	assert(*pphead);

	// 只有一个结点的情况
	if ((*pphead)->next == NULL) {
		free(*pphead);
		*pphead = NULL;
	}
	else {
		// 多个结点的情况
		SingleList* tail = *pphead;
		SingleList* tailPrev = NULL;

		while (tail->next != NULL) {
			tailPrev = tail;
			tail = tail->next;
		}
		free(tail);
		tail = NULL;
		tailPrev->next = NULL;
	}
}

⭕️ 单链表的查找

SingleList* SingleListFind(SingleList* phead, SingleListType node) {
	SingleList* cur = phead;

	while (cur != NULL) {
		if (cur->data == node) {
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

⭕️ 单链表 pos 位置前插入

void SingleListInsert(SingleList** pphead, SingleList* pos, SingleListType node) {

	assert(pos);
	assert(pphead);

	// 创建新结点
	SingleList* newNode = SingleListCreateNode(node);

	if (*pphead == pos) {
		newNode->next = *pphead;
		*pphead = newNode;

		// 复用
		// SingleListPushFront(pphead , node);
	}
	else {
		SingleList* cur = *pphead;

		while (cur->next != pos) {
			cur = cur->next;
		}
		newNode->next = cur->next;
		cur->next = newNode;
	}
}

⭕️ 单链表 pos 位置删除

void SingleListErase(SingleList** pphead, SingleList* pos) {
	assert(pphead);

	assert(pos && *pphead);

	if (*pphead == pos) {
		SingleList* next = (*pphead)->next;
		free(*pphead);
		*pphead = next;

		// 复用
		// SingleListPopFront(pphead);
	}
	else {
		SingleList* cur = *pphead;

		while (cur->next != pos) {
			cur = cur->next;
		}

		cur->next = pos->next;
		free(pos);

	}
}

⭕️ 单链表 pos 位置后插入

void SingleListInsertAfter(SingleList* pos, SingleListType node) {
	assert(pos);

	SingleList* newNode = SingleListCreateNode(node);
	newNode->next = pos->next;
	pos->next = newNode;
}

⭕️ 单链表 pos 位置后删除

void SingleListEraseAfter(SingleList* pos) {
	assert(pos);

	// 尾没有后一个结点
	assert(pos->next != NULL);


	SingleList* del = pos->next;
	pos->next = del->next;
	free(del);
}

🌠 单链表测试

void SingleListTest() {
	SingleList* pList = NULL;

	SingleListPushFront(&pList, 1);
	SingleListPushFront(&pList, 2);
	SingleListPushFront(&pList, 3);
	SingleListPushFront(&pList, 4);
	SingleListPrint(pList);

	SingleList* result = SingleListFind(pList , 2);
	if (result != NULL) {
		result->data = 20;
	}
	SingleListPrint(pList);

	result = SingleListFind(pList, 20);
	if (result != NULL) {
		SingleListInsert(&pList , result , 40);
	}
	SingleListPrint(pList);

	result = SingleListFind(pList, 1);
	if (result != NULL) {
		SingleListErase(&pList , result);
	}
	SingleListPrint(pList);
}

int main() {

	SingleListTest();

	return 0;
}

在这里插入图片描述


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

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

相关文章

OPLS-DA分析,组间差异 图形详解

OPLS-DA分析&#xff0c;组间差异 在上一场小工具讲解中&#xff0c;小姐姐给大家介绍了PLS-DA的原理及用途&#xff0c;而在代谢组学数据分析中&#xff0c;除去PLS-DA以外&#xff0c;OPLS-DA分析也是非常常见的&#xff0c;仅一个字母之差&#xff0c;那二者到底有何差别&am…

HTML select 用法及常用事件

前言 用于记录开发中常用到的&#xff0c;快捷开发 简单实例 <select><option value"volvo">Volvo</option><option value"saab">Saab</option><option value"mercedes">Mercedes</option><opt…

【WSN定位】基于浣熊优化算法的多通信半径和跳距加权Dvhop定位算法【Matlab代码#46】

文章目录 【可更换其他算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】1. Dvhop定位算法2. 原始浣熊优化算法2.1 开发阶段2.2 探索阶段 3. 多通信半径和跳距加权策略3.1 多通信半径策略3.2 跳距加权策略 4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他…

超细,设计一个“完美“的测试用例,用户登录模块实例...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 好的测试用例一定…

ad18学习笔记七:drc检查在线和批量的区别

Altium Designer 22 DRC规则检查解析 - 哔哩哔哩 硬件工程师基本功&#xff1a;DRC设置要点详解-凡亿课堂 AD中PCB检查设计错误规则设置&#xff08;DRC检查配置&#xff09;_ad怎么检查pcb有没有错误_没有价值的生命的博客-CSDN博客 Altium Designer之DRC检查学习笔记_ad d…

【Linux】基于环形队列的生产者消费者模型的实现

文章目录 前言一、基于环形队列的生产者消费者模型的实现 前言 上一篇文章我们讲了信号量的几个接口和基于环形队列的生产者消费者模型&#xff0c;下面我们就快速来实现。 一、基于环形队列的生产者消费者模型的实现 首先我们创建三个文件&#xff0c;分别是makefile&#x…

【C++】医学影像归档和通信系统-PACS

一、PACS是通过DICOM3.0国际标准接口&#xff0c;将CT、超声、放射检查(DR)、核磁、磁共振&#xff08;MR)等多种医学影像以数字化的形式保存&#xff0c;提供授权方式查看和调回&#xff0c;并提供一些辅助诊断管理功能的系统。 二、PACS系统是HIS系统的重要组成部分&#xff…

强化学习路径优化:基于Q-learning算法的机器人路径优化(MATLAB)

一、强化学习之Q-learning算法 Q-learning算法是强化学习算法中的一种&#xff0c;该算法主要包含&#xff1a;Agent、状态、动作、环境、回报和惩罚。Q-learning算法通过机器人与环境不断地交换信息&#xff0c;来实现自我学习。Q-learning算法中的Q表是机器人与环境交互后的…

打造自己的分布式MinIO对象存储

MinIO是一个对象存储解决方案&#xff0c;它提供了一个与Amazon Web Services S3兼容的API&#xff0c;并支持所有核心S3特性。MinIO旨在部署在任何地方——公共云或私有云、裸机基础架构、协调环境和边缘基础架构。 分布式MinIO如何工作 Server Pool由多个Minio服务节点与其附…

OPNET Modeler 怎么修改背景颜色

OPNET Modeler 软件中除了顶层的网络模型&#xff0c;节点模型和进程模型中的默认背景色都是灰色的。 节点模型背景颜色如下图所示。 进程模型背景颜色如下图所示。 使用时间长了发现这个灰色背景对眼睛保护还真不错&#xff0c;而且在这种灰色背景下&#xff0c;你添加包流线…

高压线路零序电流方向保护程序逻辑原理(四)

2&#xff0e;全相循环程序逻辑框图 全相循环程序逻辑简图如图3&#xff0d;18所示。程序入口首先检测标志位UQDB1&#xff0c;在采样中断服务程序中采用3U。突变量来区分接地故障和TA断线&#xff0c;接地故障时Δ3U。大于定值&#xff0c;置标志位UQDB1&#xff0c;这是11型…

web标签的使用

一、iframe标签的使用 iframe参数说明 实例&#xff1a; <body><iframe width"400" height"400" name"abc"></iframe><br /><ul><a href"01.table.html" target"abc">01.table.html&l…

使用docker安装mysql主从集群

1.安装MySQL主容器 1.1首先&#xff0c;使用以下命令创建MySQL主容器&#xff1a; sudo docker run --name mysql-master -p 3306:3306 -e MYSQL_ROOT_PASSWORD123456 -d mysql:latest 在这里&#xff0c;使用了Docker官方提供的MySQL镜像&#xff0c;并且使用了MySQL的默认3…

浅谈自动化测试框架开发,有你们不会知道的吗?

在自动化测试项目中&#xff0c;为了实现更多功能&#xff0c;我们需要引入不同的库、框架。 首先&#xff0c;你需要将常用的这些库、框架都装上。 pip install requests pip install selenium pip install appium pip install pytest pip install pytest-rerunfailures pip …

以中非经贸连线,看星沙如何练就一流营商环境

不知不觉&#xff0c;“一带一路”倡议提出已有十年&#xff0c;回望过去十年间&#xff0c;在“一带一路”倡议推动下&#xff0c;中国与各国合作共识不断凝聚&#xff0c;国际感召力持续增强&#xff0c;共建“一带一路”的朋友圈持续扩大&#xff0c;遍布亚、欧、非等五大洲…

往数据库插入数据时出现了多条重复数据

业务场景 钉钉端发起审批流程后&#xff0c;会回调开发者后台的callback接口&#xff0c;然后callback接口逻辑处理时会对一些数据做入库处理&#xff0c;但是突然发现数据库中出现了很多重复的数据 问题发现 业务代码进行断点&#xff0c;发现并无异常&#xff0c;就是一条…

探索思维导图:提升思维能力与效率的利器

思维导图作为一种强大的思考工具&#xff0c;已经被广泛应用于各个领域&#xff0c;从学习、工作到创意思维和项目管理。 本文将为您介绍思维导图的基本概念、使用方法以及它对思维能力和效率提升的价值。通过学习和掌握思维导图&#xff0c;您将能够更系统地组织和表达您的思…

scss中写3元运算

为真选第1个参数&#xff0c;为假选第2个参数 前端基础——sass的使用_sass 三元运算_ccopcx的博客-CSDN博客

LabVIEW进行临床肝透析试验

LabVIEW进行临床肝透析试验 慢性肾衰竭患者可以在透析或肾移植的帮助下大大延长其预期寿命。肝病患者需要与透析相当的治疗作为肝移植的替代方案。肾透析可清除患者血液中的水基毒素&#xff0c;肝脏透析需要消除与蛋白质相关的毒素。 为了降低肝病患者的高死亡率&#xff0c…

JNPF可视化平台的搭建及使用

目录 一、前言 二、可视化平台介绍 三、搭建可视化平台 【表单设计】 【报表设计】 【流程设计】 【代码生成器】 四、使用可视化平台 前后端分离&#xff1a; 多数据源&#xff1a; 预置功能&#xff1a; 私有化部署&#xff1a; 五、总结 一、前言 可视化低代码平台是一种快速…