递归的狂想(菜鸟的胡思乱想)

 

 

 

和很多学习刚学习算法的同学来说,递归是摆在我们面前的一道坎

结合数据结构中的二叉树和图的遍历,逛了逛51cto和csdn还有一些大牛博客,总算能摸着一些头绪了。
 
递归--传递和回归
1:传递
将规模为n的问题,传递为n-1或者n-2 更小也行
   这要求解决A问题依赖于解决小A问题
   也可以是,解决A问题=解决一个小菜问题+解决小A问题
如遍历一颗二叉树,可以是遍历左子树+遍历右子树
如遍历一幅图,打印一个节点,再从它的临节点开始遍历一副少一个结点的图
 
不要以为递归只是执行一次,f(n)不能解决,f(n-1)当然也难以解决。当问题规模不断的缩小,直到n=1or n=2这样规模的问题基本就可以解决了 
举例  f(n)=f(n-1)+f(n-2)     未知
f(5)=f(4)+f(3)     未知
f(4)=f(3)+f(2)已知
f(3)=f(2)已知+f(1)已知
(感谢 Ewarder 提供)
 
2:回归
当问题的规模中出现已知,如上图,就可以将 解 带回
 
总结:引用一张觉得概括性很高的图片

(来自Wiki—

怎样解递归题目
根据题目获取递归表达式(一般采用数学归纳法,即带值慢慢找规律)
 
递归的表达式(表现形式:自己定义自己)
这里用斐波那契的例子来说明
 
f(n)=
  1. 1                       (n=1)   (回归用) 递归终止条件   即当执行f(1) 终止
  2. 2                        ( n=2)    (回归用) 递归终止条件  即当执行f(2)时 终止
  3. f(n-1)+f(n-1)     (n>2)   (传递用)
可以看成是分段函数的编程(if语句就行了)
 
 
递归的作用
分解(依赖传递)Divide
 
 
递归与分治  Recurison <->Divide&Conqur
Ex.1 归并排序(递归)
归并排序(递归)
 1 #include<stdio.h>
 2 
 3 
 4 
 5 void mergesort(int *num,int start,int end);// 声明一个递归函数--Divide  形参为(数组指针,数组头指针,数组尾指针)
 6 
 7 
 8 void merge(int *num,int start,int middle,int end);// 这个函数用来将两个排好序的数组进行合并---Conqur
 9 
10 int main()
11 {
12     // 测试数组
13     int num[10]= {12,54,12,67,86,45,97,32,14,65};
14     int i;
15     // 排序之前
16     printf("Before sorting:\n");
17     for (i=0; i<10; i++)
18     {
19         printf("%3d",num[i]);
20     }
21     printf("\n");
22     // 进行合并排序
23     mergesort(num,0,9);
24     printf("After sorting:\n");
25     // 排序之后
26     for (i=0; i<10; i++)
27     {
28         printf("%3d",num[i]);
29     }
30     printf("\n");
31     return 0;
32 }
33 
34 
35 
36 //这个函数用来将问题细分
37 
38 void mergesort(int *num,int start,int end)
39 {
40     int middle;
41     if(start<end)
42     {
43         middle=(start+end)/2;  //数组中间位置的那个数  (区间上的中点)
44         // 归并的基本思想
45         // 排左边
46         mergesort(num,start,middle);
47         // 排右边
48         mergesort(num,middle+1,end);
49         // 合并
50         merge(num,start,middle,end);
51     }
52 }
53 
54 
55 
56 //这个函数用于将两个已排好序的子序列合并
57 
58 void merge(int *areadysort,int start,int middle,int end)
59 {    int * temparry=new int[end-start+1];  //动态分配内存(注意不能用a[num]的形式
60      int indexA=start;
61      int indexB=middle+1;
62      int I=0;
63      while((indexA<=middle)&&(indexB<=end))   //扫描两个序列
64      {
65          if  (areadysort[indexA]<=areadysort[indexB])
66             
67              temparry[I++]=areadysort[indexA++];
68              
69         else 
70             if(areadysort[indexB]<=areadysort[indexA])
71              temparry[I++]=areadysort[indexB++]; 
72             
73      }
74          while(indexA<=middle)//复制没有比较完子表中的元素
75                      
76             temparry[I++]=areadysort[indexA++];
77          while(indexB<=end)
78              temparry[I++]=areadysort[indexB++];
79 
80          I=0;
81          int tmp = end-start;
82          while(I<=tmp)
83              areadysort[start++]=temparry[I++];  //aready
84           printf("%5d\n",I);
85   
86          
87      }

Ex.2 全排列

全排列
 1 #include <stdio.h>  
 2 
 3 int n = 0;  //全局计数器,全排列的个数
 4 
 5 void swap(int *a, int *b) 
 6 {     
 7     int m;     
 8     m = *a;     
 9     *a = *b;     
10     *b = m; 
11 }  
12 void perm(int list[], int k, int m) //m是数组最大下标,k是当前递归的标记
13 {     
14     int i;     
15     if(k > m)   //当计数器大于最大下标时,
16     {          
17         for(i = 0; i <= m; i++)             
18         printf("%d ", list[i]); //输出的全排列是交换后的临时结果
19         printf("\n");         
20         n++;     
21     }     
22     else     
23     {         
24     for(i = k; i <= m; i++)         
25         {             
26             swap(&list[k], &list[i]); //把选好的元素放到最前面来
27             perm(list, k + 1, m);
28             swap(&list[k], &list[i]); //排列好之后,再换回来,等着下次交换
29         }     
30     } 
31 } 
32 int main() 
33 {     
34     int list[] = {1, 2, 3};     
35     perm(list, 0, 2);     
36     printf("total:%d\n", n);     
37     return 0; 
38 }

 Ex.3 快速排序

快速排序
 1 #include<stdio.h>
 2 #include<iostream.h>
 3 
 4 int count = 0;
 5 
 6 void Swap(int *a,int *b)
 7 {
 8     printf("Swap begin\n");int t;
 9     t = *a;
10     *a = *b;
11     *b =t;
12 }
13 int Partition( int a[],int p,int r)
14 {
15     printf("Partition begin\n");
16     int i = p; //一個指針指向數組頭部
17     int j = r+1; //一個指針指向數組尾部  (+1是為了下面方便操作)
18     int x = a[p];    //设置pivot
19     while(true)
20     {    
21         while(a[++i]<x&&i<r);
22         while(a[--j]>x); //(得益于+1)
23             if(i>=j) break;
24             Swap(&a[i],&a[j]);
25     }
26 a[p]=a[j];
27 a[j]=x;//pivot落到最终位置;
28 return j;
29 }
30 void QuickSort( int a[],int p,int r)
31 { 
32     printf("%d QickSort begin\n", count++);
33     int q ;  //划分位置
34     if(p<r)  //待排数组中 只剩下
35     {    q = Partition(a,p,r);
36         QuickSort(a,p,q-1);
37         QuickSort(a,q+1,r);
38     }
39 }
40 
41 
42 
43 
44 void main()
45 {   int a[]={8,6,3,1,5,6,4,2,7};
46 
47 cout<<"The array before sort:"<<endl;
48 for(int i=0;i<9;i++)
49 printf("%2d",a[i]);
50 printf(" OK \n");
51 
52 QuickSort(a,0,8);
53 printf(" OK\n");
54 
55 cout<<"The array after sort:"<<endl;
56 for(i=0;i<9;i++)
57 printf("%2d",a[i]);
58   printf("\n");
59 }

 

 

 

递归与动态规划 Recurison <->Dinamic Programming

 Ex.2 爬楼梯(DP)

爬楼梯之动态规划
 1 #include<iostream.h>
 2 int table[6];   // 表格,儲存全部問題的答案。 
 3 bool solve[6];  // 紀錄問題是否已經計算完畢 
 4 
 5 int f(int n) 
 6 { 
 7     if (n == 0 || n == 1) 
 8         return 1; 
 9 
10     if (solve[n]) 
11         return table[n]; 
12 
13     table[n] = f(n-1) + f(n-2); // 將答案存入表格 
14     solve[n] = true;            // 已經計算完畢 
15 
16     return table[n]; 
17 } 
18 
19 void main()   //Stair_Climbing  5阶楼梯
20 { 
21     // initial 
22     for (int i=0; i<=5; i++) 
23         solve[i] = false; 
24 
25     // compute 
26     cout << "爬完五階的踏法有" << f(5) << "種\n"; 
27 
28 
29     int n;   //Stair_Climbing   5阶以下楼梯
30 
31     cout<<"请输入:一个五阶以下的楼梯\n";
32     while (cin >> n && (n >= 0 && n <= 5)) 
33     { 
34         cout << "爬完" << n << "階的踏法"
35             << "" << f(n) << "種\n";
36         cout<<"请输入:一个五阶以下的楼梯\n";   //这句必须放在最后,即下一个循环之前
37     } 
38 }

 递归与回溯

Ex1 n皇后迭代回溯

迭代回溯
 1 #include <stdio.h>
 2 #include <iostream.h>
 3 #include <iomanip.h>
 4 #include <math.h>
 5 
 6 class Queen{
 7     friend int nQueen(int);
 8 private:
 9     bool Place(int k);
10     void Backtrack(void);
11     void display();
12     int n, //皇后个数
13         * x;  //当前解        
14     long sum; //当前已找到的可行方案
15 };
16 
17 bool Queen::Place(int k)
18 {
19   for (int j=1;j<k;j++)
20     if ((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))  //不满足隐约束
21            return false;
22     return true;
23 } 
24 
25 void  Queen::Backtrack(void)
26 {  
27     x[1] = 0;
28     int k = 1;
29     while (k>0) {
30         x[k]+=1;  //遍历所有孩子
31         while((x[k]<=n)&&!(Place(k))) x[k]+=1; //对每个孩子进行尝试
32         if (x[k]<=n)  //执行到这一行只有种可能,1。当前行没有可行解 2.找到一个活节点
33             if (k==n){    //已经搜索到第n行(在第n行已经找到一个活节点)
34                 sum++;
35                 display();
36                 cout<<"\n";
37             }
38             else{
39                 k++;    //深度搜素
40                 x[k]=0;  
41             }
42             else k--;  //回溯
43     }
44  }
45 
46 void Queen::display( ){
47     //输出n个皇后在棋盘图形上的位置
48     int i,j;
49     int queenq[100][100];
50     for ( i=1; i<=n; i++)
51         for ( j=1; j<=n; j++)
52             queenq[i][j] =0;  //初始化棋盘图形矩阵
53     for ( i=1; i<=n; i++)
54             if (x[i]) queenq[i][x[i]] =1;  //为棋盘图形矩阵赋值            
55 
56     for( i=1;i<=n;i++){  //输出棋盘图形
57        cout << "(" <<" ";
58        for ( j = 1; j<=n; j++)
59            if(queenq[i][j]) cout << "Q" << "  ";
60            else cout << "*" << "  ";
61        cout << ")" << endl;
62     }
63 }
64 
65 
66 int nQueen(int n)
67 { Queen X;
68   X.n = n;
69   X.sum = 0;
70   int *p = new int [n+1];
71   for (int i = 0; i<=n; i++)
72       p[i] = 0;
73   X.x = p;
74   X.Backtrack();
75   delete [] p;
76   return X.sum;
77 }
78 
79 void main( )
80 { 
81   int n,sum;
82   while(1){
83        cout << "用迭代回溯法解n后问题"<<"\n"<<endl;
84        cout << "请输入皇后的数目(不超过16个):  ";
85        cin >> n;
86        sum = nQueen(n); 
87        cout << "一共有"<<sum<<"种情况"<<endl; 
88        cout<<"\n"<<endl;
89        }
90 }

  n皇后递归回溯

递归回溯
 1 #include <stdio.h>
 2 #include <iostream.h>
 3 #include <iomanip.h>
 4 #include <math.h>
 5 
 6 class Queen{
 7     friend int nQueen(int);
 8 private:
 9     bool Place(int k);
10     void Backtrack(int t);
11     void display();
12     int n, //皇后个数
13         * x;  //当前解        
14     long sum; //当前已找到的可行方案
15 };
16 
17 bool Queen::Place(int k)
18 {
19   for (int j=1;j<k;j++)
20     if ((abs(k-j)==abs(x[j]-x[k]))||(x[j]==x[k]))  //不满足隐约束
21            return false;
22     return true;
23 } 
24 
25 void  Queen::Backtrack(int t)   //搜索解空间中的第t层子树(先序遍历空间树)
26 {  
27     if (t>n) { 
28         sum++;  //到达叶结点,搜索到一个解
29         display();        
30         cout<<'\n';
31     }
32     else
33       for (int i=1;i<=n;i++) {
34         x[t]=i;  //在第
35         if (Place(t)) Backtrack(t+1);
36       }
37  }
38 
39 void Queen::display( ){
40     //输出n个皇后在棋盘图形上的位置
41     int i,j;
42     int queenq[100][100];
43     for ( i=1; i<=n; i++)
44         for ( j=1; j<=n; j++)
45             queenq[i][j] =0;  //初始化棋盘图形矩阵
46     for ( i=1; i<=n; i++)
47             if (x[i]) queenq[i][x[i]] =1;  //为棋盘图形矩阵赋值            
48 
49     for( i=1;i<=n;i++){  //输出棋盘图形
50        cout << "(" <<" ";
51        for ( j = 1; j<=n; j++)
52            if(queenq[i][j]) cout << "Q" << "  ";
53            else cout << "*" << "  ";
54        cout << ")" << endl;
55     }
56 }
57 
58 
59 int nQueen(int n)
60 { Queen X;
61   X.n = n;
62   X.sum = 0;
63   int *p = new int [n+1];
64   for (int i = 0; i<=n; i++)
65       p[i] = 0;
66   X.x = p;
67   X.Backtrack(1);
68   delete [] p;
69   return X.sum;
70 }
71 
72 void main( )
73 { 
74   int n,sum;
75   while(1){
76        cout << "用递归回溯法解n后问题"<<"\n"<<endl;
77        cout << "请输入皇后的数目(不超过16个):  ";
78        cin >> n;
79        sum = nQueen(n); 
80        cout << "一共有"<<sum<<"种情况"<<endl; 
81        cout<<"\n"<<endl;
82        }
83 }

 

 

posted @ 2012-12-11 06:08  #Saxon  阅读(322)  评论(3)    收藏  举报