链表(C语言)

news2024/12/26 20:57:35

前言:前面几篇文章我们详细介绍了顺序表,以及基于顺序表来实现的通讯录。今天我们连介绍一下链表的下一个结构链表。那么链表和顺序表究竟有什么区别呢?他们两个的优缺点分别是什么。今天这篇文章就带大家了解一下链表。

目录

一.链表的概念

二.链表的分类 

三.链表的实现 

1.尾插链表

 2.尾删链表

3.头插链表 

4.头删链表

5.查找节点

6.打印链表

 7.指定位置后插入链表

8.删除指定位置链表

三.链表所有代码

四.结言


一.链表的概念

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

首先我们先构造一个链表的基本结构:

typedef int ListType;
typedef struct List
{
	ListType x;
	struct List* next;
}List;

这里我们x存放我们需要储存的数据,next指针指向下一个数据节点的地址。

大概就是这样一个形态。

 相当于一个火车的模型一节连着一节,这样就不用担心找不到下一节车厢了。

注意:

1.链式结构在逻辑上来讲是连续的,但是在物理结构上不一定连续。

2.现时结构上的内存都是从堆上申请过来的。

3.从堆上申请的空间,是按照一定的策略分配的可能连续也可能不连续。

二.链表的分类 

从结构上来讲链表分为:

1.单向或双向

2. 带头或不带头

3.循环或非循环

但是我们实际应用中最常用到的还是:

无头单向非循环链表

有头双向循环链表

 

1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结
构的子结构,如哈希桶、图的邻接表等等。

2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都
是带头双向循环链表。

三.链表的实现 

1.尾插链表

这里由于许多函数都要用到创建内容,所以我们把创建空间分装成一个函数以便后续的操作。

List* BuyMemory(List* ls, ListType x)
{
	List* tem = (List*)malloc(sizeof(List));
	if (tem == NULL)
	{
		perror(malloc);
		return;
	}
	tem->val = x;
	tem->next = NULL;
	return tem;
}

接下来是尾插的内容:

void ListBackPush(List** ls, ListType x)
{
	List*newnext=BuyMemory(*ls,x);
	if (*ls == NULL)
	{
		*ls = newnext;
		(*ls)->next = NULL;
	}
	else
	{
		List* pcur = *ls;
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		pcur->next = newnext;
	}
}}

 2.尾删链表

void ListBackPop(List** ls)
{
	assert(*ls);
	if ((*ls)->next == NULL)
	{
		*ls = NULL;
		return;
	}
	List* pcur = *ls;
	while (pcur->next->next)
	{
		pcur = pcur->next;
	}
	pcur->next = NULL;
	free(pcur->next);
	
}

尾删我们只需要找到下一个节点为空的节点然后将他free掉就可以实现我们的尾删操作。

3.头插链表 

void ListFrontPush(List** ls, ListType x)
{
	List* newnext = BuyMemory(*ls, x);

		newnext->next = (*ls);
		(*ls) = newnext;
	
}

这里我们需要注意的是 newnext->next = (*ls)   (*ls) = newnext这两句代码的位置不能改变否则就找不到(*ls)的下一个节点。

4.头删链表

void ListFrontPop(List** ls)
{
	assert(*ls);
	List* pcur = *ls;
	(*ls) = pcur->next;
	free(pcur);
	pcur = NULL;
}

与头插链表一样需要注意的是链表之间的前后关系,插入之前要弄清楚每个节点的后节点于前节点有什么改变即可。

5.查找节点

List* ListFind(List** ls, ListType x)
{
	assert(*ls);
	List* pcur = *ls;
	int count = 1;
	while (pcur->val != x)
	{
		pcur = pcur->next;
		count++;
	}
	if (pcur)
	{
		prinft("找到了\n");
		return pcur;
	}
	else
	{
		printf("找不到\n");
		return 0;
	}
}

遍历链表查找所寻找节点的val,找到后返回该节点的地址。 如果找不到则返回0。

6.打印链表

void ListPrint(List** ls)
{
	assert(*ls);
	List* pcur = *ls;
	while (pcur)
	{
		printf("%d->", pcur->val);
		pcur = pcur->next;
	}
}

我们所需要做的就是遍历链表并打印。

 7.指定位置后插入链表

