• 搜索分析(DFS、BFS、递归、记忆化搜索)


    搜索分析(DFS、BFS、递归、记忆化搜索)

    1、线性查找

    在数组a[]={0,1,2,3,4,5,6,7,8,9,10}中查找1这个元素。

    (1)普通搜索方法,一个循环从0到10搜索,这里略。

    (2)递归(从中间向两边)

     1 //递归一定要写成记忆化递归 
     2 #include <bits/stdc++.h>
     3 using namespace std;
     4 bool vis[11];
     5 int count1=0;
     6 
     7 void search(int n){
     8     count1++;
     9     if(n>10||n<0||vis[n]){
    10         //cout<<"back"<<endl;
    11     }
    12     else if(n==1){
    13         vis[n]=true;
    14         cout<<"find"<<endl;
    15     } 
    16     else {
    17         vis[n]=true;
    18         search(n-1);
    19         search(n+1);
    20         
    21     }
    22 }
    23 
    24 int main(){
    25     int a[]={0,1,2,3,4,5,6,7,8,9,10};
    26     search(9);
    27     cout<<count1<<endl;
    28     return 0;
    29 
    30 } 
    递归(从中间到两边)

    这种方法一定要加标记数组,不然会出现死循环。

    其中一个死循环:

    search(9)->search(8)->search(9)

    而这样的死循环太多了。

    其实分析的时候直接把递归的树形图画出来就好了,直观而且方便。

    这样带有标记数组的递归,本质上就是记忆化递归。

    所以这种环形的递归都可以写成记忆化递归。

    (3)递归(从后面向前面)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int count1=0;
     5 
     6 void search(int n){
     7     count1++;
     8     if(n>10||n<0){
     9     }
    10     else if(n==1){
    11         cout<<"find"<<endl;
    12     } 
    13     else {
    14         search(n-1);        
    15     }
    16 }
    17 
    18 int main(){
    19     int a[]={0,1,2,3,4,5,6,7,8,9,10};
    20     search(10);
    21     cout<<count1<<endl;
    22     return 0;
    23 
    24 } 
    递归(从后面向前面)

    这种方法是不需要标记数组的,因为递归是线性的,而不是环形的,递归之间没有交叉,不会造成重复访问。

    这种和求阶乘的是一样的。

    (4)BFS(从中间向两边)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 bool vis[11];
     4 int count1=0;
     5 queue<int> que;
     6 
     7 void searchBFS(int n){
     8     que.push(n);
     9     while(!que.empty()){
    10         count1++;
    11         cout<<"count1:"<<count1<<endl;
    12         
    13         int tmp=que.front();
    14         que.pop();
    15         vis[tmp]=true; 
    16         cout<<"tmp:"<<tmp<<endl;
    17         if(tmp==1) {
    18             cout<<"find"<<endl;
    19             return ;
    20         }
    21         else{
    22             if(tmp-1>=0&&!vis[tmp-1]) que.push(tmp-1);
    23             if(tmp+1<=10&&!vis[tmp+1]) que.push(tmp+1); 
    24         }
    25     }
    26 }
    27 
    28 int main(){
    29     int a[]={0,1,2,3,4,5,6,7,8,9,10};
    30     searchBFS(9);
    31     cout<<count1<<endl;
    32     return 0;
    33 
    34 } 
    BFS(从中间向两边)

    这种BFS也是一定要带标记数组的,所以也可以写成记忆化。

    这种BFS如果不带标记数组的话,也是可以得到正确答案的,不过会重复算很多算过的东西。

    例如:9 8 10 7 9 9 6 8 8 10 8 10 .........

    比如说上面的9就访问了很多次,而由于队列FIFO的特性,所以虽然重复算很多次,还是会得到正确答案。

    因为7、6那一支会逐渐到1的。

    当然,BFS也可以直接写成线性的,这样也是不需要标记数组的。

    其实还是那样,把情况的树形图画出来就很舒服了,直观方便。

    二、阶乘

    (1)普通求阶乘方法:略。

    (2)阶乘的递归实现DFS

    阶乘的递归实现
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int jiechen(int n){
     4     if(n==1) return 1;
     5     else{
     6         return n*jiechen(n-1);
     7     }
     8 }
     9 int main(){
    10     cout<<jiechen(8)<<endl;
    11     return 0;
    12 } 
    DFS

    从尾直接算到头,不需要标记数组

    (2)阶乘的栈实现

     1 /*
     2 伪码:
     3 我们求f(n),f(n)入栈
     4 在栈不空的情况下(下面循环)
     5 出栈 
     6 f(n)=f(n-1)*n
     7 如果f(n-1)没有被求出来,直接入栈 
     8 */
     9 
    10 //对数组而言,我们操作的肯定是下标,而一定不是数组元素的值 
    11 #include <bits/stdc++.h>
    12 using namespace std;
    13 stack<int> sta; 
    14 int a[15];
    15 
    16 int jiechen(int n){
    17     a[1]=1;
    18     sta.push(n);
    19     while(!sta.empty()){
    20         int tmp=sta.top();
    21         sta.pop();
    22         //如果a[tmp-1]被计算了 
    23         if(a[tmp-1]!=0){
    24             a[tmp]=a[tmp-1]*tmp;
    25             cout<<tmp<<" "<<a[tmp]<<endl;
    26         } 
    27         else{
    28             sta.push(tmp);
    29             sta.push(tmp-1);
    30         } 
    31     }
    32     return a[8];
    33 }
    34 
    35 int main(){
    36     cout<<jiechen(8)<<endl;
    37     return 0;
    38 } 
    阶乘的栈实现

    对数组而言,我们操作(存储进栈或者队列或者其它操作)的肯定是下标,而一定不是数组元素的值 

    其实栈实现和递归实现是一样的,因为递归在计算机内部就是用栈实现的。

  • 相关阅读:
    Linux vi/vim
    Linux 磁盘管理
    Linux 用户和用户组管理
    Linux 文件与目录管理
    Linux 文件基本属性
    Linux 远程登录
    Linux 忘记密码解决方法
    Linux 系统目录结构
    Linux 系统启动过程
    linux -- su和sudo命令的区别
  • 原文地址:https://www.cnblogs.com/Renyi-Fan/p/7468022.html
Copyright © 2020-2023  润新知