回应模式 - No.60413427


No.60413427 - 科学


计算机导读从摇滚开始无名氏No.60413427 返回主串

2023-12-04(一)01:21:43 ID:22b93o1 回应

这是一个从零开始的计算机学教程。教程里不会出现太过于深奥的内容,而是鼓励肥哥们根据串内的推荐自行学习。这个串只起到初步解释和导读的作用。

为了让计算机学更加有趣,也为了满足我的摇滚癖好,计算机和摇滚会在这个串里有机地结合起来,毕竟学习时听听音乐不也挺好嘛(ゝ∀・)

无标题无名氏No.60423437

2023-12-04(一)22:02:56 ID: 22b93o1 (PO主)

https://y.music.163.com/m/song/3424884

>计算机本质与抽象化

计算机是做什么用途的?简单来说,对计算机输入数据,计算机处理数据,计算机输出数据。这就是计算机的本质。

输入和输出数据的过程根据计算机的不同而不同,例如通过键盘可以输入键位信息,而通过显示屏可以输出图像信息。

处理数据的过程极为复杂。从物理的角度,无数电流流经电路,电平不断变化,这就是数据的处理。从数学的角度,计算机根据指令对数据进行有条件的,存在循环的,会终止的更改,使其变为我们想要的样子。从软件工程的角度,无数底层指令在我们输入高级编程语言时被一齐使用,以更改一个或多个存储于某处的数字(我们称其为变量)。

为了不让我们在思考数学公式时还要陷于对于用什么编程语言的思考,或者在编程时还要进行对于逻辑门中电平会怎样流动的回想,我们引入了一种叫做“抽象化”的东西,以屏蔽不必要的细节。

抽象化,就是把一个现实存在的,有复杂机理的东西封装(encapsulate)为不透明的黑盒,而我们没必要透过黑盒去了解其原理,也能使用这个黑盒。

计算机本身就是一个巨大的黑盒。一个人不需要懂计算机有啥零件,也可以流畅地使用计算机。这个人不需要知道什么是累加器,也可以在计算机上进行加减乘除运算。

哪怕是一个资深的软件工程师,也可以选择放弃了解一个程序的基本原理,只要知道输入一样数据,对应的输出应该是什么就可以。

那么,一个程序员可以在不知道计算机基本原理的情况下进行编程吗?

我的回答是,可以,但仅限于可以。缺乏了对于各种数学和工程原理的认知,一个程序员在遇到深奥问题时不知道如何解决。更重要的是,缺乏了基础知识的根基与基础知识所代表思想的指引,一个程序员没法更进一步地学习。

学习是计算机相关从业者很重要的一环。IEEE将“终身学习”作为软件工程师应有的品质。计算机相关的理论很容易化为实际的程序,所以计算机的发展很快,跟不上发展的节奏就会被远远落下。

抽象化是一道隐藏着智者的高墙。你能听见来自墙的另一边的声音,却不知道那是谁传出的,就像平克弗洛伊德的迷墙一样。对于未知的恐惧,是否能激励你学习各种原理呢?

无标题无名氏No.60433781

2023-12-05(二)18:40:02 ID: 22b93o1 (PO主)

https://y.music.163.com/m/song/19553390

>算法

算法,Algorithm,顾名思义,即计算的方法。在计算机学的意义下,算法接受输入,进行计算,然后输出。与“计算机”这种概念不同的是,每个算法都是为了一种设计算法时就预先定下的理念或者目的所创造的,也就是说,其目的性很强。而计算机可以用来干繁多的事物。

用个粗鲁的比方:榨汁机和人都需要吃水果,但榨汁器有着将水果转化为果汁的目的,而人广泛来说没有这么明确的目的。

算法在数学意义上可以理解为一种函数,function。Function这个词本身就有功能的意思。举个例子,加法是一种算法,其接受两个变量(不要忘了,变量是存储于某处的数据,之后会有更加明确的定义),输出一个数字,那个数字是变量中两数之和。

就像把一个盒子(变量)里的苹果(数据)和另一个盒子(变量)里的香蕉(数据)同时放进“乘法”这种榨汁机里,它们会变成处理好的果汁(数据)。别忘了再拿个杯子(变量)把果汁(数据)装进去。

我们写作:
c←x(a,b)

其中x指代乘法,a,b与c为变量。a与b为输入,箭头符号指赋值,即让输出的数字被装到c中,或者说更改c的内容,使其与输出的数字相同。这样,我们想要这个数字的时候就可以问c要。

为了写法简便,我们用等于号(=)来替代箭头符号,此时的等于号表示赋值而不是相等。

也就是,c=x(a,b)