void ListRandomPush(List** ls, ListType x, List* flag)
{
	assert(ls);
	assert(*ls);
	List* newnext = BuyMemory(*ls, x);
	List* pcur = *ls;
	while (pcur != flag)
	{
		pcur = pcur->next;
	}
	newnext->next = pcur->next;
	pcur->next = newnext;
}

同样需要注意的是每个节点之间的关系,要注意 newnext->next = pcur->next; pcur->next = newnext位置不可以改变否则会找不到pcur的next。

8.删除指定位置链表

void ListRandomPop(List** ls, List* flag)
{
	assert(ls);
	assert(*ls);
	List* pcur = *ls;

	while (pcur->next != flag)
	{
		pcur = pcur->next;
	}
	List* prev = pcur->next;
	pcur->next = pcur->next->next;
	free(prev);
	prev = NULL;
}

我们需要注意各个节点之间的关系,处理好他们的链接关系就可以了。

还有许多可以实现的操作但实现方法大都大同小异,以上的代码就可以解决大部分的实际问题,大家感兴趣的可以自己去写一下其他的操作。

三.链表所有代码

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

typedef int ListType;
typedef struct List
{
	ListType val;
	struct List* next;
}List;

void ListBackPush(List** ls,ListType x);
void ListBackPop(List** ls);
void ListFrontPush(List** ls, ListType x);
void ListFrontPop(List** ls);
List* ListFind(List** ls, ListType x);
void ListRandomPush(List** ls, ListType x,List*flag);
void ListRandomPop(List** ls, List* flag);
void ListPrint(List** ls);

List.c
nclude"List.h"


List* BuyMemory(List* ls, ListType x)
{
	List* tem = (List*)malloc(sizeof(List));
	if (tem == NULL)
	{
		perror(malloc);
		return;
	}
	tem->val = x;
	tem->next = NULL;
	return tem;
}
void ListBackPush(List** ls, ListType x)
{
	List*newnext=BuyMemory(*ls,x);
	if (*ls == NULL)
	{
		*ls = newnext;
		(*ls)->next = NULL;
	}
	else
	{
		List* pcur = *ls;
		while (pcur->next)
		{
			pcur = pcur->next;
		}
		pcur->next = newnext;
	}
}
void ListBackPop(List** ls)
{
	assert(*ls);
	if ((*ls)->next == NULL)
	{
		*ls = NULL;
		return;
	}
	List* pcur = *ls;
	while (pcur->next->next)
	{
		pcur = pcur->next;
	}
	pcur->next = NULL;
	free(pcur->next);
	
}
void ListFrontPush(List** ls, ListType x)
{
	List* newnext = BuyMemory(*ls, x);

		newnext->next = (*ls);
		(*ls) = newnext;
	
}
void ListFrontPop(List** ls)
{
	assert(*ls);
	List* pcur = *ls;
	(*ls) = pcur->next;
	free(pcur);
	pcur = NULL;
}
List* ListFind(List** ls, ListType x)
{
	assert(*ls);
	List* pcur = *ls;
	int count = 1;
	while (pcur->val != x)
	{
		pcur = pcur->next;
		count++;
	}
	if (pcur)
	{
		printf("找到了\n");
		return pcur;
	}
	else
	{
		printf("找不到\n");
		return 0;
	}
}
void ListPrint(List** ls)
{
	assert(*ls);
	List* pcur = *ls;
	while (pcur)
	{
		printf("%d->", pcur->val);
		pcur = pcur->next;
	}
}
void ListRandomPush(List** ls, ListType x, List* flag)
{
	assert(ls);
	assert(*ls);
	List* newnext = BuyMemory(*ls, x);
	List* pcur = *ls;
	while (pcur != flag)
	{
		pcur = pcur->next;
	}
	newnext->next = pcur->next;
	pcur->next = newnext;
}
void ListRandomPop(List** ls, List* flag)
{
	assert(ls);
	assert(*ls);
	List* pcur = *ls;

	while (pcur->next != flag)
	{
		pcur = pcur->next;
	}
	List* prev = pcur->next;
	pcur->next = pcur->next->next;
	free(prev);
	prev = NULL;
}

text.c 

