链表|数据结构|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;

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2023年12月青少年机器人技术等级考试(二级)理论综合试卷

2023年12月青少年机器人技术等级考试&#xff08;二级&#xff09;理论综合试卷 选择题 第 1 题 单选题 下图中&#xff0c;能够将圆周运动转化为往复摆动的是&#xff1f;&#xff08; &#xff09; A. B. C. D. 第 2 题 单选题 如图&#xff0c;该机械结构可实现的运动…

idea远程服务调试

1. 配置idea远程服务调试 这里以 idea 新 ui 为例&#xff0c;首先点击上面的 debug 旁边的三个小圆点&#xff0c;然后在弹出的框框中选择 “Edit”&#xff0c;如下图所示。 然后进入到打开的界面后&#xff0c;点击左上角的 “” 进行添加&#xff0c;找到 “Remote JVM De…

HTML 入门手册(二)

目录 10-表单 11-input标签 11.1文本框 (text) 11.2密码框 (password) 11.3单选按钮 (radio) 11.4复选框 (checkbox) 11.5普通按钮 11.6提交按钮 (submit) 11.7重置按钮 (reset) 11.8隐藏域 (hidden) 11.9文件上传 (file) 11.10数字输入 (number) 11.11日期输入 (…

有效网络安全意识的正确策略

员工在保护组织资产方面发挥着重要作用。随着威胁形势的不断变化&#xff0c;网络安全意识培训是创建良好安全文化的重要组成部分。 为什么要进行网络安全意识培训&#xff1f; 2022 年&#xff0c; 81% 的组织遭受恶意软件、网络钓鱼和密码攻击&#xff0c;主要针对用户。 …

SpringBoot 异常报告器解析

介绍 SpringBootExceptionReporter用于捕获和处理启动期间的异常&#xff0c;例如应用程序上下文的初始化失败。我们业务中的异常处理一般使用拦截器进行拦截处理业务异常。 异常报告流程解析 框架内实现 reportException实现 FailureAnalyzer介绍 analyze逻辑 FailureAnalys…

数据结构·顺序表应用

本节应用是要用顺序表实现一个通讯录&#xff0c;收录联系人的姓名、性别、电话号码、住址、年龄 ​​​​​​​ 顺序表的实现在上一节中已经完成了&#xff0c;本节的任务其实就是应用上节写出来的代码的那些接口函数功能&#xff0c;做出来一个好看的&#xff0c;可…

1.电子基础

https://www.falstad.com/circuit/circuitjs.html vcc&#xff1a;正极 三角形&#xff1a;负极 理想电路原件 电压源、电流源 电压源&#xff1a;正负号表示电压方向 电流源&#xff1a;箭头表示电流方向

2024PMP考试新考纲-【过程领域】近期典型真题和很详细解析(9)

华研荟继续为您分享【过程Process领域】的新考纲下的真题&#xff0c;帮助大家体会和理解新考纲下PMP的考试特点和如何应用所学的知识和常识&#xff08;经验&#xff09;来解题&#xff0c;并且举一反三&#xff0c;一次性3A通过2024年PMP考试。 2024年PMP考试新考纲-【过程领…

Drivable 3D Gaussian Avatars 论文笔记

Drivable 3D Gaussian Avatars 论文笔记 主要的算法架构和贡献是什么&#xff1f;如何使用这个deformation 呢&#xff1f; 主要的算法架构和贡献是什么&#xff1f; 这篇文章主要使用了两个当前流行的概念&#xff0c;一是3D高斯溅射&#xff0c;二是cage-based deformation。…

java SSM政府采购管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM政府采购管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代 码和数据库&#xff0c;系统主要采…

DC-7靶机做题记录

靶机下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1w2c_QKd_hOoR2AzNrdZjMg?pwdtdky 提取码&#xff1a;tdky 参考&#xff1a; DC7靶机地址&#xff1a;http://www.five86.com/downloads/DC-7.zipDC7靶场介绍: https://www.vulnhub.com/entry/dc-7,356/…

Matlab/simulink风储调频,多台飞轮储能调频,风电场调频,飞轮储能带有虚拟惯量和下垂控制,三机九节点系统一次调频,离散模型

上述为不同飞轮储能容量配比&#xff0c;风电场容量配比&#xff0c;以及有无附加频率控制的飞轮储能出力分析。 飞轮储能驱动电机为永磁同步机电机PMSG 有无飞轮储能容量较小&#xff0c;所以对频率的改善效果有限&#xff0c;不过可以继续增大容量&#xff0c;从而增大频率的…

数据结构之顺序表的增删查改

别丢了你的勇敢 前言&#xff1a; 自今日起&#xff0c;我们正式越过C语言的大山&#xff0c;走向了数据结构的深山&#xff0c;现如今摆在我们面前的第一个坎就是顺序表&#xff0c;我们需要了解顺序表的定义&#xff0c;并且知道&#xff0c;如何对其进行增删查改&#xff0…

unicloud 云对象 schema

目录 云对象 创建云对象 客户端调用 二、Schema&#xff08;表结构&#xff09; 什么是Schema&#xff1f; 如何编写DB Schema Schema的一级节点 客户端直连数据库 字段属性 字段类型bsonType 默认值defaultValue/forceDefaultValue 云对象 创建云对象 云对象&#…

智能算法 | Matlab实现改进黑猩猩优化算法SLWCHOA与多个基准函数对比与秩和检验

智能算法 | Matlab实现改进黑猩猩优化算法SLWCHOA与多个基准函数对比与秩和检验 目录 智能算法 | Matlab实现改进黑猩猩优化算法SLWCHOA与多个基准函数对比与秩和检验预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现改进黑猩猩优化算法SLWCHOA与多个基准函数…

mqtt连接阿里云

参考文章&#xff1a;https://blog.csdn.net/fang_dz999/article/details/112283742?app_version6.2.5&codeapp_1562916241&csdn_share_tail%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22112283742%22%2C%22source%22%3A%22mantouyouy…

JAVA中TreeSet集合的两种排序方法:自然排序和比较器排序

TreeSet支持2种排序&#xff1a;自然排序、比较器排序。 由于TreeSet对内部元素的排序的方法有2种&#xff1a;自然顺序排序、比较器排序。 所以&#xff0c;如果TreeSet采用自然顺序排序&#xff0c;需要内部的元素&#xff08;即自定义类型&#xff09;实现Comparable接口。…

前后对比效果展示的视频怎么制作?左右对比PR模板 Before and After v.2

10种表现方式&#xff0c;前后对比效果展示视频制作PR模板 Before and After v.2 如果您想比较两个图像或视频&#xff0c;这个Adobe Premiere Pro模板非常适合您。只需将两个文件拖放到媒体中&#xff0c;就可以开始了。 适合PS处理图片后期修图前后对比&#xff0c;AI绘图效果…

企业Oracle1 数据库管理

Oracle的安装 一、基础表的创建 1.1 切换到scott用户 用sys 账户 登录 解锁scott账户 alter user scott account unlock;conn scott/tiger;发现并不存在scott账户&#xff0c;自己创建一个&#xff1f; 查找资料后发现&#xff0c;scott用户的脚本需要自己执行一下 C:\ap…

FDM3D打印系列——宝可梦妙蛙种子

fdm打印妙蛙种子 大家好&#xff0c;我是阿赵。   每次打印3D模型&#xff0c;都有新的感觉&#xff0c;这次打印了个宝可梦里面的妙蛙种子&#xff0c;也就是俗称的蒜头王八。   先来看看成果&#xff0c;然后在后面再聊一下关于3D打印的一些体会。使用创想三维的Sermoon …