乘法这种算法用x(a,b)的形式不符合我们的数学认知,所以我们可以简写为a*b,即c=a*b。

这代表使用算法将a与b相乘,将算法的返回值(即算法输出的那个值)赋值给c。

而乘法的实现原理,是将a与b的每一位相乘,将得到的结果在进位后相加。如果不知道二进制乘法是怎么进行的,建议先自行学习二进制乘法。大多数情况下用不到,但身为计算机系不会这个有点丢人,而且终究还是有用的。

好好珍惜这个简单的算法,一般的算法不会这么简单。

一个人的脑中藏着无数个变量,而这些变量在神经元的电信号传播中不断变换。我们是藏在变量之中的游魂。

又如同马克思曾经说过的,“一切已死的先辈们的传统,像梦魇一样纠缠着活人的头脑”。我们在潜移默化之中,已经被文化传统赋予了一些先辈的值。

无标题无名氏No.60436181

2023-12-05(二)22:24:39 ID: 22b93o1 (PO主)

https://y.music.163.com/m/song/3955886

算法是计算机学中我最喜欢的一部分:优雅,美丽,包含着数学的纯粹和计算机的伟力。在学习算法的过程中,你会接触的大数远远大过世界上所有原子数量的总和,你会遇到的计算次数轻易超出群星之数。你会看见均称美丽的树与图。算法是计算机的灵魂。当学习算法时,请试图保持Maria一样的热情。

我很久没关心算法的教科书更新了。如果想要学习算法,我会推荐比较老的《算法导论(Introduction to Algorithms)》。

但这里还是简单地解释一下算法这种研究的目的和意义。在了解算法之前,请确保你有一些基本的函数和统计学知识。例如什么是“期望值”,什么样的函数比什么样的函数增长更快。

天道无情。对于世界来说,没有聪明的东西,没有愚蠢的东西。一切方法都只是方法。

但对于一个内卷严重的人类社会来说,这个世界上存在“笨方法”和“聪明方法”,这是大家都知道的事情。

算法是对于一种问题提出的,那么我就举一个简单的问题:排序问题。这个问题要求输入一串数字,例如9,5,2,7(注意,一串数字也可以是一个输入,这一点之后会详细说明,但结合“许多字节可以存放许多个数据”的说法,你们应该可以初步理解);然后输出从小到大排列后的数字,也就是2,5,7,9。

那么,有什么笨方法可以进行这样的排序呢?科学家能想到的(想一个笨方法也需要聪明的脑袋),最笨的方法是将数字随机打乱,然后从前往后确认一遍这串数字是否以从小到大排列,确认的方法是从第二个数开始,比较第n个数和第n-1个数,如果第n个数据比第n-1个数小,那么说明并没有排列好,停止检查,重新打乱,再次检查,直到排列好。

按平均期望来说,随机打乱n个数,假设这些数都不相同,打乱后正好排好序的可能性是1/(n!),也就是说平均n!次打乱之后可以得到一次正好排列好的。别忘了我们每次打乱顺序之后都要检查一遍是否排列好。假设每次检查都要比较n/2次(实际上大多数情况下比这个少,取决于数的分布规律),那么我们平均需要比较n/2*(n!)次。

但是如果运气很好,理论上来说我们只要打乱一次就能获得排列好的数字。此时只需要1次打乱数字,n/2次比较大小(运气好不代表我们可以省略比较大小的过程,算法可不知道自己运气好,它只会执行它被要求做的事情)。

但如果运气最差,那么我们在有限次打乱中永远获得不了排列好的数字,因为这种可能性是存在的:m次打乱获得不了排列好的数字的可能性是(1-1/(n!))^m。仅当m趋向于无限时,这个可能性趋向于0,也就是我们一定能获得排序好的数字。

也就是说,这个算法平均情况下大概需要进行n!次打乱和n/2*(n!)次比较,最好情况下约需要进行1次打乱和n/2次比较,最差情况下需要无限次打乱。

我们说这种算法是不明智的,我们不会使用这种算法,是因为我们进行了类似于上述的分析,发现它花费的计算时间理论上来说非常多,不值得我们使用。

这种算法的名字叫做猴子算法,灵感出自猴子莎士比亚打字机。或者叫它Bogosort也可以,sort是排序的意思,Bogo是这种算法的名字。在常规情况下,这种排序方式就是浪费资源。但在量子计算机的环境下,这种算法颇有启发性。

无标题无名氏No.60436207

2023-12-05(二)22:27:11 ID: 22b93o1 (PO主)

>>No.60436181
补充一点,n是大于1的正整数,否则只有一个数的列表必定是排序好的(或者必定是没有排序好的,反正没有研究的价值)

无标题无名氏No.60447352

