2019-2020-1学期 20192417《网络空间安全专业导论》第三周学习总结
第四部分 程序设计层
第6章 低级程序设计语言与伪代码
重点从“什么是计算机系统”变成“如何使用计算机系统”。
6.1计算机操作
1.计算机定义:计算机是能够存储、检索和处理数据的可编程电子设备。
2.要改变计算机对数据的处理,只需要改变指令即可。
3.存储、检索和处理是计算机能够对数据执行的动作。
4.在机器层,处理涉及在数据值上执行算术和逻辑操作。
6.2 机器语言
1.计算机真正执行的程序设计指令是用机器语言编写的指令,这些指令固定在计算机的 硬盘中。
2.机器语言(machine language):由计算机直接使用的二进制编码指令构成的语言。
3.目前几乎没有程序是用机器语言编写的,主要是因为编写这种程序太费时间。
Pep/8:一台虚拟机
1.虚拟机(virtual computer(machine)):为了模拟真实机器地重要特征而设计的假想机器。
2.Pep/8有39个机器语言指令。这意味着每个Pep/8程序一定是由这些指令组合而成的序列 。
Pep/8反映的重要特征:
1.Pep/8的内存单元由65536个字节的存储空间构成。这些字节从0到65535( 十进制)进行编号。Pep/8的字长是两字节,或者16比特。这样向算术/逻辑单元(ALU)流入的数据或从 算术/逻辑单元流出的数据在长度上就是 16比特。
3.Pep/8有 7个存储器,我们重点研究其中三个:
程序计数器(PC),其中包含下一条即将被执行的指令的地址。
指令寄存器(IR),其中包含正在被执行的指令的一个副本。
累加器(是一个寄存器):一种特殊的存储寄存器。
指令格式
一条指令由两个部分组成,即8位的指令说明符和(可选的)16位的操作数说明符。
指令说明符说明了要执行什么操作和如何解释操作数的位置。操作数说明符(指令存放的第二个和第三个字节)存放的是操作数本身或者是操作数的地址。有些指令没有操作说明符。
3比特的寻址模式说明符:
立即寻址(i)(000):指令的操作说明符中存储的是就是操作数。
直接寻址(d)(001):指令的操作说明符中存储的是操作数所在的内存地址名称。
没有操作数的指令称为一元指令,这些指令没有操作说明符,即一元指令符的长度是1个字节。
一些示例指令
0000:停止执行
1100:将操作数载入寄存器A中
1110:将寄存器A中的内容存储到操作数中
0111:将操作数加到寄存器A中
1000:将寄存器A中的值中减去操作数的值
01001:把字符输入操作数
01010:从操作数输出字符
6.3 一个程序实例
例子:在屏幕上显示“Hello”。有6条指令:5条用于显示字符,一条用于指示过程的结束。
我们必须用二进制构造操作说明符,因为它由4位操作码、1位寄存器说明符和3位寻址模式说明符构成。
我们使用双引号来指一组字符,如“Hello”,使用单引号指单个字符。
6.3.1 手工模拟
6.3.2 Pep/8模拟程序
要运行一个程序,需要逐字节地输入十六进制的代码,每个字节之间用空格隔开,以zz结束程序。
装入程序(loader):软件用于读取机器语言并把它载入内存的部分。
6.4 汇编语言
汇编语言(assembly language):一种低级语言,用助记码表示特定计算机的机器语言指令。
汇编器(assembler):把汇编语言程序翻译成机器代码的程序。
6.4.1 Pep/8汇编语言
在Pep/8汇编语言中,每个寄存器有一个操作码,操作数是十六进制的,由0x说明,寻址模式说明符由字母i或d说明。
Pep/8汇编语言提供了助记忆码DECI和DECO,它允许我们做十进制输入和输出。
6.4.2 汇编器指令
两种类型的指令:要翻译的指令和翻译程序使用的指令。
汇编器指令(assembler directive):翻译程序使用的指令。
6.4.3 Hello程序的汇编语言版本
注释(comment):为程序读者提供的解释性文字。
汇编器的输入是一个用汇编语言编写的程序,输出是用机器代码编写的程序。
6.4.4 一个新程序
6.4.5 具有分支的程序
已经表明,一个将程序计数器设为下一条被执行的指令地址的BR指令可以改变程序计数器。
6.4.6 具有循环的程序
计数器(counter):在内存中一个为0的存储单元。(散列标记)
6.5 表达算法
算法(algorithm):解决方案的计划或概要,或解决问题的逻辑步骤顺序。
伪代码(pseudocode):一种表达算法的语言。
6.5.1 伪代码的功能
虽然伪代码并没有特定的语法规则,但必须要表示以下的概念:变量、赋值、输入/输出、选择和重复。
布尔表达式(boolean expression):评价为真或假的表达式。
6.5.2 执行伪代码算法
6.5.3 写伪代码算法
桌面检查(desk checking):在纸上走查整个设计。
6.5.4 翻译伪代码算法
如何翻译伪代码算法取决于我们将算法翻译成哪种语言。
由于汇编语言的范围是有限的,所以一个伪代码语句需要几个 Pep/8语句。
6.6 测试
测试计划(test plan):说明如何测试程序的文档。
代码覆盖(明箱)测试法(code-coverage(clear-box)testing):通过执行代码中的所有语句测试程序或子程序的测试方法。
数据覆盖(暗箱)测试法(data-coverage(black-box)testing):把代码作为一个暗箱,基于所有可能的输入数据测试程序或子程序的测试方法。
测试计划实现(test-plan implementation):用测试计划中规定的测试用例验证程序是否输出了预期的结果。
第7章 问题求解与算法设计
7.1 如何解决问题
7.1.1 提出问题
典型问题:
对这个问题我了解多少?
解决方案是什么样的?
存在什么特例?
我如何知道已经找到解决方案了?
Polya的“如何解决它”列表:
第一步:必须理解问题。
第二步:找到信息和解决方案之间的联系。如果找不到直接的联系,则可能需要考虑辅助问题。最终,应该得到解决方案。
第三步:执行方案。
第四步:分析得到的解决方案。
7.1.2 寻找熟悉的情况
7.1.3 分治法
通常,我们会把一个大问题划分为几个能解决的小单元,这项原则尤其适用于计算领域:把大的问题分割成能够单独解决的小问题。
可以把一项任务分成若干个子任务,而子任务还可以继续划分为子任务,如此进行下去。可以反复利用分治法,直到每个子任务都是可以实现的为止。
7.1.4 算法
算法(algorithm):在有限的时间内用有限的数据解决问题或子问题的明确指令集合。
7.1.5 计算机问题求解过程
计算机问题求解过程包括四个阶段,即分析和说明阶段、算法开发阶段、实现阶段和维护阶段。
分析和说明阶段 分析 理解(定义)问题 说明 说明程序要解决的问题 算法开发阶段 开发算法 开发用于解决问题的逻辑步骤序列 测试算法 执行列出的步骤,看它们能否真正地解决问题 实现阶段 编码 用程序语言翻译算法(通用解决方案) 测试 让计算机执行指令序列。检查结果,修改程序,知道的得到正确答案 维护阶段 使用 使用程序 维护 修改程序,使它满足改变了的要求,或者纠正其中的错误
7.1.6 方法总结
自顶向下的方法可以分解为一下四个步骤。
1.分析问题
2.列出主要任务
3.编写其余的模块
4.根据需要进行重组和改写
7.1.7 测试算法
数学问题求解的目标是生成问题的特定答案,因此,检查结果等价于测试推出答案的过程。但是,计算机问题求解的目标是创建正确的过程。
7.2 有简单参数的算法
简单(原子)变量是那些不能被分开的变量,是存储在一个地方的一个值。
7.2.1 带有选择的算法
7.2.2 带有循环的算法
计数控制循环:
1.计数控制循环可以指定过程重复的次数,这个循环的 机制是简单记录过程重复的次数并且在重复再次开始前检测循环是否已经结束。
2.这类循环有三个不同的部分,使用一个特殊的变量叫循环控制变量。第一部分是初始化:循环控制变量初始化为某个初始值。第二部分是测试:循环控制变量是否已经达到特定值?第三部分是增量:循环控制变量以1递增。
3.while循环被称为前测试循环。
4.永远不会终止的循环称为一个 无限循环。
事件控制循环
1.定义:循环中重复的次数是由循环体自身内发生的事件控制的循环。
2.当使用 while语句来实现事件控制循环时,这一过程仍分为三部分:事件必须初始化,事件必须被测试,事件必须更新。
嵌套结构(nested structure):控制结构嵌入另一个控制结构的结构,又称为嵌套逻辑(nested logic)。
另一个示例:求数字的平方根
抽象步骤(abstract step):细节仍未明确的算法步骤。
具体步骤(concrete step):细节完全明确的算法步骤。
7.3 复杂变量
引用中的字母叫作字符串。
7.3.1 数组
1.数组:同构项目的有名集合。
2.项目在集合中的位置叫索引。
3.与数组有关的算法分为三类:搜索、排序和处理。
7.3.2 记录
记录是异构项目的有名集合,可以通过名字单独访问其中的项目。
集合可以包含整数、实数、字符串或其他类型的数据。
7.4 搜索算法
7.4.1 顺序搜索
7.4.2 有序数组中的顺序搜索
7.4.3 二分检索
二分检索不是从数组开头开始顺序前移,而是从数组中间开始。
二分检索(binary search):在有序列表中查找项目的操作,通过比较操作排除大部分检索范围。
7.5 排序
本节将介绍几种完全不同的排序算法。
7.5.1 选择排序
选择排序算法虽然简单,但却有缺陷,它需要两个完整列表(数组)的空间。即使不考虑内存空间,赋值操作显然也很费空间。
7.5.2 冒泡排序
1.冒泡排序也是一种选择排序法,只是在查找最小值时采用了不同的方法。它从数组的最后一个元素开始,比较相邻的元素对,如果下面的元素小于上面的元素,就交换这两个元素的位置。
2.冒泡排序是非常慢的排序方式。
7.5.3 插入排序
将元素加入有序部分类似于冒泡排序中冒泡的过程。如果找到了一个位置,要插入的元素比数组中这个位置的元素小,那么就将新元素插入这个位置。
current就是元素插入有序部分中的元素。
7.6 递归算法
递归算法:当在一个算法中使用它自己时时的算法。
递归(recursion):算法调用它本身的能力。
每个递归算法至少有两种情况:基本情况(答案已知的情况)和一般情况(调用自身来解决问题的更小版本的解决方案)。
7.6.1 子程序语句
命名代码出现的地方被称为调用单元。
子程序有两种形式,一种是只执行特定任务的命名代码,一种是不仅执行任务,还返回给调用单元一个值(值返回子程序)。
7.6.2 递归阶乘
数的阶乘的定义:这个数与0和它自身之间的所有数的乘积。N!=N(N - 1)!
0的阶乘是1.尺寸系数就是要计算阶乘的数。
基本情况是:
Factorial(0)=1
一般情况是:
Factorial(N)=NFactorial(N - 1)
7.6.3 递归二分检索
7.6.4 快速排序
快速排序算法的基本思想:对两个小列表排序比对一个大列表排序更快更容易。
其名字来自源于这种算法通常可以相对快地对数据元素列表进行排序,其基本策略是“分治法”。
如果数据是随机排列的,则快速排序是一个很好的排序方法。
7.7 几个重要思想
7.7.1 信息隐蔽
信息隐蔽(information hiding):隐蔽模块的细节以控制对这些细节的访问的做法。
7.7.2 抽象
信息隐蔽是隐藏细节的做法,抽象则是隐藏细节后的结果。
抽象(abstraction):复杂系统的一种模型,只包括对观察者来说必需的细节。
数据抽象(data abstraction):把数据的逻辑视图和它的实现分离开。
过程抽象(procedural abstraction):把动作的逻辑视图和它的实现分离开。
控制抽象(control abstraction):把控制结构的逻辑视图和它的实现分离开。
控制结构(control structure):用于改变正常的顺序控制流的语句。
7.7.3 事物命名
给数据和过程一个名字,这些名字叫作标识符。
7.7.4 测试
测试在编程的每个阶段都十分重要,有两种基本的测试分类:白盒测试,基于代码本身; 黑盒测试,基于测试所有可能的输入值。
问题:对于几种排序不是很明白;
平方根算法中初始值中epsilon是不是设置大于0.001就可以了?原始猜测除了平方数除以4还有更好的吗?
计算机领域的 抽象 意思是做出算法就可以了吗?P154最后几段感觉说得有点矛盾,不太明白。
P148最上面一段“而不是使用一个循环语句执行一个算法”是什么意思?