【数据结构与算法】—— * 链表 入门(一)*

简介: 【数据结构与算法】—— * 链表 入门(一)*

引言

在存储一大波数的时候,我们通常使用的是数组,但是数组有时候又会显得不够灵活,比如下面这个例子:

有一串已经排序好的数 2,3,5,8,9 ,10

如果我们想要往数组中插入6 这个元素,需要把 8 以后的元素全部往后挪一位

1.png2.png

这样操作显然很耗费时间,如果使用链表的话则会快很多。那么什么是链表呢?请看下图:

3.png

此时如果需要在8前面加入一个6,那么只需要向下图一样更改一下就可以了,而不用向像最开始那样把每个数向后挪。4.png

链表的相关思考

为了实现链表这样的数据结构,我们需要使用指针malloc这样的函数。

注意 : malloc 函数的返回值是 void * 类型,我们需要对其进行强制类型转换

使用malloc时需要调用头文件 <stdlib.h>

为什么我们要用这么复杂的办法来储存类型呢 ?

因为按照之前的方法,我们必须预先准确地知道所需变量的个数,也就是说我们必须我们必须定义出所有的变量。假如说你现在定义了100个变量,而实际上则需要101个变量,那么就不得不对这个程序进行修改。

而有了malloc函数,我们可以在程序运行的过程中根据实际情况来申请空间。


链表结点结构

5.png

每一个结点都由两个部分组成。左边的部分用来存放具体的值,那么用一个整型变量就可以;右边的部分则需要储存下一个点的地址,则可以用指针来实现(也称为后继指针)

这里我们定义一个结构体类型来存储这个结点:

structnode{
intdate;
structnode* next;
};

6.png

因为下一个结点的类型也是 struct node ,所以我们指针的类型也必须是 struct node * 类型。


建立链表

1

首先,我们需要一个头指针 head 指向链表的最开始。当链表还没有建立的时候头指针head为空(也可以理解指向空结点)。

structnode* head;
head = NULL;  //头指针初始为空

2

现在,我们来创立第一个结点,并用临时指针p指向这个结点

structnode* p;
//动态申请一块空间,用来存放一个结点,并用临时指针p指向这个结点
p = (structnode*)malloc(sizeof(structnode));


接下来分别设置新建的结点的左半部分和右半部分

scanf("%d", &a);
p->date = a;   //将数据存储到当前结点的date域中
p->next = NULL;  //设置当前结点的后继指针为空,也就是当前结点的下一个结点为空

下面来设置头指针并设置新创结点的 *next 指向空 。头指针的作用是方便以后从头遍历整个链表

if (head == NULL)
head = p;  //如果这是第一个创建的结点,则将头指针指向这个结点
elseq->next = p;  //如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点

如果是第一个创立的结点,则将头指针指向这个结点 7.png

如果不是第一个创建的结点,则将上一个结点的后继节点指向当前结点。8.png

最后要将指针q也指向当前结点,因为待会临时指针p将会指向新创建的结点。

q = p;  //指针q也要指向当前结点
#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
structnode{
intdate;
structnode* next;
};
intmain()
{
structnode* head, * p, * q = NULL, * t;
inti, n, a;
scanf("%d", &n);
head = NULL;  //头指针初始化为空
for (i = 1; i <= n; i++)
  {
scanf("%d", &a);
    //动态申请一块空间,用来存放一个结点,并用临时指针p指向这个结点
p = (structnode*)malloc(sizeof(structnode));
p->date = a;
p->next = NULL; //设置当前结点的后继指针为空,也就是下一个结点为空
if (head == NULL)
head = p; //如果这是第一个创建的结点,则将头指针指向这个点
elseq->next = p;//如果不是第一个创建的结点,则将上一个结点的后继节点指向当前结点
q = p;  //指针q也指向当前结点
  }
  //输出链表中的所有数
t = head;
while (t!= NULL)
  {
printf("%d  ", t->date);
t = t->next;  //继续下一个结点
  }
}

效果图

image.png


实现插入操作 10.png

首先用一个临时指针t从链表的头部开始遍历

t = head; //从链表的头部开始遍历

等到指针t的下一个结点的值比6大的时候,将6插到中间。

即 t -> next -> date 大于 6 的时候进行插入

代码实现

scanf("%d", &a);  //读入待插入的数
t = head;     //从链表的头部开始遍历
while (t!= NULL)
  {
if (t->next->date > a || t->next->next == NULL)
    {
      //如果当前结点是最后一个结点或者下一个结点的值大于待插入的值的时候插入
p = (structnode*)malloc(sizeof(structnode)); //申请一块空间,来存放新增结点
p->date = a;
p->next = t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
t->next = p;    //当前结点的后继指针指向新增结点
break;        //插入完毕退出循环
    }
t = t->next;   //继续下一个结点
  }

完整代码

效果图:

11.png

