title: 算法设计与分析–第二章
date: 2022-10-04 23:43:18
tags:
- 算法设计
- 期末复习
大二下学期课程–算法设计与分析复习第二章
针对老师的ppt精简内容中的知识点,仅具参考
第二章 递归与分支策略
递归的理解
- 在计算思维中最重的是一种自顶向下、先全局后局部的逆向思维,他被称为递归。与之相对应的是人类所采用的自底向上、先局部后全局的正向思维称之为递推。
- 简单来说就是自己调用自己。
递归的分类
- 直接递归:自己调用自己
- 间接递归:A调用B,B调用A
递归的特点
将问题分解为形式上更简单的子问题来进行求解。
递归算法模型
以前面的斐波那契数列为例:
f
(
1
)
=
1
f(1) = 1
f(1)=1 …(1)
f
(
n
)
=
f
(
n
−
1
)
∗
n
f(n) = f(n-1) * n
f(n)=f(n−1)∗n …(2)
式子(1)称为递归边界,式子(2)称为递归体。
即一个递归体由递归边界与递归体两部分组成。
- 实际上递归的思路是把一个不能或者不好直接求解的“大问题转化为一个或者几个“小问题”来解决;
- 再把“小问题”进一步分解为更小的“小问题”来解决:如此分解,直到“小问题”可以直接求解。
递归算法的设计
- 先将整个问题划分为若干个子问题,通过分别求解子问题,最后获得整个问题的解。而这些子问题具有与原问题相同的求解方法,于是可以再将它们划分成若干个子问题,分别求解,如此反复进行,直到不能再划分成子问题,或已经可以求解为止。
- 这种自上而下将问题分解、求解,再自下而上引用、合并,求出最后解答的过程称为递归求解过程。
递归的例子
-
阶乘
-
折半查找
int bsearch(int b[],int x, int L,int R){ int mid ; if(L > R) return -1 ; mid = (L + R) / 2 ; if(x == b[mid]) return mid ; else if(x < b[mid]) return bsearch(b,x,L,mid - 1) ; else return bsearch(b,x,mid + 1,R) ; }
- 斐波那契序列
long fib(int n){ if(n == 0 || n == 1) return n ; else return fib(n-1)+fib(n-2) ; }
-
汉诺塔问题
void Hanoi(int n,char a,char b,char c){ if(n == 1) cout << "将第" << n << "个盘片从" << a << "移动到" << c << endl ; else { Hanoi(n-1,a,c,b); cout << "将第" << n << "个盘片从" << a << "移动到" << c << endl ; Hanoi(n-1,b,a,c); } }
递归执行过程
递归执行过程中的算法调用与返回的过程
-
算法调用
当在一个算法的运行期间调用另一个算法时,在运行该被调用算法之前,需先完成三项任务:- 将返回地址、所有实参等信息传递给被调用算法保存:
- 为被调用算法的局部变量分配存储区
- 将控制转移到被调用算法的入口。
-
算法返回
从被调用算法返回调用算法之前,应该完成下列三项任务:- 保存被调算法的计算结果;
- 释放被调算法保存局部变量的数据区;
- 依照被调算法保存的返回地址将控制转移到调用算法。
分治的基本思想
- 首先,它将一个复杂的问题分成若干个简单的子问题并进行解决,这一步被称为分割(divide)
- 然后解决每一个子问题,这一部被称为征服或解决(conquer),也就是分治这个词中“治”的来源。在这一步中,如果子问题非常简单,就直接解决了。如果子问题依然很大,那么还需要递归调用分治算法,把子问题分成更小一级的问题来解决,直到那些被分出的子问题能够直接解决为止。
- 最后对子问题的结果进行合并(combine),得到原有问题的解。
分治法的适用条件(选择题)
1)该问题的规模缩小到一定的程度就可以容易地解决;
2)该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质
3)利用该问题分解出的子问题的解可以合并为该问题的解;
4)该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
合并排序
void MergeSort(Type a[], int left, int right) {
if (left<right) {//至少有 2 个元素
int i=(left+right)/2; //取中点
mergeSort(a, left, i);
mergeSort(a, i+1, right);
merge(a, b, left, i, right); //合并到数组 b
copy(a, b, left, right); //复制回数组 a
}
}
最坏时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
辅助空间:O(n)
快速排序
template<class Type>
int RandomizedPartition (Type a[], int p, int r)
{
int i = Random(p,r);
Swap(a[i], a[p]);
return Partition (a, p, r);
}
最坏时间复杂度:O(n2)
平均时间复杂度:O(nlogn)
辅助空间:O(n)或 O(logn)
找第二大
锦标赛算法(伪代码)
FindSecond
输入:n个数的数组L
输出:Second
1.k←-n
2.将k个元素两两一组,分成Lk/2」组
3.每组的2个数比较,找到较大的数
4.将被淘汰的较小的数在淘汰它的数所指向的链表中
做记录
5.ifk为奇数then k←Lk/2+1
6.esek←Lk/2」
7.if k>1 then goto 2
8.mx←最大数
9.Second←max的链表中的最大
时间复杂度:O(n)
算法Select 分治选择算法
目的:寻址数组中第K小的元素
时间复杂度:O(n)
[外链图片转存中…(img-Za0I66wL-1696847767892)]
B和C部分一定是满足B中任何元素大于m※;C中元素小于m※;他们各自分在数组S1和S2中,再将m※与A、C作比较,看将其放到S1还是S2中
一个例子: