计算机基本原理 学习笔记(六)

本篇目录

接上)

八、编程

1.编程语言发展史

2.语句和函数

九、数据结构与算法

1.算法

2.数据结构

总结

扫描二维码关注公众号,回复: 14727561 查看本文章

接上一篇 学习笔记(五)

八、编程

1.编程语言发展史

1.硬件编程

给机器编程的需求早已有之,雅卡尔织布机被认为是最早的编程。这种纸卡/纸带编程的方式一直到近一百年后的美国人口普查仍在使用。但人口普查卡片上存储的是数据,不是程序。之后有了插线板编程,即程序员先在纸上写好程序,然后使用插线板(作为控制面板)来编程,编写程序的工作很复杂。

1950年代,有了内存,于是程序员可以将程序存储在内存中,而不是插接在插线板上。这就是“存储程序计算机”。如果内存足够大,还可以存数据。将程序和数据都存在一个地方,这是“冯·诺依曼结构”。冯·诺依曼计算机的标志是CPU(包含ALU)+数据寄存器+指令寄存器+指令地址寄存器+内存(存储数据和指令)。第一台冯·诺依曼结构的计算机于1948年建造完成,绰号“宝宝”。这种计算机的架构沿用至今。

至1980年代,几乎所有计算机都是用穿孔纸卡/纸带和读卡器作为IO设备,最大型的纸卡程序是美国空军的SAGE防空系统(1955年完成)。与此同时还有另外一种编程方式,即控制面板编程。程序员(或者爱好者)不再插接导线,而是通过按开关和按钮来实现同样的效果。因此计算机有一个巨大的控制台,用于编程输入与显示内存中的数据。第一款取得商业成功的家用计算机Altair8800,使爱好者可以通过拨动面板上的开关并按“存储”键,来将程序(的二进制操作码)输入进计算机,之后执行。

总的来说,使用硬件编程复杂繁琐,人们渴望更加便捷的软件编程方式。

2.机器码编程

早期使用机器码编程,先用纸笔写好伪代码(对程序算法的高层次描述),之后对照“操作码表”(指令集中支持的指令所对应的操作码)将伪代码转为二进制机器码,再将二进制机器码输入电脑。但这种编程方式仍然很麻烦。

3.汇编语言

1940-1950年代,程序员发明了一些助记符,与二进制操作码一一对应(所以说不同的硬件有不同的汇编语言,因为指令集不同)。这就是汇编语言。为了能够在电脑上运行汇编语言程序,程序员用二进制机器码编写了“汇编器”,这种程序能够读取汇编语言(助记符是字符),并翻译为机器码。

之后汇编器还拥有了更多功能,比如自动跳转。程序员可以给指令加上一些标号,在编程时指定跳转到某个标号,汇编器会自动计算正确的跳转位置。但一条汇编指令对应一条机器指令,程序员仍然要思考大量硬件底层细节,如寄存器、内存地址等。

4.高级编程语言A-0

二战时期建造的哈弗马克一号计算机,使用打孔纸带编程,指令集非常原始,甚至没有JUMP指令。如果程序有“漏洞”,就直接用胶带粘起来。(天哪)作为哈弗马克一号的首批程序员,霍普博士设计了一个高级编程语言“算数语言版本0”(简称A-0),不过这个语言以及之后的版本没有流传下来。1952年,霍普博士创造了第一个编译器,编译器能将高级编程语言转换为低级编程语言(汇编语言或机器码)。高级编程语言的执行慢一点,但是编程效率大大提高。后来有许多人尝试发明不同的高级编程语言。

5.FORTRAN

它的名称来自“公式翻译”,由IBM在1957年发布,主宰了早期计算机编程。早期FROTRAN只运行在IBM公司的计算机上,当时大部分编程语言都是如此。1959年业界组建了数据系统语言委员会,霍普博士担任顾问,旨在开发一门具有通用性的语言。这门语言就是“普通面向商业语言”COBOL。每个计算机都要有一个COBOL编译器,之后,所有的这些计算机就可以接收相同的COBOL代码并运行,即“一次编写、到处运行”。如今大部分编程语言都是如此,这大大降低了编程门槛。

6.其它语言

1960年代,诞生了ALGOL、LISP、BASIC等语言,1970年代,诞生了PASCAL、C、Smalltalk等语言,1980年代诞生了C++、Objective-C、PERL等语言,1990年代诞生了Python、Ruby、Java等语言,2000年代诞生了SWIFT、C#、Go等语言。新的语言还在不断诞生。


2.语句和函数

1.赋值语句

将一个值赋给变量或常量。在程序中,变量的值常常需要初始化。

2.流程控制语句

语句不仅可以顺序执行,还可以通过流程控制语句来控制语句执行顺序。

3.IF语句