#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
structnode{
intdate;
structnode* next;
};
intmain()
{
structnode* head, * p, * q = NULL, * t;
inti, n, a;
scanf("%d", &n);
head = NULL;  //头指针初始化为空
for (i = 1; i <= n; i++)
  {
scanf("%d", &a);
    //动态申请一块空间,用来存放一个结点,并用临时指针p指向这个结点
p = (structnode*)malloc(sizeof(structnode));
p->date = a;
p->next = NULL; //设置当前结点的后继指针为空,也就是下一个结点为空
if (head == NULL)
head = p; //如果这是第一个创建的结点,则将头指针指向这个点
elseq->next = p;//如果不是第一个创建的结点,则将上一个结点的后继节点指向当前结点
q = p;  //指针q也指向当前结点
  }
scanf("%d", &a);  //读入待插入的数
t = head;     //从链表的头部开始遍历
while (t!= NULL)
  {
if (t->next->date > a || t->next->next == NULL)
    {
      //如果当前结点是最后一个结点或者下一个结点的值大于待插入的值的时候插入
p = (structnode*)malloc(sizeof(structnode)); //申请一块空间,来存放新增结点
p->date = a;
p->next = t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
t->next = p;    //当前结点的后继指针指向新增结点
break;        //插入完毕退出循环
    }
t = t->next;   //继续下一个结点
  }
  //输出链表中的所有数
t = head;
while (t!= NULL)
  {
printf("%d  ", t->date);
t = t->next;  //继续下一个结点
  }
}


如果觉得有什么意见或者是需要的话,欢迎在评论区向小玄提出哦!

冲冲冲!!

目录
相关文章
|
1月前
|
存储 算法
算法入门:专题二---滑动窗口(长度最小的子数组)类型题目攻克!
给定一个正整数数组和目标值target,找出总和大于等于target的最短连续子数组长度。利用滑动窗口(双指针)优化,维护窗口内元素和,通过单调性避免重复枚举,时间复杂度O(n)。当窗口和满足条件时收缩左边界,更新最小长度,最终返回结果。
|
1月前
|
存储 算法
算法入门:专题一:双指针(有效三角形的个数)
给定一个数组,找出能组成三角形的三元组个数。利用“两边之和大于第三边”的性质,先排序,再用双指针优化。固定最大边,左右指针从区间两端向内移动,若两短边之和大于最长边,则中间所有组合均有效,时间复杂度由暴力的O(n³)降至O(n²)。
|
1月前
|
存储 算法 编译器
算法入门:剑指offer改编题目:查找总价格为目标值的两个商品
给定递增数组和目标值target,找出两数之和等于target的两个数字。利用双指针法,left从头、right从尾向中间逼近,根据和与target的大小关系调整指针,时间复杂度O(n),空间复杂度O(1)。找不到时返回{-1,-1}。
|
4月前
|
机器学习/深度学习 数据采集 算法
你天天听“数据挖掘”,可它到底在“挖”啥?——数据挖掘算法入门扫盲篇
你天天听“数据挖掘”,可它到底在“挖”啥?——数据挖掘算法入门扫盲篇
101 0
|
存储 算法 Perl
数据结构实验之链表
本实验旨在掌握线性表中元素的前驱、后续概念及链表的建立、插入、删除等算法,并分析时间复杂度,理解链表特点。实验内容包括循环链表应用(约瑟夫回环问题)、删除单链表中重复节点及双向循环链表的设计与实现。通过编程实践,加深对链表数据结构的理解和应用能力。
216 4
|
8月前
|
机器学习/深度学习 算法 机器人
强化学习:时间差分(TD)(SARSA算法和Q-Learning算法)(看不懂算我输专栏)——手把手教你入门强化学习(六)
本文介绍了时间差分法(TD)中的两种经典算法:SARSA和Q-Learning。二者均为无模型强化学习方法,通过与环境交互估算动作价值函数。SARSA是On-Policy算法,采用ε-greedy策略进行动作选择和评估;而Q-Learning为Off-Policy算法,评估时选取下一状态中估值最大的动作。相比动态规划和蒙特卡洛方法,TD算法结合了自举更新与样本更新的优势,实现边行动边学习。文章通过生动的例子解释了两者的差异,并提供了伪代码帮助理解。
614 2
|
7月前
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
138 0
|
9月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
338 30
|
9月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
440 25
|
10月前
|
机器学习/深度学习 存储 C++
【C++数据结构——线性表】单链表的基本运算(头歌实践教学平台习题)【合集】
本内容介绍了单链表的基本运算任务,涵盖线性表的基本概念、初始化、销毁、判定是否为空表、求长度、输出、求元素值、按元素值查找、插入和删除数据元素等操作。通过C++代码示例详细解释了顺序表和链表的实现方法,并提供了测试说明、通 - **任务描述**:实现单链表的基本运算。 - **相关知识**:包括线性表的概念、初始化、销毁、判断空表、求长度、输出、求元素值、查找、插入和删除等操作。 - **测试说明**:平台会对你编写的代码进行测试,提供测试输入和预期输出。 - **通关代码**:给出了完整的C++代码实现。 - **测试结果**:展示了测试通过后的预期输出结果。 开始你的任务吧,祝你成功!
487 5

热门文章

最新文章