#include"List.h"
void test01()
{
	List* ls = NULL;

	ListBackPush(&ls, 1);
	ListBackPop(&ls);
	ListFrontPush(&ls, 1);
	ListBackPush(&ls, 2);
	ListBackPush(&ls, 3);
	ListBackPush(&ls, 4);
	List* ret = ListFind(&ls, 2);
	ListRandomPush(&ls, 100, ret);
	List* ret1 = ListFind(&ls, 100);
	ListRandomPop(&ls, ret1);
	ListPrint(&ls);
	//ListFrontPop(&ls);

}
int main()
{
	test01();
	return 0;
}

四.结言

以上就是链表操作的所有内容了,我们实现的只是无头单向非循环链表,但是其他链表的实现操作也是万变不离其中的只需要处理好各个节点之间的关系就问题就迎刃而解了。

还有请喜欢的朋友们一键三连哦!

谢谢大家了!!

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

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

相关文章

新质生产力走红背后,华为云的基本盘和自我修养

文 | 智能相对论 作者 | 沈浪 今年全国两会期间走红的“新质生产力”正成为中国产业转型升级的关键方向。政府工作报告更是把“大力推进现代化产业体系建设&#xff0c;加快发展新质生产力”放在今年政府工作任务的重要位置。 何为新质生产力&#xff1f;简单来说&#xff0…

C++奇迹之旅:探索C++拷贝构造函数

文章目录 &#x1f4dd;拷贝构造函数&#x1f320; 概念&#x1f309;特征 &#x1f320;浅拷贝(值拷贝)&#x1f309;深拷贝 &#x1f320;拷贝构造函数典型调用场景&#x1f320;应用时效率的思考&#x1f6a9;总结 &#x1f4dd;拷贝构造函数 &#x1f320; 概念 在现实生…

web轮播图

思路&#xff1a; 例如&#xff1a;有5张轮播的图片&#xff0c;每张图片的宽度为1024px、高度为512px.那么轮播的窗口大小就应该为一张图片的尺寸&#xff0c;即为&#xff1a;1024512。之后将这5张图片0px水平相接组成一张宽度为&#xff1a;5120px,高度依然为&#xff1a;5…

SpringBoot - Logback 打印第三方 Jar 日志解决方案

问题描述 最近碰到一个很苦恼的问题&#xff0c;就是第三方的 Jar 在自己项目里日志可以正常输出&#xff0c;但是一旦被引用到其他项目里&#xff0c;就日志死活打不出来…… 解决方案 这是原来的配置 - logback.xml <?xml version"1.0" encoding"UTF-8…

5G-A有何能耐?5G-A三载波聚合技术介绍

2024年被称作5G-A元年。5G-A作为5G下一阶段的演进技术&#xff0c;到底有何能耐呢&#xff1f; 三载波聚合&#xff08;3CC&#xff09;被认为是首个大规模商用的5G-A技术&#xff0c;将带来手机网速的大幅提升。 █ 什么是3CC 3CC&#xff0c;全称叫3 Component Carriers…

python聊天室

python聊天室 文章目录 python聊天室chat_serverchat_client使用方式1.局域网聊天2.公网聊天 下面是一个简单的示例&#xff0c;包含了chat_client.py和chat_server.py的代码。 chat_server chat_server.py监听指定的端口&#xff0c;并接收来自客户端的消息&#xff0c;并将消…

一个 .net 8 + Azure 登录 + Ant Design Blazor 的基本后台框架

一个 .net 8 Azure 登录 Ant Design Blazor 的基本后台框架 主界面使用了 Ant Design Blazor 项目模板搭建 后台技术是 .net 8 Blazor run at server 模式 登录方式使用 Azure 实现了菜单导航和路由 此外实现了读取和修改本地Json文件的功能&#xff0c;不是必须的&#x…

【Python】OPC UA模拟服务器实现

目录 服务器模拟1. 环境准备2. 服务器设置3. 服务器初始化4. 节点操作5. 读取CSV文件6. 运行服务器 查看服务器客户端总结 在工业自动化和物联网&#xff08;IoT&#xff09;领域&#xff0c;OPC UA&#xff08;开放平台通信统一架构&#xff09;已经成为一种广泛采用的数据交换…

Leo赠书活动-24期 【三大层次学习企业架构框架TOGAF】文末送书

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

鸿蒙开发岗突增!它和前端开发到底有哪些区别和联系?

