链表|数据结构|C语言深入学习

什么是链表

离散,就是“分离的、散开的”

链表是什么样子的:

有限个节点离散分配

彼此间通过指针相连

除了首尾节点,每个节点都只有一个前驱节点和一个后继节点

首节点没有前驱结点,尾节点没有后继节点

基本概念术语:

首节点:第一个存放有效数据的节点;

尾节点:最后一个存放有效数据的节点

头节点是首节点前面的那个节点。头结点里面不存放数据,有效数据是从首节点开始存的

头结点存在的目的是什么?

对链表进行操作的时候,在前面加上一个没有实际含义的头节点可以方便对链表进行操作

头指针:指向头节点的指针变量,存放了头节点的地址

尾指针:指向尾节点的指针变量,存放了尾节点的地址

链表中所有的节点的数据类型都是一样的,包括头结点

确定一个链表最少需要几个参数

只需要一个参数:头指针

通过头指针可以得到一个链表的其他所有信息

链表节点的数据类型怎么表示

每一个节点都有数据域指针域两部分

尾节点除外的每一个节点的指针域指向了下一个节点的[节点整体]

这个[节点整体]的数据类型跟他的前一个节点的数据类型是完全一样的

也就是说,一个结构体变量中的某一成员指向了跟它整体(这个结构体变量)一样的数据类型

因为第一个节点的指针域指向了第二个节点整体,而第二个节点整体和第一个节点整体的数据类型是一模一样的

说的抽象一点,就是:某一结构体的变量中的一个成员指向了和它本身的数据类型一样的另一个变量

typedef struct Node {

int data;//数据域

struct Node* pNext;//指针域  

}NODE,*PNODE;

//NODE是struct Node类型,PNODE是struct Node*类型

/*

指针域指向了和它整体本身的数据类型一模一样的另一个变量的整体

指针域存放的是下一个节点的地址,所以应该是【下一个节点的数据类型*】 类型的指针变量

下一个节点跟这个节点本身的数据类型一样,都是struct Node类型

所以,指针域的指针变量的类型是struct Node*类型

*/

链表的分类

·单链表

·双链表

每一个节点都有两个指针域

·循环链表

能通过任何一个节点找到其他所有的节点

·非循环链表

非循环单链表的创建和遍历

#include<stdio.h>

#include<malloc.h>

#include<stdlib.h>

typedef struct Node {

int data;//数据域

struct Node* pNext;//指针域  

}NODE, * PNODE;

//NODE是struct Node类型,PNODE是struct Node*类型

/*

  指针域指向了和它整体本身的数据类型一模一样的另一个变量的整体

  指针域存放的是下一个节点的地址,所以应该是【下一个节点的数据类型*】 类型的指针变量

  下一个节点跟这个节点本身的数据类型一样,都是struct Node类型

  所以,指针域的指针变量的类型是struct Node*类型

 */

PNODE createList();

void traverseList(PNODE pHead);

int main() {

PNODE pHead = NULL;

//等价于struct Node* PHead = NULL;

pHead = createList();//创建一个非循环单链表,并将链表的头结点的地址赋给pHead

traverseList(pHead);

return 0;

}

