算法复习资料总结最终版.docx
- 文档编号:30264590
- 上传时间:2023-08-13
- 格式:DOCX
- 页数:37
- 大小:64.39KB
算法复习资料总结最终版.docx
《算法复习资料总结最终版.docx》由会员分享,可在线阅读,更多相关《算法复习资料总结最终版.docx(37页珍藏版)》请在冰豆网上搜索。
算法复习资料总结最终版
笔试部分
1.简答题(40分)
1.算法的基本概念、性质及其与程序的联系与区别
算法:
是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令。
算法性质:
输入---有零个或者多个外部量作为算法的输入;
输出---算法产生至少一个量最为输出;
确定性:
组成算法的每条指令是清晰的、无歧义的;
有限性:
算法中指令的执行次数有限和执行的时间有限。
程序:
是算法用某种设计语言的具体实现,程序可以不满足算法的有限性。
2.大O表示法的含义和渐进时间复杂度(要会计算复杂度)
大O表示法:
称一个函数g(n)是O(f(n)),当且仅当存在常数c>0和n0>=1,对一切n>n0均有|g(n)|<=c|f(n)|成立,也称函数g(n)以f(n)为界或者称g(n)囿于f(n)。
记作g(n)=O(f(n))。
定义:
如果一个问题的规模是n,解这一问题的某一算法所需要的时间为T(n),它是n的某一函数。
T(n)称为这一算法的“时间复杂度”。
当输入量n逐渐加大时,时间复杂度的极限情形称为算法的“渐近时间复杂度”。
3.分治法的基本思想是什么
分治法的基本思想是:
将一个规模为n的问题分解为k个规模较小的子问题,这些子问题互相独立且与原问题相同。
递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
4.回溯算法的基本思想及其一般模式(子集树+排列树)
基本思想:
在包含问题的所有解的解空间树中,按照深度优先搜索的策略,从根结点出发深度探索解空间树。
当探索到某一结点时,要先判断该结点是否包含问题的解,如果包含,就从该结点出发继续探索下去,如果该结点不包含问题的解,则逐层向其祖先结点回溯。
若用回溯法求问题的所有解时,要回溯到根,且根结点的所有可行的子树都要已被搜索遍才结束。
而若使用回溯法求任一个解时,只要搜索到问题的一个解就可以结束。
搜索子集树的一般模式:
voidsearch(intm)
{
if(m>n)//递归结束条件
output();//相应的处理(输出结果)
else
{
a[m]=0;//设置状态:
0表示不要该物品
search(m+1);//递归搜索:
继续确定下一个物品
a[m]=1;//设置状态:
1表示要该物品
search(m+1);//递归搜索:
继续确定下一个物品
}
}
搜索排列树的一般模式:
voidsearch(intm)
{
if(m>n)//递归结束条件
output();//相应的处理(输出结果)
else
for(i=m;i<=n;i++)
{
swap(m,i);//交换a[m]和a[i]
if()
if(canplace(m))//如果m处可放置
search(m+1);//搜索下一层
swap(m,i);//交换a[m]和a[i](换回来)
}
}
5.动态规划的基本思想、基本步骤、基本要素是什么
基本思想:
将待求解问题分解成若干子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
基本步骤:
①找出最优解的性质,并刻画其结构特征;
②递归地定义最优值;
③以自底向上的方式计算出最优值;
④根据计算最优值时得到的信息,构造最优解。
基本要素:
最优子结构性质和子问题重叠问题
6.什么是最优子结构性质和子问题重叠性质
最优子结构性质:
如果问题的最优解所包含的子问题的解也是最优的,则称该问题具有最优子结构性质(即满足最优化原理)。
最优子结构性质为动态规划算法解决问题提供了重要线索。
子问题重叠性质:
指在用递归演算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。
动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。
7.分治法与动态规划的联系与区别
联系:
基本思想相同,即将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。
区别:
适用于动态规划法求解的问题,经分解得到的子问题往往不是相互独立的。
分治法子问题被重复计算多次,而动态规划子问题可用一个表来记录已解决子问题的答案,避免了子问题重复计算的问题。
8.动态规划的变形(备忘录方法)与动态规划的联系与区别
联系:
都用表格保存已解决的子问题的答案
区别:
备忘录方法的递归方式是自顶向下的,而动态规划的递归方式是自底向上的。
9.分支限界法(广度优先搜索)的基本思想是什么
分支限界法常以广度优先或以最小耗费(最大效益)优先的方式搜索问题的解空间树。
在分支限界法中,每一个活结点只有一次机会成为扩展节点。
活结点一旦成为扩展节点,就一次性产生所有儿子节点。
在这些儿子节点中,导致不可行解或导致非最优解的儿子节点被舍弃,其余儿子节点被加入活结点表中。
此后,从活结点表中取下一节点成为当前扩展节点,并重复上述节点扩展过程,这个过程一直持续到找到所需的解或活结点表为空时为止。
10.分支限界法与回溯法的区别
1.搜索方式不同:
分支限界法使用广度优先或最小消耗优先搜索,而回溯法使用深度优先搜索。
2.主要区别:
在于它们对当前扩展节点所采用的扩展方式不同。
分支限界法:
每个节点只有一次成为活结点的机会
回溯法:
活结点的所有可行子节点被遍历后才被从栈中弹出
11.搜索算法的一般模式
搜索算法关键要解决好状态判重的问题:
voidsearch()
{
open表初始化为空;
起点加入到open表;
while(open表非空)
{
取open表中的一个结点u;
从open表中删除u;
for(对扩展结点u得到的每个新结点vi)
{
if(vi是目标结点)
输出结果并返回;
If(notused(vi))
vi进入open表;
}
}
}
12.贪心算法的基本思想、基本步骤及基本要素
基本思想:
贪心算法总是做出在当前看来是最好的选择,即贪心算法并不从整体最优上加以考虑,所做的选择只是在某种意义上的局部最优选择,即贪心选择。
基本步骤:
①从问题的某个初始解出发;
②采用循环语句,当可以向求解目标前进一步时,就根据局部最优策略,得到一个局部最优解缩小问题的规模;
③将所有局部最优解综合起来,得到原问题的解。
基本要素:
①贪心选择性质:
指所求问题的整体最优解可以通过一系列的局部最优的选择,即贪心选择来达到。
贪心选择策略必须具备无后效性,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
②最优子结构性质:
一个问题的最优解包含其子问题的最优解。
13.贪心算法与动态规划算法联系与区别
联系:
都要求问题具有最优子结构性质,即一个问题的最优解包含其子问题的最优解。
区别:
①在动态规划算法中,每步所做的选择往往是依赖于相关子问题的解,因而只有在解出相关子问题后,才能做出选择。
而在贪心算法中,仅在当前状态下做出最好的选择,即局部最优选择,然后再去解做出这个选择后产生的相应的子问题。
②动态规划算法通常以自底向上方式解各子问题,而贪心算法则通常以自顶向下的方式进行,以迭代的方式做出相机的贪心选择以简化问题规模。
2.设计题(60分---写出核心代码或伪代码和相关的变量声明)
1.用二分查找算法查找某一个元素在线性表中的位置。
此问题的输入是待查元素x和线性表L,输出为x在L中的位置或者x不在L中的信息。
最直接的做法就是一个一个地扫描L的所有元素,直到找到x为止。
这种方法对于有n个元素的线性表在最坏的情况下需要n次比较。
一般来说,若没有其他的附加信息,在有n个元素的线性表中查找一个元素在最坏情况都需要n次比较。
考虑最简单的情况,该线性表为有序表,设其按照主键的递增顺序从小到大排列。
核心伪代码:
functionBinarySearch(L,a,b,x)
begin
ifa>bthenreturn-1
elsebegin
m=(a+b)div2;
ifx=L[m]thenreturn(m)
elseifx>L[m]
thenreturnBinarySearch(L,m+1,b,x);
else
returnBinarySearch(L,a,m-1,x);
end;
end;
2.请采用快速排序算法为下列数字排序,并写出最终结果(21254925*1608)
快速排序的基本思想:
选定一个基准值元素,对带排序的序列进行分割,分割之后的序列一部分小于基准值元素,另一部分大于基准值元素,再对这两个分割好的子序列进行上述的过程。
voidswap(inta,intb){intt;t=a;a=b;b=t;}
intPartition(int[]arr,intlow,inthigh)
{
intpivot=arr[low];//采用子序列的第一个元素作为基准元素
while(low { //从后往前在后半部分中寻找第一个小于基准元素的元素 while(low { --high; } //将这个比枢纽元素小的元素交换到前半部分 swap(arr[low],arr[high]); //从前往后在前半部分中寻找第一个大于基准元素的元素 while(low { ++low; } //将这个基准元素大的元素交换到后半部分 swap(arr[low],arr[high]); } returnlow;//返回基准元素所在的位置 } voidQuickSort(int[]a,intlow,inthigh) { if(low { intn=Partition(a,low,high); QuickSort(a,low,n); QuickSort(a,n+1,high); } } 3.写出对下面的序列进行归并排序的过程(从小到大)(631499823481570) 核心代码: voidMergeSort(intlow,inthigh) { if(low>=high)//每个子列表中剩下一个元素时停止 return; //将列表划分成相等的两个子列表,若有奇数个元素,则在左边子列表大于右边子列表 else intmid=(low+high)/2; MergeSort(low,mid);//递归划分子列表 MergeSort(mid+1,high);//递归划分子列表 //新建一个数组b用于存放归并的元素 int[]b=newint[high-low+1]; //两个子列表进行排序归并,直到两个子列表中的一个结束 for(inti=low,j=mid+1,k=low;i<=mid&&j<=high;k++) { if(arr[i]<=arr[j]) { b[k]=arr[i]; i++; } else { b[k]=arr[j]; j++; } } for(;j<=high;j++,k++) //如果第二个子列表中仍然有元素,则追加到新列表 b[k]=arr[j]; for(;i<=mid;i++,k++) //如果第一个子列表中仍然有元素,则追加到新列表 b[k]=arr[i]; for(intz=0;z //将排序的数组b的所有元素复制到原始数组arr中 arr[z]=b[z]; } 4.装载问题 问题关键在于: 首先将第一艘船尽可能装满且c1<最大值max,然后将剩余的部分装上第二艘船c2,若: 总重量-c1 关键代码: intc1,c2,n,w[10]; intweight=0,max=0; voidsearch(intm) { if(m==n) { if(weight<=c1) if(weight>max) max=weight; } else { if(weight+=w[m]<=c1) { weight+=w[m]; search(m+1); weight-=w[m] } search(m+1); } } 5.01-背包问题(回溯法) 关键代码: intn,c; intw[1000],v[1000]; inta[1000],max=0; voidsearch(intm) { if(m>=n) checkmax(); else { a[m]=0; search(m+1); a[m]=1; search(m+1) } voidcheckmax() { inti; intweight=0,value=0; for(i=0;i { if(a[i]==1) { weight+=w[i]; value+=v[i]; } } if(weight<=c) if(value>max) max=value; } 6.循环赛日程表(递归与分治) 设计思想: 按分治策略,可以将所有选手对分为两半,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。 递归地用这种一分为二的策略对选手进行分割,直至只剩下两个选手时,比赛日程表的指定就很简单了。 核心代码: intN=1; voidUpRightCopy(intn,intarray[]) { for(inti=0;i { for(intj=n;j<2*n;j++) { array[N*i+j]=2*n+1-array[N*i+2*n-1-j]; } } } voidDownRightCopy(intn,intarray[]) { for(inti=n;i<2*n;i++) { for(intj=n;j<2*n;j++) { array[N*i+j]=array[N*(i-n)+j-n]; } } } voidLeftDownCopy(intn,intarray[]) { for(inti=n;i<2*n;i++) { for(intj=0;j { array[N*i+j]=array[N*(i-n)+j+n]; } } } voidturn(intn,intarray[]) { if(n==1) array[0]=1; else { turn(n/2,array); DownRightCopy(n/2,array); UpRightCopy(n/2,array); LeftDownCopy(n/2,array); } } 7.最长公共子序列 核心代码: chara[201],b[201]; intn1,n2; voidsearch() { intList[201][201]; for(inti=0;i<=n1;i++) List[i][0]=0; for(intj=0;j<=n2;j++) List[0][j]=0; for(inti=0;i<=n1;i++) { for(intj=0;j<=n2;j++) { if(a[i-1]==b[j-1]) List[i][j]=List[i-1][j-1]+1; else { if(List[i-1][j]>List[i][j-1]) List[i][j]=List[i-1][j]; else List[i][j]=List[i][j-1]; } } } 8.矩阵连乘问题 核心代码: intn; intp[11]; voidsearch() { inta[11][11],temp; for(inti=1;i<=n;i++) a[i][i]=0; for(intd=1;d<=n-1;d++) { for(inti;i<=n-d;i++) { intj=i+d; a[i][j]=0+a[i+1][j]+p[i-1]*p[i]*p[j]; for(intk=i+1;k { temp=a[i][k]+a[k+1][j]+p[i-1]*p[k]*p[j];
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 算法 复习资料 总结 最终版