C语言高级-链表、状态机、多线程

第一点

链表

为什么需要链表

为了解决数组的第二个缺陷:就是可以随时改变数组的大小的一种数据结构!

什么是链表

顾名思义,链表就是用锁链链接起来的表。这里的表指的是一个一个的节点(一个节点就是一个校区),节点中有一些内存可以用来存储数据(所以叫表,表就是数据表);这里的锁链指的是链接各个表的方法,C语言中用来链接两个表(其实就是两块内存)的方法就是指针。

简单的来说,链表就像是大学的新校区,主要是为了缓解本部学生拥挤的状态,然后在异地建设新校区,然后本部与新校区之间就通过班车进行沟通链接,本质目的就是为了扩大学校范围(内存)

链表是由若干个节点构成的(链表的各个节点的结构是完全类似的),节点是由有效数据和指针组成的。有效数据区域是用来存储信息完成任务的,指针区域用来指向链表的下一个节点从而形成链表。

第二点

单链表的实现

单链表的实现

node只是一个结构体,本身并没有变量生成,也不占用内存。结构体定义相当于为链表节点定义了一个模板,但是还没有一个节点,将来在实际创建链表时需要一个节点是用这个模板来赋值一个即可。

堆内存的申请和使用

链表的内存要求比较灵活,不能用栈,也不能使用data数据段,只能用堆内存。

使用堆内存来创建一个链表节点的步骤:

1.申请堆内存,大小为一个节点的大小(检查申请结果是否正确)

2.清理申请到的堆内存

3.把申请到的堆内存当做一个新节点

4.填充每个新节点的有效数据和指针区域

上面的程序只实现了头指针到节点一的链接!!!

单链表的算法

单链表算法-插入节点

如何读取链表中的值?

以上链表中数据的读取,一定要用头指针的方式读,不能直接用节点处指针的方式读!!!因为在实际当中我们保存链表的时候是不会保存各个节点的指针的,只能通过头指针来访问链表节点。

封装成函数

通过上面的图一所示的代码,将创建一个链表节点封装成一个函数 create_node来直接调用函数创建链表节点!在这个函数中输入的参数data为节点中所存的值,返回参数为指针p;

图二中是通过调用所创建的函数构成链表的步骤;(指针指向和函数赋值的作用)

尾部插入新节点

前面的不用动,在后面直接插入就可以了!

图一中,定义一个尾部插入的函数,两个形式参数,一个为头指针,一个为新的节点的头指针!

图二中,是在主函数中调用图一定义的尾部插入函数,头指针为pHeader、新节点用create_node的返回值代替;

头部插入新节点

单链表算法-遍历

单链表算法-删除

为什么要删除节点
(1)一直在强调,链表到底用来干嘛的?
(2)有时候链表节点中的数据不想要了,因此要删掉这个节点。
删除节点的2个步骤
(1)第一步:找到要删除的节点;第二步:删除这个节点。
如何找到待删除的节点
(1)通过遍历来查找节点。从头指针+头节点开始,顺着链表依次将各个节点拿出来,按照一定的方法比对,找到我们要删除的那个节点。
(1)待删除的节点不是尾节点的情况:首先把待删除的节点的前一个节点的pNext指针指向待删除的节点的后一个节点的首地址(这样就把这个节点从链表中摘出来了),然后再将这个摘出来的节点free掉接口。
(2)待删除的节点是尾节点的情况:首先把待删除的尾节点的前一个节点的pNext指针指向null(这时候就相当于原来尾节点前面的一个节点变成了新的尾节点),然后将摘出来的节点free掉。

单链表算法-逆序

 从逻辑上来讲,链表的逆序有很多种方法。这些方法都能实现最终的需要,但是效率是不一样的。彼此的可扩展性、容错性等不同。

思路:首先遍历原链表,然后将原链表中的头指针和头节点作为新链表的头指针和头节点,原链表中的有效节点挨个依次取出来,采用头插入的方法插入新链表中即可。

