前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【RTOS训练营】课程学习方法和结构体知识复习 + 链表知识

【RTOS训练营】课程学习方法和结构体知识复习 + 链表知识

作者头像
韦东山
发布2022-09-16 09:36:18
1960
发布2022-09-16 09:36:18
举报
文章被收录于专栏:韦东山嵌入式韦东山嵌入式

一、学习方法

因为有些学员是刚进群,所以这里再把学习方法讲一下。

1. 预习

我们会在每一节晚课之后会通知要预习的章节,学员需要按如下操作观看相关视频。

​ 1.1 打开官网:百问网官网

​ 1.2 点击首页的"深入学习单片机双架构双系统项目实战线上班"

​ 1.3 再点击"单片机双架构双系统项目实战",观看视频

请添加图片描述
请添加图片描述

在电脑上、在手机浏览器里、微信或QQ里,都可以打开我们的官网,然后使用超清观看(目前微信小程序还不支持超清观看)。

2. 晚课

预习之后就是晚上上课,晚课注意事项如下:

请添加图片描述
请添加图片描述

我们大部分学员都是在上班,有可能没办法参加晚上的课程,因此我们第2天会在官网整理出晚课的图文笔记,在如下类似的位置:

请添加图片描述
请添加图片描述

这个图片上4-7、4-8是根据前次晚课录制的补充扩展内容。

并不是每次晚课的第2天都会录制视频,但是图文是肯定会有的。

图里面红框里最后一个文件是我们的一个AI课程、AI回放,基本上就是QQ聊天内容的复现。

3. 遇到问题

如果您在学习中遇到问题可以在我们论坛内对应版本进行提问,论坛使用方法:

​ 3.1 浏览器打开:百问网官网点击答疑论坛 ​ 3.2 登陆用户名:购买课程时的手机号 ​ 初始密码: 100ask (建议修改自己密码)

​ (如果是最近报班的学员,系统可能没有录入账号,请使用报名登记的手机号注册,再联系班主任开通发帖权限)

​ 3.3 账号有问题的话,联系班主任。

这个课程学习方法,是最后一次重复,下一节课就不会再重复了。

二、复习回顾

在前面的课程里,我们花了很多时间来讲变量和地址、指针。

有一个口诀的要记住:

变量、变量,就是可以变化。 可以变化,就表示可读可写。 可以写的话,肯定在内存里面。

先看看这个图:

请添加图片描述
请添加图片描述

定义了4个变量,既然是变量,肯定在内存里。

大家注意,对于指针,在32位的处理器里面,地址必定是32位的,也就是4个字节。 指针是用来保存地址的,所以说指针变量,它的大小也是32位的,也是四字节。

在图里面我们定了:一个结构体person的指针, 尽管这个person结构体非常大,但是它的指针仍然是4字节。

三、链表

3.1 链表基础知识

好了,变量和地址、指针回顾完毕,下面我们开始回顾链表。

我们假设有三个特务,ABC。

A的下线是B,B的下线是C。

换句话说,就是A有B的地址,B有C的地址。

写成代码就是这样:

请添加图片描述
请添加图片描述

给大家画一个图,这个图在上一次课已经给大家画过了。

请添加图片描述
请添加图片描述

首先我们定义了三个结构体,ABC。

在内存里面就必定有这三个结构体。

再看看下面这句话,他会导致什么结果: A.next_addr = &B;

请添加图片描述
请添加图片描述

记住上面这个图,结构体A里面的next_address, 等于B的地址。

那蓝色箭头是我画出来的,只是给我们形象的认识而已,结构体A里面保存有B的地址。

链表的核心就是:

这个链表结构体里面有一个指针,这个指针, 等于其他结构体的地址。

用人类形象化的话来说,就是结构体A里面的某一个指针,指向结构体B。

好了,现在仍然是回顾了前面晚课的知识,下面开始讲新的知识。

首先作为一个链表,肯定有头部呀,我们怎么来确定这个链表的头部?

实际上我们用一个指针来表示链表头,代码如下:

请添加图片描述
请添加图片描述

看一下这段代码,我们定义了三个结构体,还有一个结构体指针。

他们都是变量,在内存里面都有对应的空间。

请添加图片描述
请添加图片描述

在上面的图里面,在红色方框里,我们用那个指针来表示链表头。

现在这个链表头,它的值它是空的,也就是说它里面保存的地址是空的:这是一个空链表。

我们怎么判断一个链表是空的呢?

代码语言:javascript
复制
if (pHead == NULL)
   printf("It is empty list");

那么我们怎么往这个链表里面添加一个元素呢?

我们先用一个图来表示, 假设把结构体A放到列表里面去:

请添加图片描述
请添加图片描述

再看一下插入第一项非常简单,我让这个链表头直接等于结构体A的地址就可以了。

我们用箭头来表示,让我们更加形象的去了解这个链表:

请添加图片描述
请添加图片描述

在这个图里面我加了这个箭头,在代码里面可没有什么箭头, 它只是pHead这个变量,它的值等于结构体A的地址。

3.2 链表的插入

现在再把一个结构体B放入链表。有两种方法,你是放在链表头部?还是放在链表尾部?

我们画出一个图:

请添加图片描述
请添加图片描述

在左边,是这个链表里面只有元素A。

我们可以在A的左边插入这个新的元素B,也可以在A的右边插入这个新的元素B。

也就是说,我们可以在链表的头部插入新的节点,也可以在列表的尾部插入新的节点

在右边的图里面,上面这个就是把B插在链表的尾部,下面这个就是把B插在链表的头部。

怎么写代码呢?

我们先来看看,把B插在链表的头部:

代码语言:javascript
复制
void InsertNodeToHead(struct spy *newNode)
{
	/* 插到链表最前面 */
	newNode->next_addr = pHead;
	pHead = newNode;
}

