线性表--链表--单链表(不带头单向不循环链表)

news2024/11/16 9:36:11

关于顺序表存在的问题:

1.中间/头部的插⼊删除,时间复杂度为O(N)
2.增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗
3.增容⼀般是呈2倍的增长,势必会有一定的空间浪费
要如何解决这些问题?用线性表的链表就能解决

什么是链表?

链表是一种物理存储结构非连续,非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,逻辑结构上呈线性。

就如火车车厢之间的关系,可以通过挂钩链接,不用是再断开链接。

 链表的分类

链表含有6种元素,

其中最常见的是不带头单向不循环链表和带头双向循环链表;

这章将介绍单链表(不带头单向不循环链表)及其实现;

单链表

每个个体称之为节点/结点,每个节点即为一个结构体,每个结构体存着数据和指向下一个节点的指针,使之成为一条链;

链式在逻辑上是连续的,在物理结构上不一定连续;节点一般从堆上申请,从堆上申请来的空间,是按照⼀定策略分配出来的,每次申请的空间可能连续,可能不连续。

单链表的实现

 先创建节点的基本结构,数据类型重定义便于替换;

在单链表基础上实现增删查改的功能。

申请空间,创造节点

 将申请的节点next(下一个指向)先置为NULL,便于后续使用节点。

头插和尾插

尾插:

头插:

 头删和尾删

尾删:

 头删:

 查找

 指定位置之前插入数据

 指定数据之后插入数据

 删除指定位置pos的数据

 

 删除指定位置pos后面的数据

改变链表数据

 销毁链表

打印检验

 单链表代码

//SList.h


#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLTDataType;      //数据类型,重命名便于改变数据类型

typedef struct SListNode     //单链表节点结构
{
	SLTDataType data;         //数据类型,重命名便于改变数据类型
	struct SListNode* next;  //这里还不能使用SLTNode,顺序问题
}SLTNode;                    //重命名

//创造节点
SLTNode* SLTBuyNode(SLTDataType x);

//检验
void SLTPrint(SLTNode* phead);

//单链表头插/尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
void SLTPushFront(SLTNode** pphead, SLTDataType x);

//单链表头删/尾删
void SLTPopBack(SLTNode** pphead);
void SLTPopFront(SLTNode** pphead);

//查找
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x);

//指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
//指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x);

//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
//删除pos后面的节点
void SLTEraseAfter(SLTNode* pos);

//改变链表数据
void SLTChange(SLTNode* pos, SLTDataType x);

//销毁链表
void SListDestroy(SLTNode** pphead);
//SList.c


#include "SList.h"


//检验
void SLTPrint(SLTNode* phead)
{
	SLTNode* pcur = phead;//pcur指向当前节点
	while (pcur)
	{
		printf("%d->", pcur->data);
		pcur = pcur->next;
	}
	printf("NULL\n");
}


//创造节点
SLTNode* SLTBuyNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("MALLOC FAIL!\n");
		exit(1);
	}
	newnode->data = x;
	newnode->next = NULL;
	return newnode;
}


//单链表头插/尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* newnode = SLTBuyNode(x);
	//链表为空;
	if (*pphead == NULL)
	{
		*pphead = newnode;
		return;
	}
	//链表不为空
	//先遍历链表找到尾节点
	SLTNode* ptail = *pphead;
	while (ptail->next)
	{
		ptail = ptail->next;
	}
	ptail->next = newnode;
}

void SLTPushFront(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	//创造节点
	SLTNode* newnode = SLTBuyNode(x);
	//链表为空,创造节点 *pphead == NULL
	//链表不为空
	newnode->next = *pphead;
	*pphead = newnode;
}


//单链表头删/尾删
void SLTPopBack(SLTNode** pphead)
{
	assert(pphead);
	//链表为空,不能删
	assert(*pphead);

	//只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		(*pphead) = NULL;
		return;
	}
	//多个节点
	//先遍历
	SLTNode* pcur = *pphead;
	while (pcur->next->next)
	{
		pcur = pcur->next;
	}
	//销毁
	free(pcur->next);
	pcur->next = NULL;
}