PNODE createList() {

int len;//用来存放链表有效节点的个数

int val;//用来临时存放用户输入的节点的个数

/*

  pHead是一个头指针,pHead指向了头结点

  这个头结点不存放有效数据*/

PNODE pHead = (PNODE)malloc(sizeof(NODE));

if (pHead == NULL) {

printf("内存分配失败,程序终止\n");

exit(-1);

}

PNODE pTail = pHead;

pTail->pNext = NULL;

printf("请输入需要生成的链表节点的个数:");

scanf("%d", &len);

for (int i = 0; i < len; i++) {

printf("请输入需要生成的链表节点值:");

scanf("%d", &val);

PNODE pNew = (PNODE)malloc(sizeof(NODE));

if (pHead == NULL) {

printf("内存分配失败,程序终止\n");

exit(-1);

}

pNew->data = val;

pTail->pNext = pNew;

pNew->pNext = NULL;

pTail = pNew;

}

/*

  循环了len次,每一次都创建并分配了一个新节点,用pNew(指针变量)表示这个新节点

  创建了新节点后,为新节点数据域赋值

  创建了一个pTail指针变量,链表中没有有效节点之前pTail指向头结点(此时,头指针pHead和pTail都指向头结点)

  创建了一个新节点之后,为新节点赋值数据域,pNew->data = val

  pTail指针变量指向的节点(最开始是头结点,之后是链表中最后一个节点)的指针域存上新节点的地址pTail->pNext = pNew

  此时pTail指针变量指向的是倒数第二个节点

  将新茶入的节点的指针域置空pNew->pNext = NULL

  将pTail指针变量指到最后一个新插入的节点上,确保下一次插入新节点之前pTail总是指到当前链表最后一个节点上

  pTail = pNew*/

return pHead;

}

void traverseList(PNODE pHead) {

PNODE p = pHead->pNext;

while (NULL != p) {

printf("%d ", p->data);

p = p->pNext;

}

printf("\n");

}

非循环单链表插入节点

非循环单链表删除节点

链表排序算法

链表冒泡排序:

void sortList(PNODE pHead) {

if (isEmpty(pHead)) {

printf("链表为空,无法排序");

exit(-1);

}

PNODE p, q;

int i, j;

int n = numNode(pHead);//求链表有效节点个数

for (i = 0, p = pHead->pNext; i < n - 1; i++, p = p->pNext) {

for (j = 0, q = pHead->pNext; j < n - 1 - i; j++, q = q->pNext) {

if (q->data > q->pNext->data) {

int t = q->data;

q->data = q->pNext->data;

q->pNext->data = t;

}

}

}

}

由以下数组冒泡排序改编:

//数组冒泡排序:

for (int i = 0; i < n - 1; i++) {

for (int j = 0; j < n - 1 - i; j++) {

if (a[j] < a[j + 1]) {

int t = a[j];

a[j] = a[j + 1];

a[j + 1] = t;

}

}

}

链表完整代码

#include<stdio.h>

#include<malloc.h>

#include<stdlib.h>

typedef struct Node {

int data;//数据域

struct Node* pNext;//指针域  

}NODE, * PNODE;

//NODE是struct Node类型,PNODE是struct Node*类型

/*

  指针域指向了和它整体本身的数据类型一模一样的另一个变量的整体

  指针域存放的是下一个节点的地址,所以应该是【下一个节点的数据类型*】 类型的指针变量

  下一个节点跟这个节点本身的数据类型一样,都是struct Node类型

  所以,指针域的指针变量的类型是struct Node*类型

 */

PNODE createList();//创建

void traverseList(PNODE pHead);//遍历

bool isEmpty(PNODE pHead);//判空

int numNode(PNODE pHead);//求链表有效节点个数

void sortList(PNODE pHead);//排序

bool insertNode(PNODE pHead, int pos, int val);//插入节点

bool deleteNode(PNODE pHead, int pos);//删除节点

int main() {

PNODE pHead = NULL;

//等价于struct Node* PHead = NULL;

pHead = createList();//创建一个非循环单链表,并将链表的头结点的地址赋给pHead

traverseList(pHead);//遍历

if (isEmpty(pHead))

printf("链表为空");

else

printf("链表非空");

//求链表有效节点的个数

printf("链表中有效节点的个数为%d\n", numNode(pHead));

sortList(pHead);

traverseList(pHead);//遍历

insertNode(pHead, 1, 125);

traverseList(pHead);//遍历

deleteNode(pHead, 1);

traverseList(pHead);//遍历

return 0;

}