我们来画个图演示一下:

请添加图片描述
请添加图片描述

在这个图里面,左边是代码,右边是结果。

假设一开始的时候先插入结构体A,

执行图中标号为2的代码的时候, 就是:A.next_addr = pHead 等于初始值 NULL。

执行上图中标号为3的代码的时候,就是:pHead = A的地址。

结果在上图里面右边地方, 在图里面我也写出了标号2、标号3。 标号2那里A的next_address等于NULL, 标号3那里pHead等于结构体A的地址。

下面我们再来增加第2个元素B,我们在链表的头部插入元素B。

请添加图片描述
请添加图片描述

在这个图里面用蓝色的标号,把调用过程给标了出来。

在左边是代码,看标号为4的代码,要用这个函数把元素B插入链表。怎么做呢?也分为两步:

  • 第1步: 不是插到头部去吗?那我就让B指向头部。
请添加图片描述
请添加图片描述

但头部等于A,也实际上就是B指向了A。

请添加图片描述
请添加图片描述

也就说现在B指向了A, 头部也指向了A。

  • 第二步:

让头部要指向B:

请添加图片描述
请添加图片描述

这就是一个完整的插入过程。

这个图还要补充一下,让结尾指向NULL。

请添加图片描述
请添加图片描述

把链表,想成一个手牵着手的队伍,就容易理解了。

刚才我们讲的是在链表的头部插入一个元素,那怎么在一个链表的尾部插入一个元素呢?

我们假设这个图里面它有好几个元素,我们在最后一个元素的右边,再插入新元素。

请添加图片描述
请添加图片描述

得到的结果如下图:

请添加图片描述
请添加图片描述

用代码来写的话也比较简单:

tmp假设是最后一个元素,B是新元素。

代码语言:javascript
复制
tmp->next_addr = &B;
B.next_addr = NULL;

问题的关键在于,我怎么在原来的列表里面找出最后一个元素。

来看看这段代码,使用一个while循环:

请添加图片描述
请添加图片描述

图中红圈处,它的特征是什么: 它的next_addr等于NULL。

如果不是最后一项的话,我们就取出他右边的那一项: tmp = tmp->next_addr

这句话可能有些同学理解起来困难,这里画个图解释一下:

请添加图片描述
请添加图片描述

看圆框里面的代码,右边是不是temp->next_addr ?

然后我让这个tmp指针,指向右边这结构体:tmp = 右边。

这两句代码连起来写就是这样的: tmp = tmp->next_addr;

插入尾部的代码:

代码语言:javascript
复制
void InsertNodeToTail(struct spy *newNode)
{
	struct spy *tmp;
	
	/* 找到最后一项 */
	tmp = pHead;
	while (tmp)
	{
		if (tmp->next_addr == NULL) /* tmp就是最后一项 */
			break;
		else
			tmp = tmp->next_addr;
	}
	
	/* 最后一项指向新节点  */
	if (!tmp)  /* 空队列 */
	{
		pHead = newNode;
	}
	else
	{
		tmp->next_addr = newNode;
	}
	
	/* 新节点指向NULL */
	newNode->next_addr = NULL;
}

3.3 链表的删除

下面我们讲讲:在链表中,怎么删除一个元素。

请添加图片描述
请添加图片描述

再看这个图,在链表中我们要删除红色方框的这个节点

请添加图片描述
请添加图片描述

再想象一下,在一个手牵着手的队伍里面,有一个人要走了,是不是他前面那个人要跟后面那个人牵手?

所以我们要找出前面那个人和后面那个人。

假设tmp是前面那个人,后面那个人是谁?oldNode->next_addroldNode表示要删除的节点。

代码怎么写呢:tmp->next_addr = 后面的人 = oldNode->next_addr

所以关键在于我们怎么找到前面的人: tmp

这也比较简单,遍历链表:

请添加图片描述
请添加图片描述

也是一个循环,如果我的下一项就等于你的话,我就是你的前一个。

找到之后,就执行这条指令: tmp->next_addr = 后面的人 = oldNode->next_addr

3.4 链表的使用

现在明白链表的插入删除,那么我们怎么使用链表呢?

就比如说在上一节课我们说过,班主任需要把每个学员的信息都给统计起来,用链表如何操作?

怎么去把这些信息全都打印出来,从链表头去遍历链表即可:

请添加图片描述
请添加图片描述

现在回到我们的视频,我们的视频里面也讲了链表的操作。

我给大家画这个图:

请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述

首先我们定了一个结构体:List list

它是一个变量,在内存里面必定有对应的空间。

初始化完这个链表之后,它的结果就像上面的图表示的那样。

因为这个链表内部它有一个根节点, 所以把它的节点个数设置为1。

这个链表一开始的时候只有一个元素, 它的下一个元素是它自己,它的上一个元素也是它自己。

这是一个双向的循环链表,双向循环链表稍微复杂一点,

但是再怎么复杂,它也就是使用两个单向链表组成的,这里我们就不展开说了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-07-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、学习方法
    • 1. 预习
      • 2. 晚课
        • 3. 遇到问题
        • 二、复习回顾
        • 三、链表
          • 3.1 链表基础知识
            • 3.2 链表的插入
              • 3.3 链表的删除
                • 3.4 链表的使用
                相关产品与服务
                云开发 CloudBase
                云开发(Tencent CloudBase,TCB)是腾讯云提供的云原生一体化开发环境和工具平台,为200万+企业和开发者提供高可用、自动弹性扩缩的后端云服务,可用于云端一体化开发多种端应用(小程序、公众号、Web 应用等),避免了应用开发过程中繁琐的服务器搭建及运维,开发者可以专注于业务逻辑的实现,开发门槛更低,效率更高。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档