计算机算法分析设计复习题

第一章 算法概述
1、算法必须具备的四个性质:
输入: 有零个或多个由外部提供的量作为算法的输入
输出: 算法产生至少一个量作为输出.
确定性: 组成算法的每条指令是清晰的,无歧义的.
有限性: 在执行了有穷步骤后运算终止(程序则可以不满足此条性质,如操作系统,
无限循环)
2、写出算法复杂性的渐近性态的数学表达式:
(能写出上阶函数即可)如:
3、算法的复杂性分为:时间复杂性 需要时间资源的量;空间复杂性 需要的空间资源的量
4、程序所需要的空间
空间空间
空间主要由指令空间
指令空间指令空间
指令空间,
,,
,数据空间
数据空间数据空间
数据空间,
,,
,环境
环境环境
环境栈空间构成
栈空间构成栈空间构成
栈空间构成:
5、会分析程序段的时间复杂度
一次冒泡
A、template
void Bubble(T a[ ], int n)
{// 计算a[0:n-1]中最大的元素通过冒泡移到右边
for( int i =1;iif( a[i]>a[i+1]) swap(a[i], a[i+1]);
}
B、template
void BubbleSort(T a[ ], int n)
{// 计算a[0:n-1]中的n个元素通过冒泡排序
for( int i =n;i>1; i--)
Bubble(a,i);
}
第二章 递归与分治策略 1.
递归的概念(根据递归公式,能写出递归算法) 如:
递归函数如下:
A、int Factorial(int n)
{
if (n==0) return 1;
return n*Factorial(n-1);
}
B、
递归概念:一个直接或间接地调用自身的算法称为递归算法;一个使用函数自身给出定义的
函数称为递归函数
递归缺点:消耗时间空间多 优点:容易实现理解
递归小结
优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算
法、调试程序带来很大方便。

缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算0
0
)!1(
1
!
>
=
?
?
?
?
=
n
n
nn
n 法要多。
2、分治法
分治法分治法
分治法
分治法的基本思想是讲一个规模为N的问题分解成K个规模较小的子问题,这些子问题互
相独立且与原问题相同。递归的解这些子问题,然后将子问题的解合并得到原问题的解。
3、二分搜索
二分搜索二分搜索
二分搜索方法
方法方法
方法的基本算法描述和基本思想
基本思想:
二分搜搜索的基本思想是将N个元素分成个数大致相同的两半,去a【n/2】与x作比较,
如果x=a【n/2】,则找到了x,算法中止。如果小于,则只要在数组的a的左半部继续搜索x;
如果大于,则只要在数组a的右半部继续搜索x

二分搜索算法
template
int BinarySearch( T a[], const T& x, int n)
{//在a[0]<=a[1]<=···<=a[n-1]中搜索x
//如果找到,则返回所在位置,否则返回 –1
int left= ; int right= ;
while( ){
int middle= ;
if(x==a[middle]) return middle;
if(x>a[middle]) left= ;
else right= ;
}
return –1; //未找到x
}
合并排序的具体算法和基本思想:
合并排序算法是用分治法的策略实现对N个元素进行排序的算法。基本思想是:将待排序
元素分成大小大致相同的两个子集,分别对两个子集进行排序,最终将排好序的子集合合并
成所要求的排好序的集合。
合并排序的算法
template
void MergeSort(Type a[ ], int left, int right)
{// A[left:right]是一个全程数组,含有 right-left+1个待排序的元素。
if ( leftint mid = (left+right)/2; //求当前数组的分割点
MergeSort(a,left, mid);
MergeSort(a,mid+1, right);
Merge(a,b,left, mid ,right);
copy(a,b,left,right);
}
}
合并函数
template< class Type >
void Merge( Type a[ ], Type b[ ], int l, int m, int r)
{//合并a[l:m]和a[m+1:r]到b[l:r]
int i=l; j=m+1,
k=l;
while( ( i<=m )&&( j<=r ) )
if( a[ i ]<=a[ j ]) b[ k++ ]=a[ i++ ];
else b[ k++ ]=a[ j++ ];
if( i>m ) for( int q=j; q<=r; q++ )
b[ k++ ]=a[ q ];
else for( int q=I; q<=m; q++)
b[ k++ ]=a[ q ];
}
合并排序时间复杂度






快速排序的具体算法描述及基本思想,能写出一次快速排序的划分过程
快速排序的基本思想:
把原序列分成两个子问题,在被分成的两个子问题以后不再需要归并。
被分成的两个子问题必须满足一子问题中的所有元素都小于或等于另一子问题的任何一个
元素。
按照三个步骤:分解、递归求解、合并。
分解(Divide):以a[p]为基准元素将a[p:r]划分成3段a[p:q-1],a[q]和a[q+1:r],使得a[p:q-1]中任
何一个小于等于a[q],下标q在划分过程中确定。
递归求解(conquer):通过递归调用快速排序算法分别对a[p:q-1]和a[q+1:r]进行排序。
合并(Merge):由于对a[p:q-1]和a[q+1:r]的排序是就地进行的,所以在a[p:q-1]和a[q+1:r]都已
排好序后,不需执行任何计算a[p:r]就已排好序。

快速排序算法:
Template
void QuickSort(Type a[ ], int p,int r)
{
if(pint q=Partition(a,p,r);
QuickSort(a,p,q-1);//对左半段排序
QuickSort(a,q+1,r);//对右半段排


}
}
Partition的过程中,首先要选择一个元素,根据其值划分数组。称该元素为中轴。
选择中轴有许多不同的策略,我们使用最简单的策略,选择第一个元素:s = a[p]。
划分程序过程
template
int Partition(Type a[ ],int p,int r) )
log()(nnOnT=?
?
?>
+
=
=
1)2/(2
1
)(
ncnnT
na
nT {
int i = p ,
j = r+1 ;
Type x = a[p] ;
while( true ) {
while( a[ ++i ]while( a[ - - j ]>x );
if( i>=j ) break;
Swap( a[ i ], a[ j ] );
}
a[ p ] = a[j] ;
a[ j ] = x ;
return j;
}
能写出一次快速排序的划分过程

课本习题教材P39页,2-15
采用分治法,把数组分成n/2组,每组2个数。然后每组的两个数进行一次比较,确定出每
组的最大数和最小数保存在数组MAX[i]和MIN[i]中,这样总共进行了n/2次比较。最后从
MAX[i]中找出最大的数MAX,从MIN[i]中找出最小的数MIN,需要2*(n/2-1)次比较。
MAX和MIN就是原来问题的解。总比较次数为3n/2 – 2次

算法 最坏复杂性 平均复杂性
冒泡排序 n2 n2
插入排序 n2 n2
选择排序 n2 n2
快速排序 n2 n log n
归并排序 n log n n log n

第三章 动态规划

动态规划思想: 将待求解的问题分解成若干个子问题,先求解子问题,并存储子问题的解
而避免计算重复的子问题,再由子问题的解得到原问题的解。
与分治法不同,适合于用动态规划求解的问题,经分解得到的子问题往往不是互相独立的。
若用分治法来求解的问题,则分解得到的子问题数目太多,以至于最后解决原问题消耗的时
间太多。
分治法与动态规划的区别:
都是分解成子问题,由子问题的解得到原问题的解。
分治中子问题相互独立,而动态规划中子问题互相有联系,且存在重复计算,即存在重叠子
问题。

矩阵连乘
当 i = j 时,A[ i : j ]= Ai ,m[ i ][ i ] = 0,i=1,2,···,n。
当 i < j 时m[ i ][ j ]=m[ i ][ k ] + m[ k+1 ][ j ] + pi-1pkpj k∈ { i, i+1, ···, j-1 } 计算矩阵:连乘最优值
void MatrixChain(int p, int n, int * *m, int * *s)
{
for (int i=1; i<=n; i++) m[i][i]= ;//单个矩阵的计算量
for (int r=2; r<=n; r++)//r为每次循环矩阵链的长度
for (int i=1; i<= ; i++){
int j=i+r-1;

m[i][j]= m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;

for (int k=i+1; k


int t= m[i][k]+ m[k+1][j]+ ;
if (t< m[i][j]) {
m[i][j]=t;
s[i][j]=k; }
}
}
}
时间复杂度 :循环体内的计算量为O(1),三重循环的总次数是O(n3),所以,算法的计算
时间上界为O(n3)。

动态规划算法的基本要素:1 最优子结构性质、2 重叠子问题性质
采用的递归方式是自顶向下,动态规划是自低向上。
3、备忘录方法
用一个表格来保存已解决的子问题的答案,用的时候查表即可
初始化为每个子问题的记录存入一个特殊的值,表示并未求解。在求解过程中,查看相应记
录如果是特殊值,表示未求解,否则只要取出该子问题的解答即可。
4、0-1背包问题
设背包问题的子问题的最优值为m( i, j ),即m( i, j)是背包容量为j,可选择物品为i,i+1,···,
n时的最优值。




上述Knapsack算法需要O(nc)计算时间,Traceback构造最优结构需要O(n)的计算时间
缺点: 算法要求每个物品的重量为整数, 当背包容量c很大时,算法需要的计算时间较多。

最优子结构性质:




?
??
?
?
??
?
?
??
?
<
<<
<≤
≤≤
≤+
++
+

≥≥
≥+
++
+?
??
?+
++
++
++
+
=
==
=i
iiiw
jjim
wjvwjimjim
jim
0),1(
}),1(),,1(max{
),(

最优二叉搜索树时间复杂度:













第四章 贪心算法
1、
、、
、贪心算法总是作出在当前看来最好的选择
贪心算法总是作出在当前看来最好的选择贪心算法总是作出在当前看来最好的选择
贪心算法总是作出在当前看来最好的选择。
。。

贪心算法并不从整体最优考虑
贪心算法并不从整体最优考虑贪心算法并不从整体最优考虑
贪心算法并不从整体最优考虑,
,,
,它所作出的选择只是在某种意义上的局部最优选择
它所作出的选择只是在某种意义上的局部最优选择它所作出的选择只是在某种意义上的局部最优选择
它所作出的选择只是在某种意义上的局部最优选择。
。。
。当然
当然当然
当然,
,,

希望贪心算法得到的最终结果也是整体最优的
希望贪心算法得到的最终结果也是整体最优的希望贪心算法得到的最终结果也是整体最优的
希望贪心算法得到的最终结果也是整体最优的。
。。

2、
、、
、哈弗曼编码
哈弗曼编码哈弗曼编码
哈弗曼编码
前缀码
前缀码前缀码
前缀码
对每一个字符规定一个
对每一个字符规定一个对每一个字符规定一


对每一个字符规定一个0,1串作为其代码
串作为其代码串作为其代码
串作为其代码,
,,
,并要求任一字符的代码都不是其它字符代码
并要求任一字符的代码都不是其它字符代码并要求任一字符的代码都不是其它字符代码
并要求任一字符的代码都不是其它字符代码
的前缀
的前缀的前缀
的前缀。
。。
。这种编码称为前缀码
这种编码称为前缀码这种编码称为前缀码
这种编码称为前缀码。
。。

特点
特点特点
特点:
::

1、
、、
、有
有有
有n个叶子结点
个叶子结点个叶子结点
个叶子结点;
;;

2、
、、
、没有度为
没有度为没有度为
没有度为1的结点
的结点的结点
的结点;
;;

3、
、、
、总的结点数为
总的结点数为总的结点数为
总的结点数为 2n-1;
;;

4、
、、
、形态不唯一
形态不唯一形态不唯一
形态不唯一。
。。

算法
算法算法
算法huffmanTree用最小堆实现优先队列
用最小堆实现优先队列用最小堆实现优先队列
用最小堆实现优先队列Q。
。。
。初始化优先队列需要
初始化优先队列需要初始化优先队列需要
初始化优先队列需要O(n)计算时间
计算时间计算时间
计算时间,
,,
,由于最
由于最由于最
由于最
小堆的
小堆的小堆的
小堆的removeMin和
和和
和put运算均需
运算均需运算均需
运算均需O(logn)时间
时间时间
时间,
,,
,n-
--
-1次的合并总共需要
次的合并总共需要次的合并总共需要
次的合并总共需要O(nlogn)计算时
计算时计算时
计算时

间间
间。
。。
。因此
因此因此
因此,
,,
,关于
关于关于
关于n个字符的哈夫曼算法的计算时间为
个字符的哈夫曼算法的计算时间为个字符的哈夫曼算法的计算时间为
个字符的哈夫曼算法的计算时间为O(nlogn)。
。。

第五章
第五章第五章
第五章 回溯法
回溯法回溯法
回溯法
分支限界法与回溯法区别
分支限界法与回溯法区别分支限界法与回溯法区别
分支限界法与回溯法区别:
::


((
(1)
))
)求解目标
求解目标求解目标
求解目标:
::
:回溯法的求解目标是找出解空间树中满足约束条件的所有解
回溯法的求解目标是找出解空间树中满足约束条件的所有解回溯法的求解目标是找出解空间树中满足约束条件的所有解
回溯法的求解目标是找出解空间树中满足约束条件的所有解,
,,
,而分支限界
而分支限界而分支限界
而分支限界
法的求解

目标则是找出满足约束条件的一个解
法的求解目标则是找出满足约束条件的一个解法的求解目标则是找出满足约束条件的一个解
法的求解目标则是找出满足约束条件的一个解,
,,
,或是在满足约束条件的解中找出在某种意
或是在满足约束条件的解中找出在某种意或是在满足约束条件的解中找出在某种意
或是在满足约束条件的解中找出在某种意
义下的最优解
义下的最优解义下的最优解
义下的最优解。
。。


((
(2)
))
)搜索方式的不同
搜索方式的不同搜索方式的不同
搜索方式的不同:
::
:回溯法以深度优先的方式搜索解空间树
回溯法以深度优先的方式搜索解空间树回溯法以深度优先的方式搜索解空间树
回溯法以深度优先的方式搜索解空间树,
,,
,而分支限界法则以广度优
而分支限界法则以广度优而分支限界法则以广度优
而分支限界法则以广度优
先或以最小耗费优先的方式搜索解空间树
先或以最小耗费优先的方式搜索解空间树先或以最小耗费优先的方式搜索解空间树
先或以最小耗费优先的方式搜索解空间树。
。。
。、
、、


