14天阅读挑战赛
*努力是为了不平庸~
系列文章目录
第一章 算法简介
第二章 贪心算法
百度百科中,算法(Algorithm) 的定义是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。讲人话呢就是指 解决问题的过程(步骤、方案)。算法规定了解决某个问题的具体步骤,先做什么、再做什么、最后做什么,只要依次完成这些步骤,问题就可以得到解决。广义上讲,算法在我们生活上、课题研究中等各方面都有应用。例如,早上起床,在煮饭时人不是非要盯着它的,我们去洗漱,这种对时间的安排利用也可以说是一种算法的体现,有点 “多线程” 或说 “并行” 的意思。还有课题研究中,通过算法改进研究课题的方法,提高效率等等。
狭义上讲,算法就是在编程中的概念。一般认为数据结构+算法=程序,数据结构是程序的框架,算法是程序的灵魂。讲人话就是,数据结构就是形如:结构体、队列这种,算法就是对其操作的方法,最终目的是完成程序的编写。这也是本系列文章的研究对象,当然这些思路对广义上的研究也是很有用处的。
1.引子
写一个算法求下列序列之和
−
1
,
1
−
1
,
1
…
,
(
−
1
)
-1,1-1,1…,(-1 )
−1,1−1,1…,(−1)?
当看到这个题目时,你会怎么想,for 循环?还是 while 循环?
我们看算法 1-1
// 算法1-1
int sum1(int n){
int sum=0;
for(int i=1;i<=n;i++)
sum+=pow(-1,i);//表示(-1)^i
return sum;
}
这段代码可以实现求和运算,但是为什么不这样算?
−
1
,
1
−
>
0
,
−
1
,
1
−
>
0
,
…
(
−
1
)
n
-1,1 -> 0 ,-1,1-> 0,…(-1)n
−1,1−>0,−1,1−>0,…(−1)n
再看算法1-2
// 算法1-2
int sum2(int n){
int sum=0;
if(n%2==0)
sum=0;
else
sum=-1;
return sum;
}
可以看出,算法 1-1 需要运行 n + 1 n + 1 n+1次,如果 n = 10000 n = 10000 n=10000,那么就要运行 10001 10001 10001次 ,而算法 1-2 仅需运行 1 1 1次!差别可见一斑。算法是对特定问题求解步骡的一种描述。1-1是算法,1-2也是算法,只不过它们组织的方式不一样,其效率也不一样,那么应具有什么特性才能称作为算法?怎么定性并定量地去衡量算法的好坏呢?
2.算法的特性
有穷性:算法是由若干条指令组成的有穷序列,总是执行若干次后结束,不可能不可能永远不停止
确定性:每条与句都有确定的含义,无歧义
可行性:算法在当前可行条件下可以通过有限次数运算来实现
输入、输出:有零个或多个输入以及一个或多个输出
3.好算法的要求
正确性:正确性是指算法能满足具体问题的需求,程序正常运行,无语法错误,能过通过典型的软 件测试,达到预期
易读性:算法遵循标识符命名规则,简洁易懂,方便自己和他人阅读,便于后期调试和修改。
健壮性:算法对非法数据及操作有较好的反应和处理。例如:在学生信息管理系统中登记年龄时,若21岁误输为210岁,则系统应有错误提示
高效性:高效性是指算法运行效率高,即算法运行消耗的时间短。
低存储性:低存储性是指算法所需的存储空间小。对于像手机、平板电脑这样的嵌入式设备,算法如果空间过大,则无法运行,算法占用空间大小被称为“高效率、低存储”
4.定量分析:算法复杂度
算法复杂度分量种:时间复杂度和空间复杂度
衡量不同算法的优劣,主要还是根据算法所占的空间和时间两个维度去考虑。但是,世界上不会存在完美的代码,既不消耗最多的时间,也不占用最多的空间,鱼和熊掌不可得兼,那么我们就需要从中去寻找一个平衡点,使得写出一份较为完美的代码。
4.1时间复杂度
时间复杂度:算法运行需要的时间
算法的时间复杂度就是算法运行所需的时间。现代计算机一秒能计算数 10亿次,所以不能用秒来计算算法消耗时间。由于相同配置的计算机进行一次基本运算的时间是一定的,可以用算法基本运行的执行次数来衡量算法的效率,因此我们将算法基本运算的执行次数作为时间复杂度的衡量标准
观察算法1-3并分析算法的时间复杂度。
//r算法1-3
int sum=0;//运行1次
int total=0;//运行1次
for(int i=1;i<=n;i++)i{//运行n+1次。最后一次判断不满足循环条件
sum=sum+i;//运行n次
for(j=1;j<=n;j++){//运行n×(n+1)次
total=total+i*j;//运行n×n次
把算法1-3中所有语句的运行次数加起来:
1
+
1
+
+
1
+
n
+
n
×
(
n
+
1
)
+
n
×
n
1+1++1+n+n×(n+1)+n×n
1+1++1+n+n×(n+1)+n×n。这可以用一个函数
T
(
n
)
T(n)
T(n)来表达:
T
(
n
)
=
2
n
2
+
3
n
+
3
T(n) =2n^2+3n+3
T(n)=2n2+3n+3
当
n
n
n足够大时,例如
n
=
105
,
T
n
)
=
2
×
1
0
1
0
+
3
×
1
0
5
+
3
n=105,Tn)=2×10^10+3×10^5+3
n=105,Tn)=2×1010+3×105+3。可以看出,算法的运行时间主要取决于最高项,小项和常数可以忽略不计。故算法1-3的时间复杂度为
O
(
N
2
)
O(N^2)
O(N2)。
注意:并不是所有算法都能直接计算运行次数。如下例:
//算法1-4
int findx(int x){//在a[n]数组中顺序查找x
for(int i=o;i<n;i++){
if(a[ i]==x)
return i; //查找成功,返回其下标i
}
return -1;//查找失败,返回-1
}
对于算法1-4中的程序,我们很难计算到底执行了多少次,因为运行次数依赖于
x
x
x在数组中的位置。如果第一个元素就是
x
x
x,则执行
1
1
1次(最好情况)﹔如果最后一个元素是
x
x
x,则执行
n
n
n次(最坏情况)﹔如果分布概率均等,则平均运行次数为
(
n
+
1
)
/
2
(n+1)/2
(n+1)/2。
有些算法,如排序、查找、插入算法等,可以分为最好、最坏和平均情况分别求算法渐近复杂度。但考查一个算法时通常考查最坏的情况,而不是考查最好的情况,最坏情况对衡量算法的好坏具有实际意义。
4.2空间复杂度
空间复杂度:算法占用的空间大小。
空间复杂度的本意是指算法在运行过程中占用了多少存储空间。算法占用的存储空间包括:
(1)输入/输出数据;
(2)算法本身;
(3)额外需要的辅助空间。
输入/输出数据占用的空间是必需的,算法本身占用的空间可以通过精简算法来缩减,但缩减的量是很小的,可以忽略不计。算法在运行时所使用的辅助变量占用的空间(即辅助空间)才是衡量算法空间复杂度的关键因素。
5.算法种类
算法作为一门学问,有两条几乎平行的线索。一条是数据结构(数据对象)︰数、矩阵、集合、串、排列、图、表达式、分布等。另一条是算法策略:贪心策略、分治策略、动态规划策略、线性规划策略、搜索策略等。这两条线索是相互独立的:对于同一个数据对象上不同的问题(如单源最短路径和多源最短路径),就会用到不同的算法策略(如贪心策略和动态规划策略)﹔而对于完全不同的数据对象上的问题(如排序和整数乘法),也许就会用到相同的算法策略(如分治策略)。
两条线索交织在一起,该如何表述呢?我们早已习惯在一章中完全讲排序,而在另一章中完全讲图论。还没有哪一本算法书能够很好地解决这两个困难,传统的算法书大多注重内容的收录,却忽视思维过程的展示,因此我们虽然学习了经典的算法,却费解于算法设计的过程。
本书从问题出发,根据实际问题分析、设计合适的算法策略,然后在数据结构上操作实现,巧妙地将数据结构和算法策略拧成一条线。全书通过大量实例,充分展现算法设计的思维过程,让读者充分体会求解问题的思路、如何分析、使用什么算法策略、采用什么数据结构、算法的复杂性如何、是否有优化的可能等等。这里,我们培养的是让读者怀着一颗好奇心去思考问题、解决问题,更重要的是——体会学习的乐趣,发现算法的美!
总结
算法没有那么神秘~