IF语句通过判断“条件判断语句”(一个表达式)的值是true还是false,来决定接下来执行的语句。基本结构如下。

IF( 表达式 ) 
then {

    当表达式为true时要执行的语句 
} 
else{ 
    当表达式为false时要执行的语句 
}
endif

4.while循环语句

当满足条件时(表达式为true),重复执行特定语句,直到条件不再满足。

while(表达式)

    要循环执行的代码
loop

5.for循环

指定循环的次数,当超出次数后,循环结束。

for (变量 = 初始值 to 终值)
    循环执行的语句
next

6.函数

实现特定功能的一些语句,可以打包(封装,向上抽象)为一个函数,别的程序可以通过函数名调用。定义一个函数,要声明函数名称、需要接收的变量、返回值(使用return函数)。现代编程中很少有超过100行代码的函数。模块化编程有助于提高编程效率。现代编程语言中,一般有很多预先写好的函数集,即“库”。 


九、数据结构与算法

1.算法

1.算法

“算法”一词来自波斯博识者阿尔·花拉子密,表示解决问题的步骤。

2.简单选择排序

算法每趟执行,都选定一个固定位置,比较该位置的元素与数组中其它元素的大小,并根据比较结果来进行元素置换。这样,每趟执行都能将一个元素固定在正确位置上。经过n趟(假设待排序的元素有n个)后,排序完成。

这样的算法用到了2层嵌套for循环,时间复杂度是O(N^2)。这就是大O表示法。

3.归并排序

先检查数组长度是否>1,若是则拆分。之后两两归并,排序完成。这样,比较的次数为O(n),而合并的次数为O(log n),因此总的时间复杂度为O(n log n)。

4.图搜索 Dijkstra算法

对于带权图的单源最短路径问题,如果暴力求解则时间复杂度为O(n!)。Dijkstra算法的每趟都更新当前结点的邻接结点的最短路径,并从已知结点的集合中选择能伸出的最短路径作为下一条路径。这个算法的时间复杂度为O(n^2),不过之后经过优化就变为了O(n log n + E),E表示边数,N表示结点数。


2.数据结构

算法的实现要依赖一定的数据结构,即数据在内存中的存储方式(其实这是存储结构)。

1.数组

数组Array,也叫列表list,或者向量Vector。数组的值在内存中连续存储,数组有下标,可以通过“a[0]”访问名称为a的数组的首个元素(数组下标从0开始)。访问数组中的元素时,首先根据数组名称找到数组在内存中存储的首地址,接着以数组下标作为偏移量,找到内存中对应的元素。数组应用广泛,因而大多数编程语言都有大量处理数组的函数。数组在创建时就有固定大小,不能动态增加。且数组在内存中顺序存储,插入和删除数据比较困难。

2.字符串

字符串String,就是字符组成的数组。字符串在内存中以二进制0为结尾,这是NULL 字符。

3.矩阵

矩阵Matrix,可以看做是多维数组。

4.结构体

结构体Struct,将多个有内在关联的变量打包在一起。结构体可以创造比数组更加复杂的数据结构,从而消除数组结构的一些弊端(大小固定、插入与删除困难等)。

5.结点

结点Node,是一种结构体,内部有一个变量和一个指针Pointer。指针是一种特殊的变量,指向一个内存地址。用结点可以做链表,每一个结点的指针指向下一个结点。因此链表是一种灵活的数据结构,可以存多个结点,插入和删除都很方便。链表在内存中不用非要顺序存储。

链表可以是循环链表,如果是非循环的,最后一个指针是0(null),代表链表结束。链表这种存储结构可以用来实现队列QUEUE结构以及栈STACK结构。

6.队列

队列Queue,遵循先进先出(FIFO)原则。队列的常用操作是入队(在末尾新增元素)和出队(在队首删除元素)。队列使用链表作为存储结构。

7.栈

栈Stack,遵循后进先出(LIFO)原则,也是用链表作为存储结构。栈的常用操作是入栈(PUSH)和出栈(POP)。

8.树

树也是一种结构体,其中包含了一个变量和两个指针变量。每个树结点的指针指向子结点,树结构有一个根结点,没有其它结点指向根结点。如果一个结点没有子结点,那么它就是叶结点。最多只有两个结点的树是二叉树。根结点到叶结点是单向的。

9.图

图是多对多的数据结构,这种结构可以用有多个指针的结点表示。

10.其它

其它的结构变体,比如红黑树、堆等,有各自不同的性质。不同数据结构适用于不同场景,选择正确的数据结构能大大提高工作效率。大多数编程语言自带了预先定义好的数据结构,


总结

本篇内容:

1.编程语言发展史

2.语句与函数

3.算法

4.数据结构

猜你喜欢

转载自blog.csdn.net/Dr_Cheeze/article/details/128075778