PNODE createList() {

int len;//用来存放链表有效节点的个数

int val;//用来临时存放用户输入的节点的个数

/*

  pHead是一个头指针,pHead指向了头结点

  这个头结点不存放有效数据*/

PNODE pHead = (PNODE)malloc(sizeof(NODE));

if (pHead == NULL) {

printf("内存分配失败,程序终止\n");

exit(-1);

}

PNODE pTail = pHead;

pTail->pNext = NULL;

printf("请输入需要生成的链表节点的个数:");

scanf("%d", &len);

for (int i = 0; i < len; i++) {

printf("请输入需要生成的链表节点值:");

scanf("%d", &val);

PNODE pNew = (PNODE)malloc(sizeof(NODE));

if (pHead == NULL) {

printf("内存分配失败,程序终止\n");

exit(-1);

}

pNew->data = val;

pTail->pNext = pNew;

pNew->pNext = NULL;

pTail = pNew;

}

/*

  循环了len次,每一次都创建并分配了一个新节点,用pNew(指针变量)表示这个新节点

  创建了新节点后,为新节点数据域赋值

  创建了一个pTail指针变量,链表中没有有效节点之前pTail指向头结点(此时,头指针pHead和pTail都指向头结点)

  创建了一个新节点之后,为新节点赋值数据域,pNew->data = val

  pTail指针变量指向的节点(最开始是头结点,之后是链表中最后一个节点)的指针域存上新节点的地址pTail->pNext = pNew

  此时pTail指针变量指向的是倒数第二个节点

  将新茶入的节点的指针域置空pNew->pNext = NULL

  将pTail指针变量指到最后一个新插入的节点上,确保下一次插入新节点之前pTail总是指到当前链表最后一个节点上

  pTail = pNew*/

return pHead;

}

void traverseList(PNODE pHead) {

PNODE p = pHead->pNext;

while (NULL != p) {

printf("%d ", p->data);

p = p->pNext;

}

printf("\n");

}

bool isEmpty(PNODE pHead) {

if (pHead->pNext == NULL)

return true;

else

return false;

}

int numNode(PNODE pHead) {

PNODE p = pHead->pNext;

int num = 0;

while (p != NULL) {

num++;

p = p->pNext;

}

return num;

}

void sortList(PNODE pHead) {

if (isEmpty(pHead)) {

printf("链表为空,无法排序");

exit(-1);

}

PNODE p, q;

int i, j;

int n = numNode(pHead);//求链表有效节点个数

for (i = 0, p = pHead->pNext; i < n - 1; i++, p = p->pNext) {

for (j = 0, q = pHead->pNext; j < n - 1 - i; j++, q = q->pNext) {

if (q->data > q->pNext->data) {

int t = q->data;

q->data = q->pNext->data;

q->pNext->data = t;

}

}

}

}

bool insertNode(PNODE pHead, int pos, int val) {

PNODE p = pHead;

int i = 0;

while (p && i < pos) {

p = p->pNext;

i++;

}

if (p == NULL || i > pos) {

return false;

}

PNODE pNew = (PNODE)malloc(sizeof(NODE));

if (pNew == NULL) {

printf("动态内存分配失败");

return false;

}

pNew->data = val;

pNew->pNext = p->pNext;

p->pNext = pNew;

return true;

}

bool deleteNode(PNODE pHead, int pos) {

int i = 0;

PNODE p = pHead;

while (p && i < pos) {

p = p->pNext;

i++;

}

if (!p || i > pos)

return false;

PNODE q = (PNODE)malloc(sizeof(NODE));

q = p->pNext;

p->pNext = p->pNext->pNext;

free(q);

return true;

}

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

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

相关文章

1.使用分布式文件系统Minio管理文件

分布式文件系统DFS分类 文件系统 文件系统是操作系统用于组织管理存储设备(磁盘)或分区上文件信息的方法和数据结构,负责对文件存储设备空间进行组织和分配,并对存入文件进行保护和检索 文件系统是负责管理和存储文件的系统软件&#xff0c;操作系统通过文件系统提供的接口去…

Docker五部曲之五:通过Docker和GitHub Action搭建个人CICD项目