2023-12-06(三)21:41:29 ID: 22b93o1 (PO主)

https://y.music.163.com/m/song/20045638

在介绍一个优美的好方法(并不是最好)之前,我们得先简单地了解一下算法界常用的,用于评估一个算法好不好的指标。

这个评估指标被称作复杂度。我们会根据算法在消耗时间,占用空间方面的大小和输入数据的大小的比例来判断这个算法好不好用。我们还会根据算法的最优表现(对于n个输入,理论最短结束的时间或最小花费的空间),最差表现和平均表现(期望值表现)来判断复杂度。

关于复杂度的定义,请参阅算法导论,我记得这本书的很前面就有这个定义。

在你了解什么是复杂度之后,我会简单地介绍什么是数据类型和数据结构。

对于计算机来说,一切都是0和1的数据,正如对世界来说,一切都是基本粒子。

但是粒子的组合也有不同的性状,例如常温下是液体的水和常温下是固体的铁是不一样的。数据亦然。数据的性状由其用途分类。根据用途不同,我们可以分出类似于这些的数据类型:

- 整数(int):可以用于表示“个数”
- 布尔值(boolean):仅有两种布尔值:正确与错误,用于表示“是否”的判断
- 字符(char):单个的字符,如“a”或者“♡”,一般来说算法中仅考虑英文字符就足够了。字符本质上是一个代表了字符的数字(想想二进制代表不同肢体的例子)
- 列表(array):一个收纳了单个或多个数据类型的数据的集合,根据用途不同,定义不同。例如前文的“9,5,2,7”就是一个只存放整数的列表。列表中的每一个东西被称为它的元素(element)。在某些编程语言的定义下,列表甚至可以有无限个元素,但同一时间只能取出有限个元素
- 字符串(string):仅存放字符的列表。
...

对于上述数据类型中的每一个,我们都有一些独特的操作。例如对于整数,我们可以加减乘除;对于列表,我们可以增加元素,修改元素,删除元素,引用元素(即获取一个元素的值)等。

也正像我们可以通过创造工具的方式利用外物来代替自身来作业,我们可以赋予数据类型特殊的意义,以使其成为一种稳定的结构,即数据结构。这种结构有两个作用:

>方便我们使用
包括方便我们可视化,理解,提出相关理论,分析,利用和转化。

>作为算法的前提
一些算法可以简单地解决难题,是因为其输入是一种稳定的,有可以被利用的独特性质的数据结构。

事实上,一些睿智的学者甚至证明了某些应用于不同数据结构的难题可以互相转化(reduction)。PNP问题的提出就利用到了一些转化。

数据结构需要维护。当数据结构发生变化的时候,我们需要进行一些操作来使其性质不发生变化,就像你不能把随便什么东西随意扔在你的桌子上,然后声称它还是被整理好的桌子。

接下来的排序算法中,我用到“列表”这种数据类型,和“被排序好的列表”这种数据结构。

听一听Discipline,它会让你感受到变化与秩序的伟力。

无标题无名氏No.60447359

2023-12-06(三)21:41:57 ID: 22b93o1 (PO主)

https://y.music.163.com/m/song/20045638

在介绍一个优美的好方法(并不是最好)之前,我们得先简单地了解一下算法界常用的,用于评估一个算法好不好的指标。

这个评估指标被称作复杂度。我们会根据算法在消耗时间,占用空间方面的大小和输入数据的大小的比例来判断这个算法好不好用。我们还会根据算法的最优表现(对于n个输入,理论最短结束的时间或最小花费的空间),最差表现和平均表现(期望值表现)来判断复杂度。

关于复杂度的定义,请参阅算法导论,我记得这本书的很前面就有这个定义。

在你了解什么是复杂度之后,我会简单地介绍什么是数据类型和数据结构。

对于计算机来说,一切都是0和1的数据,正如对世界来说,一切都是基本粒子。

但是粒子的组合也有不同的性状,例如常温下是液体的水和常温下是固体的铁是不一样的。数据亦然。数据的性状由其用途分类。根据用途不同,我们可以分出类似于这些的数据类型:

- 整数(int):可以用于表示“个数”
- 布尔值(boolean):仅有两种布尔值:正确与错误,用于表示“是否”的判断
- 字符(char):单个的字符,如“a”或者“♡”,一般来说算法中仅考虑英文字符就足够了。字符本质上是一个代表了字符的数字(想想二进制代表不同肢体的例子)
- 列表(array):一个收纳了单个或多个数据类型的数据的集合,根据用途不同,定义不同。例如前文的“9,5,2,7”就是一个只存放整数的列表。列表中的每一个东西被称为它的元素(element)。在某些编程语言的定义下,列表甚至可以有无限个元素,但同一时间只能取出有限个元素
- 字符串(string):仅存放字符的列表。
...

