递归与分治

一、算法思想

递归(Recurrence):计算机、数学、运筹等领域经常使用的最强大的解决问题的方法之一,它用一种简单的方式来解决那些用其他方法解起来可能很复杂的问题,也就是说有些问题用递归算法来求解,则变得简单,而且容易理解。

递归的基本思想:把一个问题划分为一个或多个规模更小的子问题,然后用同样的方法解规模更小的子问题。

递归算法的基本设计步骤

1.找到问题的初始条件(递归出口),即当问题规模小到某个值时,该问题变得很简单,能够直接求解。

2.设计一个策略,用于将一个问题划分为一个或多个一步步接近递归出口的相似的规模更小的子问题。

3.将所解决的各个小问题的解组合起来,即可得到原问题的解。

设计递归算法时需注意以下几个问题:

1.如何使定义的问题规模逐步缩小,而且始终保持同一问题类型?

2.每个递归求解的问题其规模如何缩小?

3.多大规模的问题可作为递归出口?

4.随着问题规模的缩小,能到达递归出口吗?

Hanoi问题

给定三根柱子,其中A柱子从大到小套有n个圆盘,问题是如何借助B柱子,将圆盘从A搬到C。

和尚搬圆盘的游戏规则如下:

1.一次只能搬动一个圆盘;

2.不能将大圆盘放在小圆盘上面。

用递归来做,具体步骤如下:

把a上面n-1个盘子看做一个整体,这样a上面就剩下两个盘子了(n,n-1)。

 如果只有一个盘子 直接将a柱子上的盘子移到C柱上

否则     先将a柱上的n-1盘子移到B柱上,再将第n个盘子移动到C柱上。

要想完成将a柱上的n-1个盘子移到B柱上,遇到了刚才同样的问题,即将n-1个盘子从a柱借由c柱将n-2个盘子的先移到C柱上,再将最下面的第n-1个盘子移到B柱上。

 1 /*
 2 Haboi问题
 3 用递归来做 
 4 Hanoi(n,A,B,C)
 5     if n=1 then move(1,A,C)
 6     else
 7       Hanoi(n-1,A,C,B)
 8       move(n,A,C)
 9       Hanoi(n-1,B,A,C)
10 */ 
11 
12 #include<iostream>
13 using namespace std;
14 
15 void Hanoi(int n,char a,char b,char c)
16 {
17     if(n==1)  //如果只有一个盘子,直接a->c 
18     {
19         cout << n << ":" << a <<"->" << c << endl;
20     }
21     else
22     {
23         //把n-1个盘子借助于c从a移动到b
24         Hanoi(n-1,a,c,b);
25          cout << n << ":" << a <<"->" << c << endl;
26          //把n-1个盘子借助于借助于a从b移动到c
27          Hanoi(n-1,b,a,c); 
28     }
29 }
30 
31 int main()
32 {
33     int num;
34     cout << "盘子数:";
35     cin >> num;
36     Hanoi(num,'a','b','c');
37     return 0;
38 }

时间复杂度分析:

二、选择排序

基本思想就像排列你手中的扑克牌一样:

■把所有牌摊开,放在桌上,伸出你的左手,开始为空,准备拿牌;

■将桌上最小的牌拾起, 并把它插到左手所握牌的最右边。

■重复步骤(2) ,直到桌.上所有牌都拿在你的左手上,此时左手上所握的牌便是排好序的牌。

 

 1 /*
 2 SelectSort
 3 从头到尾扫描序列,找出最小的一个元素,和第一个元素交换,
 4 接着从剩下的元素中继续这种选择和交换
 5 最终得到一个有序序列 
 6 */
 7 
 8 #include<iostream>
 9 using namespace std;
10 
11 void swap(int *a,int *b)  //交换两个数的值 
12 {
13     int temp=*a;
14     *a=*b;
15     *b=temp;
16 }
17 
18 void selection_sort(int a[],int len)
19 {
20     int i,j;
21     for(i=0;i<len;i++)
22     {
23         int min=i;
24         for(j=i+1;j<len;j++)  //走访未排序的元素
25         if(a[j]<a[min])   //找到目前最小值 
26         min=j;   //记录最小值 
27         swap(&a[min],&a[i]);  //交换 
28     }
29 }
30 
31 int main()
32 {
33     int num[100];
34     int n;
35     cout << "输入元素个数:";
36     cin >> n;
37     for(int i=0;i<n;i++)
38     cin >> num[i];
39     cout << "排序后的结果为:" << endl;
40     selection_sort(num,n);
41     for(int j=0;j<n;j++)
42     cout << num[j] << ' ';
43     cout << endl;
44     return 0;
45  } 

选择排序是一种简单直观的排序算法,无论什么数据进去都是 O(n²) 的时间复杂度。所以用到它的时候,数据规模越小越好。唯一的好处可能就是不占用额外的内存空间了吧。

三、生成排列

问题是生成{,2..,n}的所有n!个排列

想法1:固定位置放元素

假设我们能够生成n-1个元素的所有排列,我们可以得到如下算法:

1.生成元素{2,3.,n} 的所有排列,并且将元素1放到每个排列的开头;

2.接着,生成元素{1,3...,n}的所有排列,并将数字2放到每个排列的开头;

3.重复这个过程,直到元素{2,3,..,n-1}的所有排列都产生,并将元素n放到每个排列的开头。

 1 /*
 2 permutstion
 3 递归生成全排列问题 
 4 */
 5 
 6 #include<iostream>
 7 using namespace std;
 8 
 9 void swap(int *a,int *b)
10 {
11     int temp=*a;
12     *a=*b;
13     *b=temp;
14 }
15 
16 void print_array(int a[],int len)
17 {
18     for(int i=0;i<len;i++)
19     cout << a[i] <<' ';
20     cout << endl;
21  } 
22  
23 void permutation(int num[],int p,int q)
24 {
25     if(p==q)
26     print_array(num,q+1);
27     else
28     {
29         for(int j=p;j<=q;j++)
30         {
31             swap(&num[p],&num[j]);
32             permutation(num,p+1,q);
33             swap(&num[p],&num[j]);
34         }
35     }
36 }
37 
38 int main()
39 {
40     int n;
41     cout << "n=";
42     cin >> n;
43     int array[100];
44     for(int i=0;i<n;i++)
45     array[i]=i+1;
46     //print_array(array,n);
47     permutation(array,0,n-1);
48     return 0;
49 }
原文地址:https://www.cnblogs.com/wlyperfect/p/12513915.html