【链表逆序 = 遍历 + 头插入】

  

第三点

双链表

单链表的单向移动性导致我们在操作单链表时,当前节点只能向后移动不能向前移动,因此不自由,不利于解决更复杂的算法。

因此就有了双链表的出现!!
解决思路:有效数据+2个指针的节点(双链表)

双向链表的节点 = 有效数据 + 2个指针(一个指向后一个节点,另一个指向前一个节点)

第四点

状态机

有限状态机


(1)常说的状态机是有限状态机FSM。FSM指的是有有限个状态(一般是一个状态变量的值),这个机器同时能够从外部接收信号和信息输入,机器在接收到外部输入的信号后会综合考虑当前自己的状态和用户输入的信息,然后机器做出动作:跳转到另一个状态。
(2)考虑状态机的关键点:当前状态、外部输入、下一个状态


两种状态机:Moore型和Mealy型


(1)Moore型状态机特点是:输出只与当前状态有关(与输入信号无关)。相对简单,考虑状态机的下一个状态时只需要考虑它的当前状态就行了。
(2)Mealy型状态机的特点是:输出不只和当前状态有关,还与输入信号有关。状态机接收到一个输入信号需要跳转到下一个状态时,状态机综合考虑2个条件(当前状态、输入值)后才决定跳转到哪个状态。
状态机的主要用途:电路设计、FPGA程序设计、软件设计
(1)电路设计中广泛使用了状态机思想
(2)FPGA程序设计
(3)软件设计(框架类型的设计,譬如操作系统的GUI系统、消息机制)

状态机解决了什么问题


(1)我们平时写程序都是顺序执行的,这种程序有个特点:程序的大体执行流程是既定的,程序的执行是遵照一定的大的方向有迹可寻的。
(2)但是偶尔会碰到这样的程序:外部不一定会按照既定流程来给程序输入信息,而程序还需要完全能够接收并响应外部的这些输入信号,还要能做出符合逻辑的输出。


C语言实现简单的状态机
题目:开锁状态机。功能描述:用户连续输入正确的密码则会开锁,如果密码输入过程错误则锁会退回到初始状态重新计入密码,即:用户只需要连续输入出正确的密码即可开锁(输入错误不用撤销、也不用删除)
 

第五点

多线程简介


操作系统下的并行执行机制


(1)并行就是说多个任务同时被执行。并行分微观上的并行和宏观上的并行。
(2)宏观上的并行就是从长时间段(相对于人来说)来看,多个任务是同时进行的;微观上的并行就是真的在并行执行。
(3)操作系统要求实现宏观上的并行。宏观上的并行有2种情况:第一种是微观上的串行,第二种是微观上的并行。
(4)理论来说,单核CPU本身只有一个核心,同时只能执行一条指令,这种CPU只能实现宏观上的并行,微观上一定是串行的。微观上的并行要求多核心CPU。多核CPU中的多个核心可以同时微观上执行多个指令,因此可以达到微观上的并行,从而提升宏观上的并行度。

进程和线程的区别和联系


(1)进程和线程是操作系统的两种不同软件技术,目的是实现宏观上的并行(通俗一点就是让多个程序同时在一个机器上运行,达到宏观上看起来并行执行的效果)。
(2)进程和线程在实现并行效果的原理上不同。而且这个差异和操作系统有关。譬如windows中进程和线程差异比较大,在linux中进程和线程差异不大(linux中线程就是轻量级的进程)。
(3)不管是多进程还是多线程,最终目标都是实现并行执行。

多线程的优势


(1)前些年多进程多一些,近些年多线程开始用得多。
(2)现代操作系统设计时考虑到了多核心CPU的优化问题,保证了:多线程程序在运行的时候,操作系统会优先将多个线程放在多个核心中分别单独运行。所以说多核心CPU给多线程程序提供了完美的运行环境。所以在多核心CPU上使用多线程程序有极大的好处。

线程同步和锁


(1)多线程程序运行时要注意线程之间的同步

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值