微信扫一扫打赏支持

搜索分析(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 } 
阶乘的栈实现

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

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

posted @ 2017-09-02 21:47  范仁义  阅读(1558)  评论(0编辑  收藏  举报