递归

来源:互联网 发布:nginx动静分离检验 编辑:程序博客网 时间:2024/04/27 23:38
 

什么样的问题可以用递归?
其实很多问题都可以用递归解决,例如数列的求和:

#include <iostream>
using namespace std;

template 
<class T>
T    recrusive_sum(T a[], 
int idx)
{
    
if(idx == 0// 退出条件
        return a[0];
    
else
        
return a[idx] + recrusive_sum(a, idx - 1); // 使用内层返回的结果
}

int main(void)
{
    
const int elem_cnt = 100;
    
int a[elem_cnt];
    
for(int i = 0; i < elem_cnt; ++i)
        a[i] 
= i + 1;
    cout 
<< recrusive_sum(a, elem_cnt - 1<< endl;
    
return 0;
}

显然,这不是一个高效的算法,我们通常用率更高的迭代法来解决上面的问题。用这个例子只是想说明,很多问题可以用递归解决。
能用递归解决的问题通常具有两个特点:
1  有退出条件
2  外层需要用到内层算出的结果(也可能是内层需要外层的计算结果,但比较少见)
最难的地方是找出外层利用内层结果的方法,这往往需要在思考问题的过程中发现规律,纸笔是不可缺少的。
另外退出条件需要拿捏准确,这也是一个容易出错的地方。

下面是求全排列和求全部子集的算法,注意以上两点在代码中的体现。

(*) 求全排列
不妨写出一个简单例子,我们用P(a,b,c)表示a,b,c的全排列,
则P(a,b,c)=
a b c
a c b
b a c
b c a
c a b
c b a
我们发现,以上结果按首字母可划分为三组,它们是
a + P(b,c)
b + P(a,c)
c + P(a,b)
其实就是第一个字母轮换,其余两个位置是剩下两个字母的全排列。“剩下两个字母的全排列”正是我们可以利用的内层结果。
代码如下:

#include <iostream>
using namespace std;

template 
<class T>
void    perm(T list[], int begin, int end)
{
    
if(begin == end){
        
for(int i = 0; i <= end; ++i)
            cout 
<< list[i] << '/t';
        cout 
<< endl;
    }
    
else{
        
for(int i = begin; i <= end; ++i){
            swap(list[begin], list[i]);            
            perm(list, begin 
+ 1, end);            
            swap(list[begin], list[i]);
        }
    }
}

int main()
{
    
char a[] = {'1''2''3''4'};
    
int min_idx = 0;
    
int max_idx = sizeof a / sizeof *- 1;
    perm(a, min_idx, max_idx);
    
return 0;
}


(*) 求所有子集

不妨写一个简单的例子,然后从中发现规律。例如,集合{a,b,c}的子集有:
{}
{a}
{b}
{a, b}
{c}
{a, c}
{b, c}
{a, b, c}
耐心分析结果,发现:
{}                                (0)
{a} = {a} + {}                    (a)
{b} = {b} + {}                    (b)
{a, b} = {b} + {} + {a}           (b)
{c} = {c} + {}                    (c)
{a, c} = {c} + {a}                (c)
{b, c} = {c} + {b}                (c)
{a, b, c} = {c} + {a, b}          (c)
其实我们能从上面的分析过程中得到不只一条结论:
1 所有的子集总数是二项展开式系数和C(n,0)+C(n,1)+...+C(n,n)=2^n.这个结论虽然对解决本题没什么帮助,但它应该,也是最容易被注意到的。
2 我们将上面的所有子集分组,发现从最简单的空集开始,新出现的组都是新元素和之前所有组的笛卡尔积。这正是递归利用内层计算结果的地方。代码如下:

#include <iostream>
#include 
<vector>
#include 
<string>
using namespace std;

template 
<class T>
void    subset(vector< vector<T> >& res, const vector<T>& src, int idx);

template 
<class T>
void    show_1d(const vector<T>& vec);

template 
<class T>
void    show_2d(const vector< vector<T> >& vec);

template 
<class T>
void    append_cartesian(vector< vector<T> >& res, T appendant);

int main()
{
    vector
<string>        src;
    vector
< vector<string> >    res;
    
    src.push_back(
"c");
    src.push_back(
"b");
    src.push_back(
"a");

    subset(res, src, 
0);

    show_2d(res);
    
return 0;
}

template 
<class T>
void    subset(vector< vector<T> >& res, const vector<T>& src, int idx)
{
    
if(src.size() == idx){        
        vector
<T> empty_set;
        res.push_back(empty_set);
// append an empty vector when reach base
    }
    
else{
        subset(res, src, idx 
+ 1);
        append_cartesian(res, src[idx]);
//将内层算出的结果笛卡尔积到本层
    }
}

template 
<class T>
void    append_cartesian(vector< vector<T> >& res, T appendant)
{
    
int len = res.size();
    
for(int i = 0; i < len; ++i){
        vector
<T> tmp = res[i];
        tmp.push_back(appendant);
        res.push_back(tmp);
    }
}

template 
<class T>
void    show_1d(const vector<T>& vec)
{
    cout 
<< '{';
    
for(int i = 0; i < vec.size(); ++i){
        cout 
<< vec[i];
        
if(i != vec.size() - 1)
            cout 
<< "";
    }
    cout 
<< '}' << endl;
}

template 
<class T>
void    show_2d(const vector< vector<T> >& vec)
{
    
for(int i = 0; i < vec.size(); ++i)
        show_1d(vec[i]);
}
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 吃了不熟的田螺怎么办 包上的螺丝掉了怎么办 工厂打螺丝手疼怎么办 打螺丝打到手痛怎么办 欧曼gtl不烧尿素怎么办 放油螺丝滑牙怎么办 蝴蝶刀螺丝松了怎么办 婴儿车铆钉松了怎么办 扇子上的铆钉松怎么办 锅的把手松了怎么办 奶锅把手松了怎么办 锅的手柄烧坏了怎么办 鞋子上的铆钉生锈了怎么办 包包上的铆钉生锈了怎么办 凉鞋的铆钉生锈了怎么办 扇子的铆钉坏了怎么办 包包的铆钉坏了怎么办 汽车半轴螺丝母拧不动怎么办? 卫衣袖子短了怎么办 u型导轨蚊帐下垂怎么办 100的水管螺纹出漏水怎么办 吊顶螺丝没有防锈处理怎么办 膨胀螺丝洞松了怎么办 膨胀螺丝眼大了怎么办 墙上螺丝孔大了怎么办 膨胀螺丝孔深了怎么办 克霉膨胀栓的线怎么办 摩托车排气管螺丝断了怎么办 汽车轮胎螺丝卸不下来怎么办 内六角螺丝卸不下来怎么办 洗衣机六角螺丝卸不动怎么办 黄油嘴打不进去怎么办 螺杆冷水机氟系统有空气怎么办 脚踏式加油枪皮碗不下去怎么办? 自攻螺丝滑丝怎么办? 大工打小工老板不管怎么办 虾缸的过滤吸虾怎么办 加热棒坏了鱼怎么办 钢材软打孔断钻头怎么办 空调余额下水管检查口按不上怎么办 风机盘管噪音大怎么办