void SLTPopFront(SLTNode** pphead)
{
	assert(pphead);
	//链表为空,不能删
	assert(*pphead);
	//只有一个节点
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		(*pphead) = NULL;
		return;
	}
	//多个节点
	SLTNode* temp = *pphead;
	*pphead = (*pphead)->next;//注意优先级*比->小
	free(temp);
	temp = NULL;
}


//查找
SLTNode* SLTFind(SLTNode** pphead, SLTDataType x)
{
	assert(pphead);
	SLTNode* pcur = *pphead;
	while (pcur)
	{
		if (pcur->data == x)
		{
		//	printf("找到了\n");
			return pcur;
		}
		pcur = pcur->next;
	}
	//找不到
//	printf("找不到\n");
	return NULL;
}


//指定位置之前插入数据
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{
	assert(pphead);
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	SLTNode* pcur = *pphead;
	//头插(包括了一个或者多个节点的情况)
	if (pos == *pphead)
	{
		newnode->next = pcur;
		*pphead = newnode;
		return;
	}
	//多个节点
	while (pcur->next != pos)
	{
		pcur = pcur->next;
	}
	pcur->next = newnode;
	newnode->next = pos;
}

//指定位置之后插入数据
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	SLTNode* newnode = SLTBuyNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}


//删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);
	assert(*pphead);//链表不能为空

	//删除头节点/只有一个节点
	if (pos == *pphead)
	{
		SLTNode* temp = (*pphead)->next;
		free(pos);
	    pos = NULL;
		*pphead = temp;
		return;
	}

	//多个节点
	SLTNode* pcur = *pphead;
	while (pcur->next != pos)
	{
		pcur = pcur->next;
	}
	pcur->next = pos->next;
	free(pos);
	pos = NULL;
}

//删除pos后面的节点
void SLTEraseAfter(SLTNode* pos)
{
	assert(pos);
	//不存在后面的节点
	assert(pos->next);
	//正常情况
	SLTNode* pAfter = pos->next;
	pos->next = pAfter->next;
	free(pAfter);
	pAfter = NULL;
}


//改变链表数据
void SLTChange(SLTNode* pos, SLTDataType x)
{
	assert(pos);
	pos->data = x;
}


//销毁链表
void SListDesTroy(SLTNode** pphead) 
{
	assert(pphead);
	assert(*pphead);

	SLTNode* pcur = *pphead;
	while (pcur)
	{
		SLTNode* next = pcur->next;
		free(pcur);
		pcur = next;
	}
	*pphead = NULL;
	pphead = NULL;
}

//Test.h


#include "SList.h"

void test1()
{
	SLTNode* plist = NULL;
	SLTPushFront(&plist, 4);
	SLTPushFront(&plist, 3);
	SLTPushFront(&plist, 2);
	SLTPushFront(&plist, 1);
	SLTPushBack(&plist, 5);
	SLTPushBack(&plist, 6);
	SLTPushBack(&plist, 7);
	SLTPushBack(&plist, 8);
	SLTPrint(plist);
	//SLTInsert(&plist, SLTFind(&plist, 1), 999);
	//SLTInsertAfter(SLTFind(&plist, 8), 888);
	//SLTErase(&plist, SLTFind(&plist, 1));
	//SLTErase(&plist, SLTFind(&plist, 2));
	//SLTErase(&plist, SLTFind(&plist, 3));
	//SLTErase(&plist, SLTFind(&plist, 8));
	//SLTErase(&plist, SLTFind(&plist, 5));
	//SLTErase(&plist, SLTFind(&plist, 6));
	//SLTErase(&plist, SLTFind(&plist, 7));
	//SLTErase(&plist, SLTFind(&plist, 4));
	//SLTEraseAfter(SLTFind(&plist, 1));
	//SLTEraseAfter(SLTFind(&plist, 1));
	//SLTEraseAfter(SLTFind(&plist, 1));
	//SLTEraseAfter(SLTFind(&plist, 1));
	//SLTEraseAfter(SLTFind(&plist, 1));
	//SLTEraseAfter(SLTFind(&plist, 7));
	//SLTEraseAfter(SLTFind(&plist, 1));
	//SLTChange(SLTFind(&plist, 1), 999);
	//SLTChange(SLTFind(&plist, 5), 888);
	//SLTChange(SLTFind(&plist, 8), 777);
	//SListDesTroy(&plist);

	SLTPrint(plist);

}