回溯法在包含问题的所有解的解空间树中
回溯法在包含问题的所有解的解空间树中回溯法在包含问题的所有解的解空间树中
回溯法在包含问题的所有解的解空间树中,
,,
,按照深度优先的策略
按照深度优先的策略按照深度优先的策略
按照深度优先的策略,
,,
,从根结点出发搜索解空
从根结点出发搜索解空从根结点出发搜索解空
从根结点出发搜索解空
间树
间树间树
间树。
。。

算法搜索至解空间树的任一结点时
算法搜索至解空间树的任一结点时算法搜索至解空间树的任一结点时
算法搜索至解空间树的任一结点时,
,,
,总是先判断该结点是否肯定不包含问题的解
总是先判断该结点是否肯定不包含问题的解总是先判断该结点是否肯定不包含问题的解
总是先判断该结点是否肯定不包含问题的解,
,,
,如果肯
如果肯如果肯
如果肯
定不包含
定不包含定不包含
定不包含,
,,
,则跳过对以该结点为根的子树的系统搜索
则跳过对以该结点为根的子树的系统搜索则跳过对以该结点为根的子树的系统搜索
则跳过对以该结点为根的子树的系统搜索,
,,
,逐层向其祖先结点回溯
逐层向其祖先结点回溯逐层向其祖先结点回溯
逐层向其祖先结点回溯。
。。
。否则进入
否则进入否则进入
否则进入 该子树
该子树该子树
该子树,
,,
,继续按深度优