对于上述数据类型中的每一个,我们都有一些独特的操作。例如对于整数,我们可以加减乘除;对于列表,我们可以增加元素,修改元素,删除元素,引用元素(即获取一个元素的值)等。

也正像我们可以通过创造工具的方式利用外物来代替自身来作业,我们可以赋予数据类型特殊的意义,以使其成为一种稳定的结构,即数据结构。这种结构有两个作用:

>方便我们使用
包括方便我们可视化,理解,提出相关理论,分析,利用和转化。

>作为算法的前提
一些算法可以简单地解决难题,是因为其输入是一种稳定的,有可以被利用的独特性质的数据结构。

事实上,一些睿智的学者甚至证明了某些应用于不同数据结构的难题可以互相转化(reduction)。PNP问题的提出就利用到了一些转化。

数据结构需要维护。当数据结构发生变化的时候,我们需要进行一些操作来使其性质不发生变化,就像你不能把随便什么东西随意扔在你的桌子上,然后声称它还是被整理好的桌子。

接下来的排序算法中,我用到“列表”这种数据类型,和“被排序好的列表”这种数据结构。

听一听Discipline,它会让你感受到变化与秩序的伟力。

无标题无名氏No.60447367

2023-12-06(三)21:42:34 ID: 22b93o1 (PO主)

>>No.60447359
说实话,关于数据结构和数据类型的定义我有些记不清了,如果有问题的话请告诉我,非常感谢

无标题无名氏No.60460658

2023-12-08(五)01:05:03 ID: 22b93o1 (PO主)

https://y.music.163.com/m/song/18860373

那么,我开始介绍归并排序(Mergesort),包括其算法的运作机制,原理,具体实现,改进方案,复杂度与缺点。

首先,为了普适性,我们拿的例子是一个仅包含数字的列表:[1.0, 3.1, 2.5, 5.6, 0.7]。

“[”代表列表的开始,“]”代表其结束,其中每一个被逗号分割的数字都是一个该列表的元素。

归并排序的运行机制如下:
将列表从中间切开,分成两个列表[1.0, 3.1]与[2.5, 5.6, 0.7](如果为奇数,我们在这里默认切成(n-1)/2和(n+1)/2的长度,反过来也不会有什么影响)。

为了方便表示,我们写作[1.0, 3.1/2.5, 5.6, 0.7]表示我们在“/”的地方切了一次,分成了两份。

对每个切开后的列表再次切开,例如[1.0, 3.1]将变为[1.0]和[3.1](注意,[1.0]并不是1.0,前者是含一个元素的列表,后者是一个数字)。

像这样,每次一切为二,在经过三次切割后可得[1.0/3.1/2.5/5.6/0.7]。

这是归并排序的第一步,分开。对于长度为n(含n个元素)的列表,需要花费的时间为lg(n),其中lg为以2为底的log(不知道什么是log?请自行学习对数)。

分久必合,下一步是合。

在最后一次切割结束后,对于每一轮切割过后的两半,将这两半合起来,以一个保证其从小到大排列的方式。

什么意思?我们还是看刚才的例子。

在最后一轮中,[5.6, 0.7]被拆分为[5.6],[0.7]。现在我们想以从大到小排列的顺序来合并这两个数,方法很简单:比较一次5.6,0.7的大小。0.7小,所以0.7排前面,5.6排后面,两个列表合并为[0.7,5.6]。

在倒数第二轮(也就是第二轮)中,[2.5]和[5.6, 0.7]被拆分开来。因为我们已经将[5.6, 0.7]在拆分后有序组合,使其变为[0.7, 5.6],我们需要让2.5先和[0.7, 5.6]中的第一个数0.7比,比0.7大之后再和5.6比。比5.6小,则排5.6前面,变为[0.7, 2.5, 5.6]。

同理,[1.0, 3.1]和[0.7, 2.5, 5.6]比。1.0大于0.7小于2.5,则排在两者之间。3.1因为在1.0后,而0.7小于1.0,所以3.1必定大于0.7,从2.5开始比。比2.5大,比5.6小,所以排两者之间。

列表被排序完成。

被排序的列表带来了秩序。秩序的作用会在下文中提到,在其原理之后,在具体实现之前,但是我们可以先听听Disorder,感受一下无序是多么痛苦的一件事吧。

无标题无名氏No.60460670

2023-12-08(五)01:05:59 ID: 22b93o1 (PO主)

>>No.60460658
为了普适性的意思是我不只用整数。但实际上,因为和数字有关的操作只有比较大小,用整数和浮点数(就是小数)是一样的