当前位置: 首页 > news >正文

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

}

相关文章:

  • c++设计模式之单例模式
  • 力扣(leetcode)第35题搜索插入位置(Python)
  • Git 操作
  • 启动低轨道卫星LEO通讯产业与6G 3GPP NTN标准
  • 纯前端网页编辑Office文档安全预览之打开Word文档后禁止另存为....
  • P1068 [NOIP2009 普及组] 分数线划定————C++、Python
  • HTML+CSS:飞翔按钮
  • 04 单链表
  • Go 爬虫之 colly 从入门到不放弃指南
  • HTTP 第二章 发展历史
  • 电工技术实验指导书-万用表的使用
  • Django随笔
  • linux 抓包
  • 【Docker】未来已来 | Docker技术在云计算、边缘计算领域的应用前景
  • Java面试汇总——jvm篇
  • [分享]iOS开发-关于在xcode中引用文件夹右边出现问号的解决办法
  • “大数据应用场景”之隔壁老王(连载四)
  • 《用数据讲故事》作者Cole N. Knaflic:消除一切无效的图表
  • C# 免费离线人脸识别 2.0 Demo
  • centos安装java运行环境jdk+tomcat
  • CODING 缺陷管理功能正式开始公测
  • CSS3 聊天气泡框以及 inherit、currentColor 关键字
  • HashMap ConcurrentHashMap
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • MQ框架的比较
  • node学习系列之简单文件上传
  • SOFAMosn配置模型
  • Spring Boot快速入门(一):Hello Spring Boot
  • spring-boot List转Page
  • 机器学习中为什么要做归一化normalization
  • 聊聊redis的数据结构的应用
  • 让你的分享飞起来——极光推出社会化分享组件
  • 使用common-codec进行md5加密
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 再谈express与koa的对比
  • 责任链模式的两种实现
  • 7行Python代码的人脸识别
  • linux 淘宝开源监控工具tsar
  • 进程与线程(三)——进程/线程间通信
  • ###C语言程序设计-----C语言学习(3)#
  • #mysql 8.0 踩坑日记
  • $.type 怎么精确判断对象类型的 --(源码学习2)
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (二)换源+apt-get基础配置+搜狗拼音
  • (分布式缓存)Redis哨兵
  • (附源码)ssm本科教学合格评估管理系统 毕业设计 180916
  • (附源码)ssm学生管理系统 毕业设计 141543
  • (九)c52学习之旅-定时器
  • (免费领源码)Java#ssm#MySQL 创意商城03663-计算机毕业设计项目选题推荐
  • (免费领源码)python+django+mysql线上兼职平台系统83320-计算机毕业设计项目选题推荐
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失