1.2 算法和算法评价
1.2.1 算法的基本概念
算法 (Algorithm) 是对特定问题求解步骤的一种描述, 它是指令的有限序列, 其中的每条指令表示一个或多个操作。此外, 一个算法还具有下列五个重要特性:
有穷性。一个算法必须总在执行有穷步之后结束, 且每一步都可在有穷时间内完成。
确定性。算法中每条指令必须有确切的含义, 对于相同的输入只能得出相同的输出。
可行性。算法中描述的操作都可以通过已经实现的基本运算执行有限次来实现。
输入。一个算法有零个或多个输入, 这些输入取自于某个特定的对象的集合。
输出。一个算法有一个或多个输出, 这些输出是与输入有着某种特定关系的量。
通常, 设计一个 “好” 的算法应考虑达到以下目标:
正确性。算法应能够正确地解决求解问题。
可读性。算法应具有良好的可读性, 以帮助人们理解。
健壮性。算法能对输入的非法数据做出反应或处理, 而不会产生莫名其妙的输出。
高效率与低存储量需求。效率是指算法执行的时间, 存储量需求是指算法执行过程中所需要的最大存储空间, 这两者都与问题的规模有关。
1.2.2 算法效率的度量
【命题追踪】 (算法题) 分析时空复杂度 (2010-2013、2015、2016、2018-2021)
算法效率的度量是通过时间复杂度和空间复杂度来描述的。
1. 时间复杂度
【命题追踪】 分析算法的时间复杂度 (2011-2014、2017、2019、2022)
一个语句的频度是指该语句在算法中被重复执行的次数。算法中所有语句的频度之和记为
注:取
式中,
算法的时间复杂度不仅依赖于问题的规模
(1) i = n - 1;
(2) while (i>=0 && (A[i] !=k) )
(3) i--;
(4) return i ;
该算法中语句 3 (基本运算) 的频度不仅与问题规模
① 若 A 中没有与 k 相等的元素,则语句 3 的频度
② 若 A 的最后一个元素等于 k ,则语句 3 的频度
最坏时间复杂度是指在最坏情况下, 算法的时间复杂度。
平均时间复杂度是指所有可能输入实例在等概率出现的情况下, 算法的期望运行时间。
最好时间复杂度是指在最好情况下, 算法的时间复杂度。
一般总是考虑在最坏情况下的时间复杂度, 以保证算法的运行时间不会比它更长。
在分析一个程序的时间复杂性时, 有以下两条规则:
加法规则:
乘法规则:
例如,设
①
a {
b {}
c {}
}
时间复杂度为
②
a {
b {
c {}
}
}
时间复杂度为
常见的渐近时间复杂度为
2. 空间复杂度
算法的空间复杂度
一个程序在执行时除需要存储空间来存放本身所用的指令、常数、变量和输入数据外, 还需要一些对数据进行操作的工作单元和存储一些为实现计算所需信息的辅助空间。若输入数据所占空间只取决于问题本身, 和算法无关, 则只需分析除输入和程序之外的额外空间。例如, 若算法中新建了几个与输入数据规模
算法原地工作是指算法所需的辅助空间为常量,即
1.2.3 本节试题精选
一、单项选择题
01. 一个算法应该是 ( )。
A. 程序 B. 问题求解步骤的描述
C. 要满足五个基本特性 D. A 和 C
02. 某算法的时间复杂度为
A. 问题规模是
C. 执行时间与
03. 若某算法的空间复杂度为
A. 不需要任何辅助空间 B. 所需辅助空间大小与问题规模
C. 不需要任何空间 D. 所需空间大小与问题规模
04. 下列关于时间复杂度的函数中, 时间复杂度最小的是 ( )。
A.
C.
05. 以下算法的时间复杂度为 ( )。
void fun(int n) {
int i = 1;
while(i<=n) {
i = i * 2;
}
}
A.
06. 有以下算法, 其时间复杂度为 ( )。
void fun(int n) {
int i = 0;
while(i*i*i<=n) {
i++;
}
}
A.
07. 程序段如下:
for(i=n-1; i>1; i--)
for(j=1; j<1; j++)
if(A[j] > A[j+1])
A[j] 与 A[j+1] 对换
其中
A.
08. 下列程序段的时间复杂度为
if (n >= 0) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
printf("输入数据大于或等于零\n");
}
else {
for (int j = 0; j < n; j++)
printf("输入数据小于零\n");
}
A.
09. 以下算法中加下画线(m++
)的语句的执行次数为 ( )。
int m = 0, i, j;
for (i = 1; i <= n; i++)
for (j = 1; j <= 2 * i; j++)
m++;
A.
10. 下列函数代码的时间复杂度是 ( )。
int Func(int n) {
if (n == 1) return 1;
else return 2 * Func(n / 2) + n;
}
A.
11.【2011 统考真题】设
x=2;
while(x<n/2)
x = 2*x;
A.
12.【2012 统考真题】求整数
int fact(int n) {
if (n == 1) return 1;
else return 2 * fact(n - 1);
}
A.
13.【2014 统考真题】下列程序段的时间复杂度是 ( )。
for (int k = 0; k < n; k *= 2)
{
for (int j = 1; j <= n; j++)
{
count++;
}
}
A.
14.【2017 统考真题】下列函数的时间复杂度是 ( )
int func(int n)
{
int i = 0, sum = 0;
while (sum < n)
{
sum += ++i;
return i;
}
}
A.
15.【2019 统考真题】设
x=0;
while(n >= (x+1) * (x+1))
x=x+1;
A.
16. 【2022 统考真题】下列程序段的时间复杂度是 ( )。
int sum = 0;
for (int i = 1; i < n; i *= 2)
for (int j = 0; j < i; j++)
sum++;
A.
二、综合应用题
01. 分析以下各程序段, 求出算法的时间复杂度。
①:
int i = 1;
int k = 0;
while (i < n - 1)
{
k = k + 10 * i;
i++;
}
②:
int y = 0;
while ((y + 1) * (y + 1) <= n)
y = y + 1;
③
for(i=0;i<n;i++)
for(i=0;j<m;j++)
a[i][j]=0;
1.2.4 答案与解析
一、单项选择题
01. B
本题是中山大学往年真题, 题目没有问题, 考查的是算法的定义。程序不一定满足有穷性, 如死循环、操作系统等, 而算法必须有穷。算法代表对问题求解步骤的描述, 而程序则是算法在计算机上的特定实现。不少读者认为 C 也对,它只是算法的必要条件,不能成为算法的定义。
02. C
时间复杂度为
03. B
算法的空间复杂度为
04. D
05 . D
找出基本运算
更直观的方法: 计算基本运算
06. C
基本运算为 i++
,设执行次数为
07. D
这是冒泡排序的算法代码, 考查最坏情况下的元素交换次数 (若觉得理解困难, 则可在学完第 8 章后再回顾)。当所有相邻元素都为逆序时, 则最后一行的语句每次都会执行。此时,
所以在最坏情况下该语句的频度是
08. A
当程序段中有条件判断语句时, 取分支路径上的最大时间复杂度。
09. Am++
语句的执行次数为
10. C
本题求的是递归调用的时间复杂度, 递归调用可视为多重循环, 每次递归执行的基本语句是 if(n == 1) return 1
;,因此可认为单层循环的执行次数为 1,设递归次数为
循环变量i | 单层循环 | 单层循环执行次数 |
---|---|---|
n | if(n==1) return 1; | 1 |
n/2 | if(n==1) return 1; | 1 |
n/4 | if(n==1) return 1; | 1 |
... | ... | ... |
1 | if(n==1) return 1; | 1 |
11. A
基本运算 (执行频率最高的语句) 为
12. B
本题求的是递归调用的时间复杂度, 递归调用可视为多重循环, 每次递归执行的基本语句是 if(n < 1) return 1
;,因此可认为单层循环的执行次数为 1,共执行了
循环变量i | 单层循环语句 | 单层循环执行次数 |
---|---|---|
n | if(n<=1) return 1; | 1 |
n-1 | if(n<=1) return 1; | 1 |
n-2 | if(n<=1) return 1; | 1 |
... | ... | ... |
1 | if(n<=1) return 1; | 1 |
13. C
对于单层循环如 for(j=1;j<=n;j++) sum++;
可以直接数出执行次数为
循环变量k | 单层循环语句 | 单层循环执行次数 |
---|---|---|
1 | for(j=1;j<=n;j++) | n |
for(j=1;j<=n;j++) | n | |
for(j=1;j<=n;j++) | n | |
... | ... | ... |
for(j=1;j<=n;j++) | n |
进入外层循环的条件是
14. B
基本运算为 sum+=++i
,等价于 ++i; sum=sum+i
,每执行一次, i
都自增 1 。当 i = 1
时,sum = 0+1
; 当 i = 2
时, sum = 0+1+2
; 当 i = 2
时, sum = 0+1+2+3
,以此类推,得出 sum=0+1+2+3+...+i=(1+i)×i/2
,可知循环次数
【注 意】统考真题中常将
书写为 ,此时默认底数为 2 。
15 . B
假设第
16 . B
对于单层循环如 for(j=0;j<=i;j++) sum++;
,可以直接数出执行次数为
循环变量k | 单层循环语句 | 单层循环执行次数 |
---|---|---|
1 | for(j=0;j<=1;j++) | 1 |
for(j=0;j<=2;j++) | 2 | |
for(j=0;j<=4;j++) | 4 | |
... | ... | ... |
for(j=0;j<= |
进入外层循环的条件是 i < n
,当循环结束时,循环变量的幂次
二、综合应用题
01 .【解答】
① 基本语句
② 设循环体共执行
③ 内循环执行