文章目录 项目介绍Dockerfile解析compose.yml解析Nginx反向代理到容器以及SSL证书设置MySQL的准备工作Spring和环境变量的交互 GitHub Action解析项目测试结语 项目介绍 该项目是一个入门CICD-Demo&#xff0c;它由以下几部分组成&#xff1a; Dockerfile&#xff1a;用于构建…

「 典型安全漏洞系列 」05.XML外部实体注入XXE详解

1. XXE简介 XXE&#xff08;XML external entity injection&#xff0c;XML外部实体注入&#xff09;是一种web安全漏洞&#xff0c;允许攻击者干扰应用程序对XML数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件&#xff0c;并与应用程序本身可以访问的任何后…

【Unity小技巧】3D人物移动脚步和跳跃下落音效控制

文章目录 单脚步声多脚步声&#xff0c;跳跃落地音效播放不同材质的多脚步声完结 单脚步声 public AudioClip walkingSound; public AudioClip runningSound;//移动音效 public void MoveSound() {// 如果在地面上并且移动长度大于0.9if (isGround && moveDirection.s…

动物免疫(羊驼免疫)-泰克生物

在过去几十年里&#xff0c;抗体研究和应用的领域已经经历了革命性的变化。在这个进程中&#xff0c;一种特殊来源的抗体 —— 来自骆驼科动物&#xff08;包括羊驼&#xff09;的单链抗体&#xff08;也称纳米抗体&#xff09;引起了全球科学家的广泛关注。 羊驼等骆驼科动物…

【Linux】python版本控制和环境管理

文章目录 1.查看目前python的版本2.添加软件源并更新3.选择你想要下载的版本4.警示&#xff1a;没必要设置默认版本误区千万千万不要覆盖python3软链接解决办法 5.pip软件包管理最省心稍微麻烦换源 网上有很多教程都是教导小白去官方下载之后编译安装。但是&#xff0c;小白连c…

4.go 基础类型及类型转换

目录 概述basic types总结例子 Zero values总结例子 类型转换总结例子 结束 概述 go 版本&#xff1a; go1.20.13 basic types 总结 基本类型如下&#xff1a; boolstringint int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptrbyte // alias for uint8…

[pytorch入门] 2. tensorboard

tensorboard简介 TensorBoard 是一组用于数据可视化的工具。它包含在流行的开源机器学习库 Tensorflow 中.但是也可以独立安装&#xff0c;服务Pytorch等其他的框架 可以常常用来观察训练过程中每一阶段如何输出的 安装pip install tensorboard启动tensorboard --logdir<d…

蓝桥杯理历年真题 —— 数学

1. 买不到的数目 这道题目&#xff0c;考得就是一个日常数学的积累&#xff0c;如果你学过这个公式的话&#xff0c;就是一道非常简单的输出问题&#xff1b;可是如果没学过&#xff0c;就非常吃亏&#xff0c;在考场上只能暴力求解&#xff0c;或是寻找规律。这就要求我们什么…

Python图像处理【19】基于霍夫变换的目标检测