先的策略进行搜索
继续按深度优先的策略进行搜索继续按深度优先的策略进行搜索
继续按深度优先的策略进行搜索。
。。

用来求问题的所有解时
用来求问题的所有解时用来求问题的所有解时
用来求问题的所有解时,
,,
,要回溯到根
要回溯到根要回溯到根
要回溯到根,
,,
,且根结点的所有子树都已被搜索遍才结束
且根结点的所有子树都已被搜索遍才结束且根结点的所有子树都已被搜索遍才结束
且根结点的所有子树都已被搜索遍才结束。
。。

用来求问题的任一解时
用来求问题的任一解时用来求问题的任一解时
用来求问题的任一解时,
,,
,只要搜索到问题的一个解就可结束
只要搜索到问题的一个解就可结束只要搜索到问题的一个解就可结束
只要搜索到问题的一个解就可结束。
。。

回溯法适用于解一些组合数较大的问题
回溯法适用于解一些组合数较大的问题回溯法适用于解一些组合数较大的问题
回溯法适用于解一些组合数较大的问题。
。。

回溯法基本思想
回溯法基本思想回溯法基本思想
回溯法基本思想:
::

从开始结点
从开始结点从开始结点
从开始结点(
((
(根结点
根结点根结点
根结点)
))
)出发
出发出发
出发,
,,
,它成为第一个
它成为第一个它成为第一个
它成为第一个活结点
活结点活结点
活结点,
,,
,也成为当前的扩展结点
也成为当前的扩展结点也成为当前的扩展结点
也成为当前的扩展结点。
。。

