序章 算法的基本知识
0-1 什么是算法
算法就是计算或者解决问题的步骤。
算法和程序的区别在于:程序是以计算机能够理解的编程语言编写而成的,可以在计算机上运行,而算法是以人类能够理解的方式描述的,用于编写程序之前。就算使用同一个算法,编程语言不同,写出来的程序也不同;即便使用相同的编程语言,写程序的人不同,那么写出来的程序也是不同的。
0-1-1 算法示例-选择排序
排列整数的算法:排序 -> 查找最小的数字并交换:选择排序
输入:随意排列的整数数列。
输出:按从小到大的顺序重新排列。
要求:算法是可以应对任意输入的计算步骤,所以必须采用通用的描述。
步骤:
1、先从输入的数字中找出最小的数字,再将它和最左边的数字交换位置,之后该数字的位置便固定下来不再移动。
2、接下来在剩下的数字里继续寻找最小数,再将它和左边第2个数字交换位置。我们将这样的一次交换称为“1轮”。到了第k轮的时候,就把剩下的数字中最小的一个,与左边开始第k个数字进行交换。于是在结束第k轮后,从左数的k个数字便都按从小到大的顺序排列了。
3、只要将上述步骤重复n次,那么所有的数字都将按从小到大的顺序排列。
0-1-2 选择排序算法的效率
首先,为了在第1轮找到最小的数字,需要从左往右确认数列中的数字,只要查询n个数字即可。在接下来的第2轮中,需要从n-1个数字中寻找最小值,所以需要查询n-1个数字。将这个步骤进行到第n轮的时候,需要查询的次数如下。
n
+
(
n
−
1
)
+
(
n
−
2
)
+
.
.
.
3
+
2
+
1
=
n
(
n
+
1
)
2
≤
n
2
n+(n-1)+(n-2)+...3+2+1=\frac{n(n+1)}{2}\le n^2
n+(n−1)+(n−2)+...3+2+1=2n(n+1)≤n2
n=50的时候n2=2500。假设1秒能确认1万亿(=1012)个数字,那么2500÷1012=0.0000000025秒便能得出结果。
0-2 运行时间的计算方法
0-2-1 从理论层面求运行时间
选择排序的步骤如下。
① 从数列中寻找最小值;
② 将最小值和数列最左边的数字进行交换,排序结束。回到①如果数列中有n个数字,那么①中“寻找最小值”的步骤只需确认n个数字即可。我们将“确认1个数字的大小”作为操作的基本单位,需要的时间设为Tc,那么步骤①的运行时间就是n×Tc。接下来,把“对两个数字进行交换”也作为操作的基本单位,需要的时间设为Ts。那么,①和②总共重复n次,每经过“1轮”,需要查找的数字就减少1个,因此总的运行时间如下。
(
n
×
T
c
+
T
s
)
+
(
(
n
−
1
)
×
T
c
+
T
s
)
+
(
(
n
−
2
)
×
T
c
+
T
s
)
+
.
.
.
+
(
2
×
T
c
+
T
s
)
+
(
1
×
T
c
+
T
s
)
=
1
2
T
c
n
(
n
+
1
)
+
n
T
s
=
1
2
T
c
n
2
+
(
1
2
T
c
+
T
s
)
n
\begin{aligned} &(n \times T_c + T_s) + ((n-1) \times T_c + T_s) + ((n-2)\times T_c + T_s) + ... +(2\times T_c + T_s) + (1 \times T_c + T_s) \\ &=\frac{1}{2}T_cn(n+1) + nT_s \\ &=\frac{1}{2}T_cn^2 + (\frac{1}{2}T_c + T_s)n \end{aligned}
(n×Tc+Ts)+((n−1)×Tc+Ts)+((n−2)×Tc+Ts)+...+(2×Tc+Ts)+(1×Tc+Ts)=21Tcn(n+1)+nTs=21Tcn2+(21Tc+Ts)n
Tc和Ts都是基本单位,与输入无关,根据输入变化而变化的只有数列的长度n,n越大,上式中的n2也就越大,其他部分就相对变小了。也就是说,对式子影响最大的是n2。所以可以删掉其他部分,将结果表示成下式右边的形式。(此处可以用多项式的一个重要性质来理解,当x很大时,首项决定一切,常用于求极限问题)
1
2
T
c
n
2
+
(
1
2
T
c
+
T
s
)
n
=
O
n
2
\frac{1}{2}T_cn^2 + (\frac{1}{2}T_c + T_s)n=On^2
21Tcn2+(21Tc+Ts)n=On2
通过这种表示方法,我们能大致了解排序算法的运行时间与输入数据量n的平方成正比。
假设某个算法的运行时间如下:
5
T
x
n
3
+
12
T
y
n
2
+
3
T
z
n
5T_xn^3+12T_yn^2+3T_zn
5Txn3+12Tyn2+3Tzn
那么,这个结果就可以用O(n3)来表示。
如果运行时间为
3
n
l
o
g
n
+
2
T
y
n
3nlog n+2T_yn
3nlogn+2Tyn
这个结果就可以用O(nlogn)来表示。
O这个符号的意思是“忽略重要项以外的内容”,读音同Order。O(n2)的含义就是“算法的运行时间最长也就是n2的常数倍”。通过这种表示方法,我们可以直观地了解算法的时间复杂度。比如,当我们知道选择排序的时间复杂度为O(n2)、快速排序的时间复杂度为O(nlogn)时,很快就能判断出快速排序的运算更为高速。二者的运行时间根据输入n产生的变化程度也一目了然。