基于霍夫变换的目标检测 0. 前言1. 使用圆形霍夫变换统计图像中圆形对象2. 使用渐进概率霍夫变换检测直线2.1 渐进霍夫变换原理2.2 直线检测 3. 使用广义霍夫变换检测任意形状的对象3.1 广义霍夫变换原理3.2 检测自定义形状 小结系列链接 0. 前言 霍夫变换 (Hough Transform,…

H5112C PWM调光 无频闪 高性价比 支持12V 24V 36V 48V 60V 72V 内置MOS

PWM调光芯片是一种常用于LED调光控制的芯片&#xff0c;其工作原理如下&#xff1a; 脉冲宽度调制&#xff08;PWM&#xff09;&#xff1a;PWM是一种调制技术&#xff0c;通过改变信号的脉冲宽度来控制输出信号的平均功率。在PWM调光中&#xff0c;芯片会以一定的频率产生一系…

SpringCloud Alibaba 深入源码 - Nacos 和 Eureka 的区别(健康检测、服务的拉取和订阅)

目录 一、Nacos 和 Eureka 的区别 1.1、以 Nacos 注册流程来解析区别 一、Nacos 和 Eureka 的区别 1.1、以 Nacos 注册流程来解析区别 a&#xff09;首先&#xff0c;我们的服务启动时。都会把自己的信息提交给注册中心&#xff0c;然后注册中心就会把信息保存下来. 注册的…

ELK日志分析

目录 一、ELK概述 &#xff08;一&#xff09;ELK的定义 &#xff08;二&#xff09;ELK工具 1.ElasticSearch 2.Kiabana 3.Logstash &#xff08;1&#xff09;定义 &#xff08;2&#xff09;插件 ① input ② filter ③ output &#xff08;三&#xff09;可以添…

快速排序(三)——hoare法

目录 ​一.前言 二.快速排序 hoare排法​ 三.结语 一.前言 本文给大家带来的是快速排序&#xff0c;快速排序是一种很强大的排序方法&#xff0c;相信大家在学习完后一定会有所收获。 码字不易&#xff0c;希望大家多多支持我呀&#xff01;&#xff08;三连&#xff0b;关…

Spring Boot3整合Druid(监控功能)

目录 1.前置条件 2.导依赖 错误依赖&#xff1a; 正确依赖&#xff1a; 3.配置 1.前置条件 已经初始化好一个spring boot项目且版本为3X&#xff0c;项目可正常启动。 作者版本为3.2.2最新版 2.导依赖 错误依赖&#xff1a; 这个依赖对于spring boot 3的支持不够&#…

H5嵌入小程序适配方案

时间过去了两个多月&#xff0c;2024已经到来&#xff0c;又老了一岁。头发也掉了好多。在这两个月时间里都忙着写页面&#xff0c;感觉时间过去得很快。没有以前那么轻松了。也不是遇到了什么难点技术&#xff0c;而是接手了一个很烂得项目。能有多烂&#xff0c;一个页面发起…

开源无代码应用程序生成器Saltcorn

什么是 Saltcorn &#xff1f; Saltcorn 是一个无需编写任何代码即可构建数据库 Web 应用程序的平台。它配备了一个吸睛的仪表板&#xff0c;丰富的生态系统、视图生成器以及支持主题的界面&#xff0c;使用直观的点击、拖放用户界面来构建整个应用程序。 软件的特点&#xff1…

智慧文旅运营综合平台:重塑文化旅游产业的新引擎

目录 一、建设意义 二、包含内容 三、功能架构 四、典型案例 五、智慧文旅全套解决方案 - 210份下载 在数字化浪潮席卷全球的今天&#xff0c;智慧文旅运营综合平台作为文化旅游产业与信息技术深度融合的产物&#xff0c;正逐渐显现出其强大的生命力和广阔的发展前景。 该…

海外抖音TikTok、正在内测 AI 生成歌曲功能,依靠大语言模型 Bloom 进行文本生成歌曲

近日&#xff0c;据外媒The Verge报道&#xff0c;TikTok正在测试一项新功能&#xff0c;利用大语言模型Bloom的AI能力&#xff0c;允许用户上传歌词文本&#xff0c;并使用AI为其添加声音。这一创新旨在为用户提供更多创作音乐的工具和选项。 Bloom 是由AI初创公司Hugging Fac…

C语言——内存函数介绍和模拟实现(memcpy、memmove、memset、memcmp)

之前我们讲过一些字符串函数&#xff08;http://t.csdnimg.cn/ZcvCo&#xff09;&#xff0c;今天我们来讲一讲几个内存函数&#xff0c;那么可能有人要问了&#xff0c;都有字符串函数了&#xff0c;怎么又来个内存函数&#xff0c;这不是一样的么&#xff1f; 我们要知道之前…