2024年1 月 18 日&#xff0c;鸿蒙 Next 预览版面向开发者正式开放申请。至此&#xff0c;鸿蒙原生应用版图已成型&#xff0c;这个中国自主研发的操作系统&#xff0c;正式走上了独立之路。 有许多的公司都陆续地加入了鸿蒙原生应用开发的队列&#xff0c;从年初宣布的200个应…

网络基础-基于TCP协议的Socket通讯

一、Socket通讯基于TCP协议流程图 UDP 的 Socket 编程相对简单些不在介绍。 二、 服务端程序启动 服务端程序要先跑起来&#xff0c;然后等待客户端的连接和数据。 服务端程序首先调用 socket() 函数&#xff0c;创建网络协议为 IPv4&#xff0c;以及传输协议为 TCP 的…

基于数据库现有表导出为设计文档

1.查询 SELECTCOLUMN_NAME 字段名,COLUMN_COMMENT 字段描述,COLUMN_TYPE 字段类型,false as 是否为主键 FROMINFORMATION_SCHEMA.COLUMNS wheretable_NAME region -- 表名2.查询结果 3.导出为excel

求交错且分母为阶乘的和(java)

import java.util.*; public class APP1{public static void main(String[] args){double sum0.0;int n0;int flag1;int fm1;Scanner reader new Scanner(System.in);System.out.println("请输入n的值&#xff1a;");nreader.nextInt();for(int i0;i<n;i){fm*i; …

【笔试训练】day5

今天的题&#xff0c;最后一题忘公式了&#xff0c;卡了一会推出来了 1、游游的you 思路&#xff1a; 看清题目意思就行&#xff0c;这里的相邻两个o可以重复算&#xff0c;也就是说&#xff0c;“ooo”算2分。 先算you的得分&#xff0c;再算oo 对了&#xff0c;不开long lo…

图神经网络实战——利用节点回归预测网络流量

图神经网络实战——利用节点回归预测网络流量 0. 前言1. 数据集分析2. 实现 GCN 模型执行节点回归3. 模型测试相关链接 0. 前言 在机器学习中&#xff0c;回归指的是对连续值的预测。通常与分类形成鲜明对比&#xff0c;分类的目标是找到正确的类别(即离散值&#xff0c;而非连…

C++_智能指针

文章目录 前言一、智能指针原理二、库支持的智能指针类型1.std::auto_ptr2.std::unique_ptr3.std::shared_ptr4.std::weak_ptr 三、删除器总结 前言 智能指针是一种采用RAII思想来保护申请内存不被泄露的方式来管理我们申请的内存&#xff0c;对于RAII&#xff0c;我们之前也已…

这是刚发布的人形机器人?不,分明是《午夜凶铃》现实版

波士顿动力公司大名鼎鼎的人形机器人Atlas&#xff0c;你一定见识过吧。 Atlas可以像人一样行走、奔跑和攀爬 | 波士顿动力公司 这款用液压系统打造的机器人产品&#xff0c;经过十多年的调试升级&#xff0c;才终于拥有了人类一般灵活的身手。在波士顿动力公司历年来放出的视频…

OpenHarmony UI开发-ohos-svg

简介 ohos-svg是一个SVG图片的解析器和渲染器&#xff0c;解析SVG图片并渲染到页面上。它支持大部分 SVG 1.1 规范&#xff0c;包括基本形状、路径、文本、样式和渐变,它能够渲染大多数标准的 SVG 图像。ohos-svg的优点是性能好、内存占用低。 效果展示 SVG图片解析并绘制: …

第七周学习笔记DAY.4-方法重写与多态

学完本次课程后&#xff0c;你能够&#xff1a; 实现方法重写 深入理解继承相关概念 了解Object类 会使用重写实现多态机制 会使用instanceof运算符 会使用向上转型 会使用向下转型 什么是方法重写 方法的重写或方法的覆盖&#xff08;overriding&#xff09; 1.子类根据…

【STM32CubeIDE 1.15.0】汉化包带路径配置过程

一、IDE软件下载 二、汉化版包路径 三、IDE软件板载汉化包 一、IDE软件下载 ST官网IDE下载链接 二、汉化版包路径 https://mirrors.ustc.edu.cn/eclipse/technology/babel/update-site/ 找不到就到.cn后面一级一级进 三、IDE软件板载汉化包 https://mirrors.ustc.edu…