int main()
{
	test1();


	return 0;
}

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

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

相关文章

HCIA vlan练习

目录 实验拓扑 实验要求 实验步骤 1、交换机创建vlan 2、交换机上的各个接口划分到对应vlan中 3、trunk干道 4、路由器单臂路由 5、路由器DHCP设置 实验测试 华为交换机更换端口连接模式报错处理 实验拓扑 实验要求 根据图划分vlan&#xff0c;并通过DHCP给主机下发…

Android学习之路(22) ARouter原理解析

1.ARouter认知 首先我们从命名来看:ARouter翻译过来就是一个路由器。 官方定义&#xff1a; 一个用于帮助 Android App 进行组件化改造的框架 —— 支持模块间的路由、通信、解耦 那么什么是路由呢&#xff1f; 简单理解就是&#xff1a;一个公共平台转发系统 工作方式&…

vue项目中使用XgPlay.js播放视频

官网&#xff1a;西瓜播放器 1、首先安装下载 XgPlay.js依赖 npm i xgplayer --savenpm i xgplayer-hls.js --save2、页面引用 import FlvPlayer from "xgplayer-flv.js"; import "xgplayer/dist/index.min.css"; 3、建立dom容器 // 提供一个容器 <…

【Linux驱动】休眠与唤醒 | POLL机制 | 异步通知 | 阻塞与非阻塞 | 软件定时器

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《Linux驱动》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3d3;休眠与唤醒&#x1f3f8;内核函数&#x1f3f8;驱动框架及编程 &#x1f3d3;…

VC++中使用OpenCV进行形状和轮廓检测

VC中使用OpenCV进行形状和轮廓检测 在VC中使用OpenCV进行形状和轮廓检测&#xff0c;轮廓是形状分析以及物体检测和识别的有用工具。如下面的图像中Shapes.png中有三角形、矩形、正方形、圆形等&#xff0c;我们如何去区分不同的形状&#xff0c;并且根据轮廓进行检测呢&#…

re:从0开始的HTML学习之路 2. HTML的标准结构说明

1. <DOCTYPE html> 文档声明&#xff0c;用于告诉浏览器&#xff0c;当前HTML文档采用的是什么版本。 必须写在当前HTML文档的首行&#xff08;可执行代码的首行&#xff09; HTML4的此标签与HTML5不同。 2. <html lang“en”> 根标签&#xff0c;整个HTML文档中…

基于SpringBoot的SSM整合案例

项目目录: 数据库表以及表结构 user表结构 user_info表结构 引入依赖 父模块依赖: <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.12.RELEASE</version>…

LINUX文件fd(file descriptor)文件描述符

目录 1.文件接口 1.1open 1.2C语言为什么要对open进行封装 2.fd demo代码 第一个问题 第二个问题 打开文件流程 引言&#xff1a;在学习C语言的时候&#xff0c;我们见过很多的文件的接口&#xff0c;例如fopen&#xff0c;fwrite&#xff0c;fclose等等&#xff0c;但…

Mac NTFS 磁盘读写工具选哪个好?Tuxera 还是 Paragon?

在使用 Mac 电脑时&#xff0c;我们经常需要读写 NTFS 格式的硬盘或 U 盘。然而&#xff0c;由于 Mac 系统不支持 NTFS 格式的读写&#xff0c;因此我们需要借助第三方工具来实现这个功能。而在市场上&#xff0c;Tuxera 和 Paragon 是两款备受推崇的 Mac NTFS 磁盘读写工具。那…

CPMS靶场练习

