链表(C语言)

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

目录

一.链表的概念

二.链表的分类 

三.链表的实现 

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.mzph.cn/web/254.shtml

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

相关文章

瑞芯微RK3328(ROC-RK3328-PC)buildroot 开发QT的hello world

第一部分&#xff1a;编译rk3328 sdk 0. 环境 - EC-R3328PC&#xff08;ROC-RK3328-PC&#xff09; - ubuntu18&#xff08;100GB&#xff09; 1. 安装依赖 sudo apt-get updatesudo apt-get install repo git-core gitk git-gui gcc-arm-linux-gnueabihf u-boot-tools devi…

【系统移植三】uboot移植

开发板类型&#xff1a;emmc、7寸屏 1 NXP官方开发板uboot编译测试 1.1 获取源码 1&#xff09;源码路径&#xff1a;1、例程源码->4、NXP 官方原版 Uboot 和 Linux -> uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2。 2&#xff09;将源码拷贝到ubuntu中的~/linux/IMX6…

Linux 目录结构与基础查看命令

介绍 目录结构如下 /bin&#xff1a;存放着用户最经常使用的二进制可执行命令&#xff0c;如cp、ls、cat等。这些命令是系统管理员和普通用户进行日常操作所必需的。 /boot&#xff1a;存放启动系统使用的一些核心文件&#xff0c;如引导加载器&#xff08;bootstrap loader…

采用C#.Net +JavaScript 开发的云LIS系统源码 二级医院应用案例有演示

采用C#.Net JavaScript 开发的云LIS系统源码 二级医院应用案例有演示 一、系统简介 云LIS是为区域医疗提供临床实验室信息服务的计算机应用程序&#xff0c;可协助区域内所有临床实验室相互协调并完成日常检验工作&#xff0c;对区域内的检验数据进行集中管理和共享&#xff0…

4*5的矩阵(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;int i 0;int j 0;int result 0;//嵌套循环输出&#xff1b;for (i 1; i < 4; i){//列…

L2正则化——解释为什么可以减少模型的复杂度

L2正则化是一种用于机器学习模型的技术&#xff0c;旨在减少模型的复杂度&#xff0c;从而提高其泛化能力。在L2正则化中&#xff0c;通过添加一个惩罚项&#xff0c;模型的权重被迫保持较小的值&#xff0c;这有助于防止过拟合&#xff0c;即模型在训练数据上表现良好但在未见…

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

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

单链表的基本操作实现:初始化、尾插法、头插法、输出单链表、求表长、按序号查找、按值查找、插入结点、删除结点。

1.参考学习博文&#xff08;写的相当好的文章&#xff09;&#xff1a; http://t.csdnimg.cn/AipNl 2.关于我的总结&#xff1a; 定义单链表&#xff1a; typedef struct LNode {Elemtype data;struct LNode* next; }LNode; data用来存放元素值&#xff0c;next用来指向后…

【算法】反转链表

本题来源---《反转链表》 题目描述&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输…

医学图像三维重建与可视化系统 医学图像分割 区域增长

医学图像的三维重建与可视化&#xff0c;这是一个非常有趣且具有挑战性的课题&#xff01;在这样的项目中&#xff0c;可以探索不同的医学图像技术&#xff0c;比如MRI、CT扫描等&#xff0c;然后利用这些图像数据进行三维重建&#xff0c;并将其可视化以供医生或研究人员使用。…

C++中的继承与多态

一、继承&#xff1a; 1.什么是继承&#xff1f; 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。继承呈现了面向对象…

golang map总结

目录 概述 一、哈希表原理 哈希函数 哈希表和哈希函数的关系 哈希表的优势 哈希冲突 什么是哈希冲突 如何处理哈希冲突 链表法 开放寻址法 哈希表常见操作过程 存储数据 检索数据 删除数据 常用的哈希算法 哈希表的应用场景 二、golang map map的内部结构 h…

Docker Volume (存储卷)

什么是存储卷? 存储卷就是将宿主机的本地文件系统中存在的某个目录直接与容器内部的文件系统上的某一目录建立绑定关系。这就意味着&#xff0c;当我们在容器中的这个目录下写入数据时&#xff0c;容器会将其内容直接写入到宿主机上与此容器建立了绑定关系的目录。在宿主机上…

选课成绩管理系统

文章目录 员工管理系统一、项目演示二、项目介绍三、系统部分功能截图四、部分代码展示五、底部获取项目&#xff08;9.9&#xffe5;&#xff09; 员工管理系统 一、项目演示 课程管理系统 二、项目介绍 基于springbootvue的前后端分离选课成绩管理系统 该系统可做课程管理…

基础算法之二分算法

前言 本次博客&#xff0c;将要介绍二分算法的基本原理以及如何使用&#xff0c;深入浅出 二分可以针对整型以及浮点型接下来对其讲解希望对小白有所帮助吧 整型的二分法 一般要在一个数组中猜出一个数是否存在我们可以遍历一遍整个数组&#xff0c;判断是否存在&#xff0…

使用Windows11自带的WSL安装Ubuntu Linux系统教程

WSL介绍 WSL全称Windows Subsystem for Linux&#xff0c;它是Windows10带来的新特性&#xff0c;用于Windows系统上的Linux子系统。也就是说&#xff0c;可以在Windows系统中获取Linux系统&#xff0c;这个过程无需通过虚拟机&#xff0c;而是直连计算机硬件。 简而言之&#…

Linux--进程间的通信-命名管道

前文&#xff1a; Linux–进程间的通信-匿名管道 Linux–进程间的通信–进程池 命名管道的概念 命名管道是一种进程间通信&#xff08;IPC&#xff09;机制&#xff0c;运行不同进程之间进行可靠的、单向或双向的数据通信。 特点和作用&#xff1a; 跨平台性&#xff1a;在W…

ResNet最新变体!性能反超Transformer,模型准确率达98.42%

目前ResNet&#xff08;残差网络&#xff09;有两大主流创新思路&#xff1a;一是与其他技术或模型结合&#xff0c;比如前文讲到的ResNetTransformer&#xff1b;二是在原始设计的基础上进行改进。 尽管ResNet通过残差学习有效改善了深层网络的训练和性能&#xff0c;但同时它…

永磁同步电机无感FOC(扩展卡尔曼滤波EKF位置观测控制)

文章目录 1、前言2、扩展卡尔曼滤波器原理2.1 预测阶段&#xff08;时间更新阶段&#xff09;2.2 校正阶段&#xff08;状态更新阶段&#xff09; 3、永磁同步电机EKF的模型4、永磁同步电机EKF的无位置状态观测仿真4.1 核心模块&#xff08;在滑膜、龙伯格、磁链等观测器基础上…

三角洲期刊投稿发表论文

《三角洲》杂志是由国家新闻出版总署批准&#xff0c;南通市委宣传部主管&#xff0c;南通日报社、南通市文学艺术界联合会主办的正规文学类期刊。适用于发表高品质文学学术作品&#xff0c;科研机构的专家学者以及高等院校的师生等具有原创性的学术理论、工作实践、科研成果和…