2020—2021—1学期20202405《网络空间安全导论》第三周学习总结
学习内容:《计算机科学概论》第6、7章
这两天自学了《计算机科学概论》第六七章,下面进行一个简单的学习总结。
第六、七章是《计算机科学概论》的第四部分——程序设计层的一个小部分。第一章《全景图》中提到过,程序设计层负责处理软件、用于实现计算的指令以及管理数据。程序有多种形式,可以在许多层面上执行,由各种语言实现。尽管程序设计问题多种多样,但是他们的目的是相同的,即解决问题。下面我系统的梳理一下我所学的知识。
第6章: 低级程序设计语言与伪代码
进入第6章,我们的重点终于从“什么是计算机系统”变成了“如何使用计算机系统”。
6.1计算机操作
首先我们重温一下计算机的定义:
计算机是能够存储、检索和处理数据的可编程电子设备。
那么因为数据和操作数据在指令逻辑上是相同的,它们存储在相同的地方。要改变计算机对数据的处理,只需要改变指令即可。控制单元执行的指令能够把数据存储到机器的内存当中,在机器内存中检索数据,在算术/逻辑单元中以某种方式处理数据。在机器层,处理涉及在数据值上执行算术和逻辑操作。
有一些指令可以用来规定输入设备与CPU之间以及CPU与输出设备之间的交互。
6.2机器语言
机器语言:由计算机直接使用的二进制编码指令构成的语言。
每种处理器都有自己专用的机器指令集合,这些指令是处理器真正能够执行的指令。
但是事实上目前几乎没有程序是用机器语言编写的,大多数程序是用高级语言编写的,然后再翻译成机器语言。
6.2.1Pep/9:一台虚拟机
因为机器代码因机器的不同而不同,那么如果使用不同类型的机器怎么展示使用机器语言的经验?
对此,我们引入虚拟机:
虚拟机:为了模拟真实机器的重要特征而设计的假想机器。
书上使用的是Pep/9。
6.2.1.1Pep/9的基本特性
Pep/9有7个寄存器,在这里重点研究三个。
①程序计数器 ,其中包含下一条即将被执行的指令的地址。
②指令寄存器,其中包含正在被执行的指令的一个副本。
③累加器,用来存储数据和运算的结果。
存储器的地址本身并不存储在存储器中,它们只是其中独立字节的名字。当涉及内存中某一个特定的字节时,实际使用它的地址替代的。
可用的位数决定了我们可以使用的内存大小。
6.2.1.2指令格式
一条指令由两部分组成,即八位的指令说明符和十六位的操作数说明符。因此Pep/9的指令在长度上是1字节或3字节,取决于是否需要用操作数说明符。
指令说明符说明了要执行什么操作和如何解释操作数的位置。操作数说明符存放的是操作数本身或者操作数的地址。有些指令没有操作数说明符。
操作代码长度从4位到8位不等,3位的寻址模式说明符表示了怎样解析指令中的操作数部分。
如果寻址模式是000,那么指令的操作数说明符中存储的就是操作数。这种寻址模式叫立即寻址
如果寻址模式是001,那么操作数说明符中存储的事操作数所在的内存地址名称。这种寻址模式叫直接寻址
没有操作数的指令称为一元指令,没有操作数说明符,也就是说它的长度是1字节。
6.2.1.3一些示例指令
0000停止执行:一元指令,没有操作数说明符。
1100将字载入寄存器A中:寻址模式决定了该字要载入的位置。也就是说要载入的值要么是操作数说明符中的实际值,要么是在操作数说明符中找到的地址的内存位置。
1101将字节载入寄存器A中:这条指令只载入1字节,如果寻址模式是立即寻址,那么操作数说明符中的第一个字节会被忽略,只有第二个字节会被载入A中;如果是直接寻址,那么只会载入内存位置的1字节。
1110存储寄存器A中的字:在存储操作码使用立即寻址模式是非法的,因为我们不能将寄存器的内容存储到操作数说明符中。
1111存储寄存器A的字节:只存储1字节,而且不支持立即寻址模式。只有寄存器A的第二个字节会存储在操作数说明符给出的地址中,累加器的前8位会被忽略。
0110将操作数加到寄存器A中:操作数说明符的内容被视为地址,执行指令时,该位置的任何值都被加到寄存器A中。
1000从寄存器A减操作数:支持立即寻址和直接寻址模式。
6.3一个程序实例
书上用两个实例加深了对上述知识的印象。
6.4汇编语言
汇编语言给每条机器语言指令分配了一个助记指令码,可以提高效率,也可以减少错误。一个名为汇编器的程序将读取每条指令的助记码,然后翻译成为等价的机器语言。所以有多少种机器,就有多少种汇编语言和翻译程序。
6.4.1Pep/9汇编语言
汇编器指令:翻译程序使用的指令。
Pep/9的汇编器指令(伪操作):
伪操作 | 操作数 | 含义 |
---|---|---|
.END | 表示汇编语言程序的终点 | |
.ASCII | “banana\x00” | 表示一个ASCII字节的字符串 |
.WORD | 0x008B | 在内存中保留一个字,并存值进去 |
.BLOCK | 字节数 | 在内存中保留一些特定的字节 |
注释:为程序读者提供的解释性文字。
6.4.2数字数据、分支、标签
分支:指出执行下一条指令的指令。
助记码 | 操作数,模式 | 含义 |
---|---|---|
DECI | 0*008B,d | 读入八进制数字,并且将它存入008B位置 |
DECO | 0*008B,i | 写十进制数字139(十六进制8B) |
DECO | 0*008B,d | 写内存单元008B上的十进制数字 |
STRO | 0*008B,d | 写内存单元008B上的字符串 |
BR | 0*001A | 转到位置001A |
BRLT | 0*001A | 如果累加器小于零,转到位置001A |
BREO | 0**01A | 如果累加器为零,转到位置001A |
CPWA | 0*008B | 比较内存单元008B和累加器中存储的字 |
标签:对内存位置起的名字,可以将这个名字当作操作数。
6.4.3汇编语言中的循环
6.5表达算法
在计算领域中,解决方案的计划被称为算法,从一个文字叙述形式的问题变为代码并不总是一个明确的过程。伪代码是一种语言,可以让我们以更清晰的形式表达算法。
算法:解决方案的计划或概要,或解决问题的逻辑步骤顺序。
伪代码:一种表达算法的语言。
6.5.1伪代码的功能
虽然伪代码并没有特定的语法规则,但必须要表示出下面的概念:
1.变量
出现在伪代码算法中的名字,引用的是内存中存储值的位置。这些名字要能反映出它存放的值在算法中的角色。
2.赋值
3.输入/输出
4.选择
5.重复
布尔表达式:评价为真为假的表达式
6.5.2执行伪代码计算
6.5.3写伪代码算法
桌面检查:在纸上走查整个设计
6.5.4 翻译伪代码算法
为了测试一个特定的程序以确定它的正确性,我们将设计和实现一个测试计划,测试计划要列出选择这套数据和数据值的原因,还要列出每套数据预期的输入是什么。
有几种测试方法可以作为测试过程的指导:代码覆盖测试法、明箱测试法、数据覆盖测试法、暗箱测试法,测试计划实现要运行测试计划中列出的所有计划用例,并记录运行结果。
测试计划:说明如何测试程序的文档。
代码覆盖(明箱)测试法:通过执行代码中的所有语句测试程序或子程序的测试方法。
数据覆盖(暗箱)测试法:把代码作为一个暗箱,基于所有可能的输入数据测试程序或子程序的测试方法。
测试计划实现:用测试计划中规定的测试用例验证程序是否输出了预期的结果。
最后看一看小结,对本章的知识大体有所了解,但是说实话,还是不太掌握,因为很多东西太过抽象,如果不实践很难弄懂,下周五的课上一定要认真听讲,理解这些抽象难懂的知识。
第7章: 问题求解与算法设计
这一章我们要开始简要讨论总体上如何解决问题。
7.1如何解决问题
7.1.1提出问题
7.1.2寻找熟悉的情况
7.1.3分治法
7.1.4算法
“最终应该得到解决方案”,在计算领域,这种“解决方案”就是算法。算法中的指令是明确的
算法:在有限的时间内用有限的数据解决问题或子问题的明确指令集合。
7.1.5计算机问题求解过程
计算机问题求解包括四个阶段,即分析和说明阶段、算法开发阶段、实现阶段和维护阶段。
7.1.6方法总结
分析问题→列出主要任务→编写其余的模块→根据需要进行重组和改写
7.1.7测试算法
7.2有简单变量的算法
简单变量是那些不能被分开的变量,是存储在一个地方的一个值。
7.2.1带有选择的算法
“if”/“else”
7.2.2带有循环的算法
有两种基本循环,计数控制和事件控制。
1、计数控制循环
计数控制循环可以制定过程重复的次数,这个循环的机制是简单记录过程重复的次数并且在重复再次开始前检测循环是否已经结束。这类循环有三个不同的部分,使用一个特殊的变量叫做循环控制变量。第一部分是初始化:循环控制变量初始化为某个初始值;第二部分是测试:循环控制变量是否已经达到特定值?第三部分是增量:循环控制变量以1递增。
while循环被称为前测试循环,因为在循环开始前就测试了,如果最初条件为假,那么将不进入循环。
2.事件控制循环
循环中重复的次数是由循环体自身内发生的事件控制的循环被称为事件控制循环。当使用while语句来实现事件控制循环时,这一过程仍然分成三部分:事件必须初始化,事件必须被测试,事件必须更新。
计数控制循环是非常简单直接的,而事件控制循环中则不太清楚。
在控制结构中执行或跳过的语句可以是简单的语句或者是复杂的语句。因此跳过或重复的语句中可以包含一个控制结构。
嵌套结构:控制结构嵌入另一个控制结构的结构,又称为嵌套逻辑。
3.平方根
抽象步骤:细节仍未明确的算法步骤。
具体步骤:细节完全明确的算法步骤。
7.3复杂变量
在本节中,我们描述了两种把数据收集到一起、给这个集合命名并访问其中单独的值或者作为一个集合来访问它的方法。
7.3.1数组
数组是同构项目的有名集合,可以通过单个项目在集合中的位置访问它们。项目在集合中的位置叫做索引。
与数组有关的算法分为三类:搜索、排序和处理
搜索就是搜索数组中的项,排序就是按顺序将元素放在数组中,处理是一种捕捉短语,包含了对数组中的项所做的所有其他计算。
7.3.2记录
记录是异构项目的有名集合,可以通过名字单独访问其中的项目,所谓异构,就是指集合中的元素可以不必相同。
7.4搜索算法
7.4.1顺序搜索
7.4.2有序数组中的顺序搜索
如果知道数组中的项目是有序的,那么在查找时,如果我们需要的项目在数组中,到了这个数可以在数组中的位置时就可以停止查找了。
7.4.3二分检索
二分检索:在有序列表中查找项目的操作,通过比较操作排除大部分检索范围。
二分检索算法假设要检索的数组是有序的,其中每次比较操作可以找到要找的项目或把数组减少一半。二分检索不是从数组开头就开始顺序前移,而是从数组中间开始。如果要搜索的项目小于数组的中间项,那么知道这个项目一定不会出现在数组的后半部分。然后再检测数组的中间项,如果要搜索的项目大于中间项,搜索将在数组的后半部分继续。如果中间项等于正在搜索的项目,搜索将停止。
7.5排序
7.5.1选择排序
选择排序算法也许是最简单的,因为它与我们手动排序十分相似。
7.5.2冒泡排序
冒泡排序也是一种选择排序法,只是在查找最小值的时候采用了不同的方法。
7.5.3插入排序
选择排序每次迭代后,一个元素被放置到它的永久位置,而插入排序的每次迭代后,一个元素将被放在相对于其他元素来说适当的位置上。
7.6递归算法
当在一个算法中使用它自己时,这样的算法被称为递归算法,也就是说,如果在某种程度上调用自己,那这个调用称为递归调用。递归就是算法调用它本身的能力,是另一种重复(循环)的控制结构。这种算法使用一个选择语句来确定是否重复算法来调用一遍或停止这一过程,而不是使用一个循环语句来执行一个算法。
递归:算法调用它本身的能力。
每个递归算法至少有两种情况:基本情况和一般情况。基本情况是答案已知的情况;一般情况则是调用自身来解决问题的更小版本的解决方案。因为一般情况下解决的是原始问题越来越小的版本,所以程序最终达到基本情况。
与每个递归问题相关的是如何衡量问题的大小。
所有递归解决方案的第一步都是确定尺寸系数。如果问题涉及的是数值,尺寸系数可能就是数值本身。如果问题涉及结构,那么尺寸系数可能就是结构尺寸。
7.6.1子程序语句
我们可以给一段代码一个名称,然后程序另一部分的一个语句使用这个名称。遇到这个名称时,这个进程的其他部分将会终止,等待这个命名代码被执行。命名代码出现的地方被称为调用单元。
子程序的两种形式:只执行特定任务的命名代码;不仅执行任务,还返回给调用单元一个值。
第一种形式的子程序在调用单元中用作语句,第二种则作为表达式,返回的值被用来测估表达式。
7.6.2递归阶乘
N!=N * (N-1)!
Factorial(O)=1
Factorial(N)=N * Factorial(N-1)
每次调用Factorial时N都会减少,每次给出的数据称为参数。如果参数是负数,子程序将不断调用自身,直到运行时间支持系统耗尽了内存为止。这叫做无限递归。
7.6.3递归二分检索
递归算法必须从非递归算法中调用,正如刚才的阶乘算法那样。
7.6.4快速排序
如果数据是随机排列的,那么快速排序是一个很好的排序方法。
7.7几个重要思想
7.7.1信息隐蔽
信息隐蔽:隐蔽模块的细节以控制对这些细节的访问的做法。
7.7.2抽象
信息隐蔽是隐藏细节的做法,抽象则是隐藏细节后的结果,
抽象:复杂系统的一种模型,只包括对观察者来说必需的细节。
我们会看到计算领域中的各种抽象类型:
数据抽象:把数据的逻辑视图和它的实现分离开。
过程抽象:把动作的逻辑视图和它的实现分离开。
控制抽象:把控制结构的逻辑视图和它的实现分离开。
控制结构:用于改变正常的顺序控制流的语句。
7.7.3事物命名
7.7.4测试
思维导图
最后用两张思维导图总结一下内容吧~
总结与反思
本周自学的这两章在内容上比较抽象,比较难以理解。不过好在上周的自学内容经过一个礼拜的消化和老师的讲解已经比自学时候有较大进步,今日事今日毕,希望这两章抽象难懂的内容也能慢慢消化,直到彻底理解。上课还要认真听,不要慌张,加油!冲冲冲!