算法的基本知识
什么是算法?
算法就是计算或者解决问题的步骤。我们可以把它想象成食谱。要想做出特定的料理,就要遵循食谱上的步骤;同理,要想用计算机解决特定的问题,就要遵循算法。这里所说的特定问题多种多样,比如“将随意排列的数字按从小到大的顺序重新排列”“寻找出发点到目的地的最短路径”,等等。食谱和算法之间最大的区别就在于算法是严密的。食谱上经常会有描述得比较模糊的部分,而算法的步骤都是用数学方式来描述的,所以十分明确。算法和程序有些相似,区别在于程序是以计算机能够理解的编程语言编写而成的,可以在计算机上运行,而算法是以人类能够理解的方式描述的,用于编写程序之前。不过,在这个过程中到哪里为止是算法、从哪里开始是程序,并没有明确的界限。就算使用同一个算法,编程语言不同,写出来的程序也不同;即便使用相同的编程语言,写程序的人不同,那么写出来的程序也是不同的。
排列整数的算法:排序
查找最小的数字并交换:选择排序
来看一个具体的算法示例吧。这是一个以随意排列的整数为输入,把它们按从小到大的顺序重新排列的问题。这类排序问题我们将在第 2 章详细讲解。只解决这一个问题很简单,但是算法是可以应对任意输入的计算步骤,所以必须采用通用的描述。虽然在这个示例中输入的整数个数 n 为 8,然而不管 n 多大,算法都必须将问题解决。
我们将这样的一次交换称为“1 轮”。到了第 k 轮的时候,就把剩下的数字中最小的一个,与左边开始第 k 个数字进行交换。于是在结束第 k 轮后,从左数的 k 个数字便都按从小到大的顺序排列了。只要将这个步骤重复 n 次,那么所有的数字都将按从小到大的顺序排列。
这便是我们将在 2-3 节中介绍的选择排序。不管输入的数字是什么、n 有多大,都可以用这个算法解决问题。
用计算机能理解的方式构思解法:算法的设计
计算机擅长高速执行一些基本命令,但无法执行复杂的命令。此处的“基本命令”指的是“做加法”或者“在指定的内存地址上保存数据”等。
如何选择算法
能解决排序问题的算法不止选择排序这一个。那么,当有多个算法都可以解决同一个问题时,我们该如何选择呢?在算法的评判上,考量的标准也各有不同。比如,简单的算法对人来说易于理解,也容易被写成程序,而在运行过程中不需要耗费太多空间资源的算法,就十分适用于内存小的计算机。不过,一般来说我们最为重视的是算法的运行时间,即从输入数据到输出结果这个过程所花费的时间。
运行时间的计算方法?
如何求得运行时间
现实的方法就是在计算机上运行一下程序,测试其实际花费的时间。但是,就算使用同样的算法,花费的时间也会根据所用计算机的不同而产生偏差,十分不便。
如果数列中有 n 个数字,那么①中“寻找最小值”的步骤只需确认 n 个数字即可。这里,将“确认 1 个数字的大小”作为操作的基本单位,需要的时间设为 Tc,那么步骤①的运行时间就是n×Tc。接下来,把“对两个数字进行交换”也作为操作的基本单位,需要的时间设为 Ts。那么,①和②总共重复 n 次,每经过“1 轮”,需要查找的数字就减少 1 个,因此总的运行时间如下。
虽说只剩最后 1 个数字的时候就不需要确认了,但是方便起见还是把对它的确认和交换时间计算在内比较好。
运行时间的表示方法
虽说我们已经求得了运行时间,但其实这个结果还可以简化。Tc 和 Ts 都是基本单位,与输入无关。会根据输入变化而变化的只有数列的长度 n,所以接下来考虑 n 变大的情况。n 越大,上式中的 n2 也就越大,其他部分就相对变小了。也就是说,对式子影响最大的是 n2 。所以,我们删掉其他部分,将结果表示成下式右边的形式。
那么,这个结果就可以用 O(n3) 来表示。如果运行时间为
这个结果就可以用 O(nlogn) 来表示。