关键&#xff1a;找到文件上传点&#xff0c;分析对方验证的手段 首先查看前端发现没有任何上传的位置&#xff0c;找到网站的后台&#xff0c;通过弱口令admin 123456可以进入 通过查看网站内容发现只有文章列表可以进行文件上传&#xff1b;有两个图片上传点 图片验证很严格…

HCIP-BGP选路实验

一.实验拓扑图 二.详细配置 R1 interface GigabitEthernet0/0/0 ip address 12.1.1.1 255.255.255.0interface LoopBack0 ip address 1.1.1.1 255.255.255.0interface LoopBack1 ip address 10.1.1.1 255.255.255.0bgp 1 router-id 1.1.1.1 peer 12.1.1.2 as-number 2ipv4-fa…

websocket实现聊天室(vue2 + node)

通过websocket实现简单的聊天室功能 需求分析如图&#xff1a; 搭建的项目结构如图&#xff1a; 前端步骤&#xff1a; vue create socket_demo (创建项目)views下面建立Home , Login组件路由里面配置路径Home组件内部开启websocket连接 前端相关组件代码&#xff1a; Login…

CVE重要通用漏洞复现java phpCVE-2021-44228

在进行漏洞复现之前我们需要在linux虚拟机上进行docker的安装 我不喜欢win上安因为不知道为什么总是和我的vmware冲突 然后我的kali内核版本太低 我需要重新安装一个新的linux 并且配置网络 我相信这会话费我不少时间 查看版本 uname -a 需要5.5或以上的版本 看错了浪…

微信小程序-03

小程序官方把 API 分为了如下 3 大类&#xff1a; 事件监听 API 特点&#xff1a;以 on 开头&#xff0c;用来监听某些事件的触发 举例&#xff1a;wx.onWindowResize(function callback) 监听窗口尺寸变化的事件 同步 API 特点1&#xff1a;以 Sync 结尾的 API 都是同步 API 特…

使用多进程库计算科学数据时出现内存错误

问题背景 我经常使用爬虫来做数据抓取&#xff0c;多线程爬虫方案是必不可少的&#xff0c;正如我在使用 Python 进行科学计算时&#xff0c;需要处理大量存储在 CSV 文件中的数据。由于每个处理过程需要很长时间才能完成&#xff0c;而您拥有多核处理器&#xff0c;所以您尝试…

SpringBoot教务管理源码

技术框架&#xff1a; springboot mybatis layui shiro jquery react 运行环境&#xff1a; jdk8 mysql5.7 IntelliJ IDEA maven nginx 系统介绍&#xff1a; 教务管理系统是一个基于网络的在线管理平台 , 帮助学校管理教务系统&#xff0c; 用一个账号解决学校教…

聪明的小羊肖恩(双指针)

题目 import java.util.Arrays; import java.util.Scanner;public class Main {public static long calc(long[] num,int max) { int l 0;int r num.length-1;long res 0;while(l<r) {while(l<r && num[l]num[r]>max) {r--;}res(r-l);l;}return res;}pub…

LeetCode---380周赛

题目列表 3005. 最大频率元素计数 3006. 找出数组中的美丽下标 I 3007. 价值和小于等于 K 的最大数字 3008. 找出数组中的美丽下标 II 一、最大频率元素计数 这题就是个简单的计数题&#xff0c;正常遍历统计数据即可&#xff0c;关键是你要会写代码逻辑。 代码如下&…

CocoaPods的安装和使用

前言 本篇文章讲述CocoaPods的安装和使用 安装cocoaPods 如果电脑没有安装过cocoaPods&#xff0c;需要先安装&#xff0c;使用下面的命令&#xff1a; sudo gem install cocoapods输入密码后开始安装&#xff0c;需要等待。。。但是我这里报错了。 The last version of d…

本地读取Excel文件并进行数据压缩传递到服务器

在项目开发过程中&#xff0c;读取excel文件&#xff0c;可能存在几百或几百万条数据内容&#xff0c;那么对于大型文件来说&#xff0c;我们应该如何思考对于大型文件的读取操作以及性能的注意事项。 类库&#xff1a;Papa Parse - Powerful CSV Parser for JavaScript 第一步…