算法设计与分析-第二章


title: 算法设计与分析–第二章
date: 2022-10-04 23:43:18
tags:

  • 算法设计
  • 期末复习

大二下学期课程–算法设计与分析复习第二章

针对老师的ppt精简内容中的知识点,仅具参考

第二章 递归与分支策略

递归的理解
  1. 在计算思维中最重的是一种自顶向下、先全局后局部的逆向思维,他被称为递归。与之相对应的是人类所采用的自底向上、先局部后全局的正向思维称之为递推
  2. 简单来说就是自己调用自己。
递归的分类
  1. 直接递归:自己调用自己
  2. 间接递归: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(n1)n …(2)

式子(1)称为递归边界,式子(2)称为递归体。
即一个递归体由递归边界递归体两部分组成。

  • 实际上递归的思路是把一个不能或者不好直接求解的“大问题转化为一个或者几个“小问题”来解决;
  • 再把“小问题”进一步分解为更小的“小问题”来解决:如此分解,直到“小问题”可以直接求解。
递归算法的设计
  • 先将整个问题划分为若干个子问题,通过分别求解子问题,最后获得整个问题的解。而这些子问题具有与原问题相同的求解方法,于是可以再将它们划分成若干个子问题,分别求解,如此反复进行,直到不能再划分成子问题,或已经可以求解为止。
  • 这种自上而下将问题分解、求解,再自下而上引用、合并,求出最后解答的过程称为递归求解过程。
递归的例子
  • 阶乘

    [外链图片转存中…(img-2V6Fqx24-1696847767891)]

  • 折半查找

    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) ;
    }
    
    • 斐波那契序列

    xlnOhT.png

    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);
          }
      }
      
递归执行过程

递归执行过程中的算法调用与返回的过程

  1. 算法调用
    当在一个算法的运行期间调用另一个算法时,在运行该被调用算法之前,需先完成三项任务:

    • 返回地址、所有实参等信息传递给被调用算法保存:
    • 为被调用算法的局部变量分配存储区
    • 控制转移到被调用算法的入口。
  2. 算法返回
    从被调用算法返回调用算法之前,应该完成下列三项任务:

    • 保存被调算法的计算结果
    • 释放被调算法保存局部变量的数据区;
    • 依照被调算法保存的返回地址控制转移到调用算法。
分治的基本思想
  1. 首先,它将一个复杂的问题分成若干个简单的子问题并进行解决,这一步被称为分割(divide)
  2. 然后解决每一个子问题,这一部被称为征服或解决(conquer),也就是分治这个词中“治”的来源。在这一步中,如果子问题非常简单,就直接解决了。如果子问题依然很大,那么还需要递归调用分治算法,把子问题分成更小一级的问题来解决,直到那些被分出的子问题能够直接解决为止。
  3. 最后对子问题的结果进行合并(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中

一个例子:

xl5aaF.png

xl50PJ.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值