算法之分治法小结

算法课 是这学期开的,但几乎没有去过 ,最近开始自己看自己学。



先从分治​递归开始

引用  算法老师课件里的东西:

凡治众如治寡,分数是也。

             —《孙子兵法》

大概意思就是:治理大军团就象治理小部队一样有效,是依靠合理的组织、结构、编制。

将一个难以直接解决的大问题,合理分割成一些规模较小的相同问题,以便各个击破,这个策略就叫分而治之

(分治法)。

主要思想是:将一个问题不断分割成若干个小问题,然后通过对小问题的求解再生成大问题的解。

分治法可以分为两个重要步骤:

(1)自顶向下:将问题不断分割成小的问题。

(2)自底而上:将小问题解决来构建大问题的解。

分治和递归经常同时应用在算法设计中。

例子1:找一组数的最大最小数。

直接求解:需要 n - 1 次比较来求最小数(n 个数两两比较共需要 n – 1 次),然后另外 n - 2 次比较来求最大

数(除去最小值的剩下 n – 1 个数两两比较共需要 n – 2 次)。总计为( 2n - 3)次。

分治方法: 

(1)将数据集 S 均分为 S1 和 S2;

(2)求解 S1 和 S2 中的最大和最小值;

(3)最终的最大和最小值可以计算得到:min( S1, S2 ), max( S1, S2 );

(4)采用同样的处理方法递归处理 S1 和 S2。

算法描述(为方便起见,假定 n 是 2 的指数倍,n > 1):

min_max(S, min, max) {
  if |S| = 2 then
    min  min(S)
    max  max(S)
  else 
    split S evenly into S1 and S2
    min_max(S1, min1, max1)
    min_max(S2, min2, max2)
    min  min(min1, min2)
    max  max(max1, max2)
}


代码如下:

#include <iostream>
using namespace std;
void min_max(int *a,int start,int end,int *min,int *max);
int main(void)
{
	int a[8]={2,3,6,5,1,2,8,3};
	int min=a[0];
	int max=a[0];

	min_max(a,0,7,&min,&max);
	for(int i=0;i<8;i++){
		cout<<a[i];
	}
	cout<<endl;

	cout<<"max="<<max<<endl;
	cout<<"min="<<min<<endl;

}
void min_max(int *a,int start,int end,int *min,int *max)
{
	if((end-start)<=1){
		if(a[start] > a[end]){
			*max = *max > a[start] ? *max : a[start];
			*min = *min < a[end] ? *min : a[end];
		}else{
			*max = *max > a[end] ? *max : a[end];
			*min = *min < a[start] ? *min : a[start];
		}
		return;
	}else{
		int i = start + (end-start)/2;
		min_max(a,start,i,min,max);
		min_max(a,i+1,end,min,max);
	}
}
例子2:排列问题。

设计一个递归算法生成 n 个元素{ r1, r2, …, rn }的全排列。
全排列:从 n 个不同元素中任取m(m ≤ n)个元素,按照一定的顺序排列起来,叫做从 n 个不同元素中取出 m 个

元素的一个排列。当 m = n 时所有的排列情况叫全排列。
如 1, 2, 3 三个元素的全排列为:
1, 2, 3      1, 3, 2
2, 1, 3      2, 3, 1
3, 1, 2      3, 2, 1
共 3!= 3 * 2 * 1 = 6 种排列

全排列的递归算法设计
从实际例子中观察可知:
(1){ 1 }的全排列为:1
(2){ 1, 2 }的全排列为:1, 2     2, 1
(3){ 1, 2, 3 }的全排列为:
           1, 2, 3      1, 3, 2  → { 2, 3 } 的全排列加上 1 所得
           2, 1, 3      2, 3, 1  → { 1, 3 } 的全排列加上 2 所得
           3, 1, 2      3, 2, 1  → { 1, 2 } 的全排列加上 3 所得
           即:3 个元素的全排列问题可转化为求 2 个元素的全排列问题。
………………….
推广结论:n 个元素的全排列问题可转化为求 n - 1 个元素的全排列问题(递归设计)。

全排列的递归算法
设 R ={ r1, r2, …, rn }是要进行排列的 n 个元素,Ri = R - { ri }。
集合 X 中元素的全排列记为 perm( X )。
( ri )perm( X ) 表示在全排列 perm( X ) 的每一个排列前加上前缀得到的排列。R的全排列可归纳定义如下:
 

当 n = 1 时,perm( R ) = ( r ),其中 r 是集合 R 中唯一的元素;
当 n > 1 时,perm( R ) 由 ( r1 )perm(R1),( r2 )perm(R2),…,( rn )perm(Rn)构成。

代码如下:

#include <iostream>
#include <cstring>
using namespace std;
void Swap(char *text1,char *text2)
{
	char temp = *text1;
	*text1 = *text2;
	*text2 = temp;
}
void AllRange(char *text,int s,int e)
{
	if(s == e){
		static int s_i = 1;
		cout<<"the "<<s_i++<<"AllRange "<<text<<endl;
	}else{
		for(int i=s;i<=e;i++){
			Swap(text+s,text+i);
			AllRange(text,s+1,e);
			Swap(text+s,text+i);
		}
	}
}
void Foo(char *text)
{
	AllRange(text,0,strlen(text)-1);
}
int main(void)
{
	char text[] = "123";
	cout<<text<<endl;

	Foo(text);

	return 0;
}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值