2 在当前的扩展结点处
在当前的扩展结点处在当前的扩展结点处
在当前的扩展结点处,
,,
,搜索向纵深方向移至一个新结点
搜索向纵深方向移至一个新结点搜索向纵深方向移至一个新结点
搜索向纵深方向移至一个新结点。
。。
。这个结点就成为一个新的活结
这个结点就成为一个新的活结这个结点就成为一个新的活结
这个结点就成为一个新的活结

点点
点,
,,
,并成为当前扩展结点
并成为当前扩展结点并成为当前扩展结点
并成为当前扩展结点。
。。

3 如果在当前的扩展结点处不能再向纵深方向移动
如果在当前的扩展结点处不能再向纵深方向移动如果在当前的扩展结点处不能再向纵深方向移动
如果在当前的扩展结点处不能再向纵深方向移动,
,,
,则当前的扩展结点就成为死结点
则当前的扩展结点就成为死结点则当前的扩展结点就成为死结点
则当前的扩展结点就成为死结点,
,,
,此
此此

时应往回移动

应往回移动时应往回移动
时应往回移动(
((
(回溯
回溯回溯
回溯)
))
)至最近的一个活结点处
至最近的一个活结点处至最近的一个活结点处
至最近的一个活结点处,
,,
,并使这个活结点成为当前的扩展结点
并使这个活结点成为当前的扩展结点并使这个活结点成为当前的扩展结点
并使这个活结点成为当前的扩展结点,
,,
,用
用用

这种方式递归地在解空间中搜索
这种方式递归地在解空间中搜索这种方式递归地在解空间中搜索
这种方式递归地在解空间中搜索,
,,
,直至找到所要求的解或解空间中已无活结点为止
直至找到所要求的解或解空间中已无活结点为止直至找到所要求的解或解空间中已无活结点为止
直至找到所要求的解或解空间中已无活结点为止。
。。

相关文档
最新文档