文档库 最新最全的文档下载
当前位置:文档库 › 递归与分治

递归与分治

递归与分治
递归与分治

分治算法

一、分治算法

分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。

分治法解题的一般步骤:

(1)分解,将要解决的问题划分成若干规模较小的同类问题;

(2)求解,当子问题划分得足够小时,用较简单的方法解决;

(3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。

当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。下面通过实例加以说明。

【例1】[找出伪币] 给你一个装有1 6个硬币的袋子。1 6个硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。你的任务是找出这个伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。比较硬币1与硬币2的重量。假如硬币1比硬币2轻,则硬币1是伪造的;假如硬币2比硬币1轻,则硬币2是伪造的。这样就完成了任务。假如两硬币重量相等,则比较硬币3和硬币4。同样,假如有一个硬币轻一些,则寻找伪币的任务完成。假如两硬币重量相等,则继续比较硬币5和硬币6。按照这种方式,可以最多通过8次比较来判断伪币的存在并找出这一伪币。

另外一种方法就是利用分而治之方法。假如把1 6硬币的例子看成一个大的问题。第一步,把这一问题分成两个小问题。随机选择8个硬币作为第一组称为A组,剩下的8个硬币作为第二组称为B组。这样,就把1 6个硬币的问题分成两个8硬币的问题来解决。第二步,判断A和B组中是否有伪币。可以利用仪器来比较A组硬币和B组硬币的重量。假如两组硬币重量相等,则可以判断伪币不存在。假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中。最后,在第三步中,用第二步的结果得出原先1 6个硬币问题的答案。若仅仅判断硬币是否存在,则第三步非常简单。无论A组还是B组中有伪币,都可以推断这1 6个硬币中存在伪币。因此,仅仅通过一次重量的比较,就可以判断伪币是否存在。

现在假设需要识别出这一伪币。把两个或三个硬币的情况作为不可再分的小问题。注意如果只有一个硬币,那么不能判断出它是否就是伪币。在一个小问题中,通过将一个硬币分别与其他两个硬币比较,最多比较两次就可以找到伪币。这样,1 6硬币的问题就被分为两个8硬币(A组和B组)的问题。通过比较这两组硬币的重量,可以判断伪币是否存在。如果没有伪币,则算法终止。否则,继续划分这两组硬币来寻找伪币。假设B是轻的那一组,因此再把它分成两组,每组有4个硬币。称其中一组为B1,另一组为B2。比较这两组,肯定有一组轻一些。如果B1轻,则伪币在B1中,再将B1又分成两组,每组有两个硬币,称其中一组为B1a,另一组为B1b。比较这两组,可以得到一个较轻的组。由于这个组只有两个硬币,因此不必再细分。比较组中两个硬币的重量,可以立即知道哪一个硬币轻一些。较轻的硬币就是所要找的伪币。

【例2】在n个元素中找出最大元素和最小元素。我们可以把这n个元素放在一个数组中,用直接比较法求出。算法如下:

void maxmin1(int A[],int n,int *max,int *min)

{ int i;

*min=*max=A[0];

for(i=2;i < n;i++)

{ if(A> *max) *max= A;

if(A < *min) *min= A;

}

}

上面这个算法需比较2(n-1)次。能否找到更好的算法呢?我们用分治策略来讨论。

把n个元素分成两组:

A1={A[1],...,A[int(n/2)]}和A2={A[INT(N/2)+1],...,A[N]}

分别求这两组的最大值和最小值,然后分别将这两组的最大值和最小值相比较,求出全部元素的最大值和最小值。如果A1和A2中的元素多于两个,则再用上述方法各分为两个子集。直至子集中元素至多两个元素为止。

例如有下面一组元素:-13,13,9,-5,7,23,0,15。用分治策略比较的过程如下:

图中每个方框中,左边是最小值,右边是最大值。从图中看出,用这种方法一共比较了10次,比直接比较法的14次减少4次,即约减少了1/3。算法如下:

void maxmin2(int A[],int i,int j,int *max,int *min)

/*A存放输入的数据,i,j存放数据的范围,初值为0,n-1,*max,int *m in 存放最大和最小值*/

{ int mid,max1,max2,min1,min2;

if (j==i) {最大和最小值为同一个数;return;}

if (j-1==i) {将两个数直接比较,求得最大会最小值;return;}

mid=(i+j)/2;

求i~mid之间的最大最小值分别为max1,min1;

求mid+1~j之间的最大最小值分别为max2,min2;

比较max1和max2,大的就是最大值;

比较min1和min2,小的就是最小值;

}

利用分治策略求解时,所需时间取决于分解后子问题的个数、子问题的规模大小等因素,而二分法,由于其划分的简单和均匀的特点,是经常采用的一种有效的方法,例如二分法检索。运用分治策略解决的问题一般来说具有以下特点:

1、原问题可以分解为多个子问题,这些子问题与原问题相比,只是问题的规模有所降低,其结构和求解方法与原问题相同或相似。

2、原问题在分解过程中,递归地求解子问题,由于递归都必须有一个终止条件,因此,当分解后的子问题规模足够小时,应能够直接求解。

3、在求解并得到各个子问题的解后,应能够采用某种方式、方法合并或构造出原问题的解。

不难发现,在分治策略中,由于子问题与原问题在结构和解法是的相似性,用分治方法解决的问题,大都采用了递归的形式。在各种排序方法中,如归并排序、堆排序、快速排序等,都存在有分治的思想。

递归算法

递归算法:是一种直接或者间接地调用自身的算法。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。

递归算法的特点

递归过程一般通过函数或子过程来实现。

递归算法:在函数或子过程的内部,直接或者间接地调用自己的算法。

递归算法的实质:是把问题转化为规模缩小了的同类问题的子问题。然后递归调用函数(或过程)来表示问题的解。

递归算法解决问题的特点:

(1) 递归就是在过程或函数里调用自身。

(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。

(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

递归算法所体现的“重复”一般有三个要求:

一是每次调用在规模上都有所缩小(通常是减半);

二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);

三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

例子如下:

描述:把一个整数按n(2<=n<=20)进制表示出来,并保存在给定字符串中。比如121用二进制表示得到结果为:“1111001”。

参数说明:s: 保存转换后得到的结果。

n: 待转换的整数。

b: n进制(2<=n<=20)

void

numbconv(char *s, int n, int b)

{

int len;

if(n == 0) {

strcpy(s, "");

return;

}

/* figure out first n-1 digits */

numbconv(s, n/b, b);

/* add last digit */

len = strlen(s);

s[len] = "0123456789ABCDEFGHIJKLMNOPQRSTUVW XYZ"[n%b];

s[len+1] = '\0';

}

void

main(void)

{

char s[20];

int i, base;

FILE *fin, *fout;

fin = fopen("palsquare.in", "r");

fout = fopen("palsquare.out", "w");

assert(fin != NULL && fout != NULL);

fscanf(fin, "%d", &base);

/*PLS set START and END*/

for(i=START; i <= END; i++) {

numbconv(s, i*i, base);

fprintf(fout, "%s\n", s);

}

exit(0);

}

递归算法简析(PASCAL语言)

递归是计算机科学的一个重要概念,递归的方法是程序设计中有效的方法,采用递归编写

程序能是程序变得简洁和清晰.

一递归的概念

1.概念

一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数).

如:

procedure a;

begin

.

.

.

a;

.

.

.

end;

这种方式是直接调用.

又如:

procedure b; procedure c;

begin begin

. .

. .

. .

c; b;

. .

. .

. .

end; end;

这种方式是间接调用.

例1计算n!可用递归公式如下:

1 当n=0 时

fac(n)={n*fac(n-1) 当n>0时

可编写程序如下:

program fac2;

var

n:integer;

function fac(n:integer):real;

begin

if n=0 then fac:=1 else fac:=n*fac(n-1) end;

begin

write('n=');readln(n);

writeln('fac(',n,')=',fac(n):6:0);

end.

例2 楼梯有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,编一程序计算共有多少种不同的走法.

设n阶台阶的走法数为f(n)

显然有

1 n=1

f(n)={

f(n-1)+f(n-2) n>2

可编程序如下:

program louti;

var n:integer;

function f(x:integer):integer;

begin

if x=1 then f:=1 else

if x=2 then f:=2 else f:=f(x-1)+f(x-2);

end;

begin

write('n=');read(n);

writeln('f(',n,')=',f(n))

end.

二,如何设计递归算法

1.确定递归公式

2.确定边界(终了)条件

三,典型例题

例3 梵塔问题

如图:已知有三根针分别用1,2,3表示,在一号针中从小放n个盘子,现要求把所有的盘子

从1针全部移到3针,移动规则是:使用2针作为过度针,每次只移动一块盘子,且每根针上

不能出现大盘压小盘.找出移动次数最小的方案.

程序如下:

program fanta;

var

n:integer;

procedure move(n,a,b,c:integer);

begin

if n=1 then writeln(a,'--->',c)

else begin

move(n-1,a,c,b);

writeln(a,'--->',c);

move(n-1,b,a,c);

end;

end;

begin

write('Enter n=');

read(n);

move(n,1,2,3);

end.

例4 快速排序

快速排序的思想是:先从数据序列中选一个元素,并将序列中所有比该元素小的元素都放到它的右边或左边,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为1, 处理结束.

程序如下:

program kspv;

const n=7;

type

arr=array[1..n] of integer;

var

a:arr;

i:integer;

procedure quicksort(var b:arr; s,t:integer);

var i,j,x,t1:integer;

begin

i:=s;j:=t;x:=b ;

repeat

while (b[j]>=x) and (j>i) do j:=j-1;

if j>i then begin t1:=b; b:=b[j];b[j]:=t1;end;

while (b<=x) and (i

if i

until i=j;

b:=x;

i:=i+1;j:=j-1;

if s

if i

end;

begin

write('input data:');

for i:=1 to n do read(a);

writeln;

quicksort(a,1,n);

write('output data:');

for i:=1 to n do write(a:6);

writeln;

end.

二叉树遍历

二叉树的遍历搜索路径

遍历概念:

所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题。

遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。

遍历方案:

1.遍历方案

从二叉树的递归定义可知,一棵非空的二叉树由根结点及左、右子树这三个基本部分组成。因此,在任一给定结点上,可以按某种次序执行三个操作:(1)访问结点本身(N),

(2)遍历该结点的左子树(L),

(3)遍历该结点的右子树(R)。

以上三种操作有六种执行次序:

NLR、LNR、LRN、NRL、RNL、RLN。

注意:

前三种次序与后三种次序对称,故只讨论先左后右的前三种次序。

2.三种遍历的命名

根据访问结点操作发生位置命名:

①NLR:前序遍历(PreorderTraversal亦称(先序遍历))

——访问结点的操作发生在遍历其左右子树之前。

②LNR:中序遍历(InorderTraversal)

——访问结点的操作发生在遍历其左右子树之中(间)。

③LRN:后序遍历(PostorderTraversal)

——访问结点的操作发生在遍历其左右子树之后。

注意:

由于被访问的结点必是某子树的根,所以N(Node)、L(Left subtree)和R (Right subtree)又可解释为根、根的左子树和根的右子树。NLR、LNR和LR N分别又称为先根遍历、中根遍历和后根遍历。

遍历算法

1.中序遍历的递归算法定义:

若二叉树非空,则依次执行如下操作:

(1)遍历左子树;

(2)访问根结点;

(3)遍历右子树。

2.先序遍历的递归算法定义:

若二叉树非空,则依次执行如下操作:

(1) 访问根结点;

(2) 遍历左子树;

(3) 遍历右子树。

3.后序遍历得递归算法定义:

若二叉树非空,则依次执行如下操作:

(1)遍历左子树;

(2)遍历右子树;

(3)访问根结点。

4.中序遍历的算法实现

用二叉链表做为存储结构,中序遍历算法可描述为:

void InOrder(BinTree T)

{ //算法里①~⑥是为了说明执行过程加入的标号

①if(T) { // 如果二叉树非空

②InOrder(T->lchild);

③printf("%c",T->data);// 访问结点

④InOrder(T->rchild);

⑤}

⑥} // InOrder

遍历序列

1.遍历二叉树的执行踪迹

三种递归遍历算法的搜索路线相同(如下图虚线所示)。

具体线路为:

从根结点出发,逆时针沿着二叉树外缘移动,对每个结点均途径三次,最后回到根结点。

2.遍历序列

A

/ \

B C

/ / \

D E F

(1)中序序列(inorder travers al)

中序遍历二叉树时,对结点的访问次序为中序序列

【例】中序遍历上图所示的二叉树时,得到的中序序列为:

D B A

E C F

(2)先序序列(preorder traversal)

先序遍历二叉树时,对结点的访问次序为先序序列

【例】先序遍历上图所示的二叉树时,得到的先序序列为:

A B D C E F

(3)后序序列(postorder traversal)

后序遍历二叉树时,对结点的访问次序为后序序列

【例】后序遍历上图所示的二叉树时,得到的后序序列为:

D B

E

F C A

(4)层次遍历(level traversal)二叉树的操作定义为:若二叉树为空,则退出,否则,按照树的结构,从根开始自上而下,自左而右访问每一个结点,从而实现对每一个结点的遍历

注意:

(1)在搜索路线中,若访问结点均是第一次经过结点时进行的,则是前序遍历;若访问结点均是在第二次(或第三次)经过结点时进行的,则是中序遍历(或后序遍历)。只要将搜索路线上所有在第一次、第二次和第三次经过的结点分别列表,即可分别得到该二叉树的前序序列、中序序列和后序序列。

(2)上述三种序列都是线性序列,有且仅有一个开始结点和一个终端结点,其余结点都有且仅有一个前趋结点和一个后继结点。为了区别于树形结构中前趋(即双亲)结点和后继(即孩子)结点的概念,对上述三种线性序列,要在某结点的前趋和后继之前冠以其遍历次序名称。

【例】上图所示的二叉树中结点C,其前序前趋结点是D,前序后继结点是E;中序前趋结点是E,中序后继结点是F;后序前趋结点是F,后序后继结点是A。但是就该树的逻辑结构而言,C的前趋结点是A,后继结点是E和F。

二叉链表的构造

1.基本思想

基于先序遍历的构造,即以二叉树的先序序列为输入构造。

注意:

先序序列中必须加入虚结点以示空指针的位置。

【例】

建立上图所示二叉树,其输入的先序序列是:ABD∮∮∮CE∮∮F∮∮。

2.构造算法

假设虚结点输入时以空格字符表示,相应的构造算法为:

void CreateBinTree (BinTree *T)

{ //构造二叉链表。T是指向根指针的指针,故修改*T就修改了实参(根指针)本身

char ch;

if((ch=getchar())=='') *T=NULL;//读人空格,将相应指针置空

else{ //读人非空格

*T=(BinTNode *)malloc(sizeof(BinTNode));//生成结点

(*T)->data=ch;

CreateBinTree(&(*T)->lchild);//构造左子树

CreateBinTree(&(*T)->rchild);//构造右子树

}

}

注意:

调用该算法时,应将待建立的二叉链表的根指针的地址作为实参。

【例】

设root是一根指针(即它的类型是BinTree),则调用CreateBinTree(&roo t)后root就指向了已构造好的二叉链表的根结点。

二叉树建立过程见https://www.wendangku.net/doc/0812295626.html,/course_ware/data_structure/we b/flashhtml/erchashujianli.htm

下面是关于二叉树的遍历、查找、删除、更新数据的代码(递归算法):

[code]

#include

using namespace std;

typedef int T;

class bst{

struct Node{

T data;

Node* L;

Node* R;

Node(const T& d, Node* lp=NULL, Node* rp=NULL):data(d),L(lp),R (rp){}

};

Node* root;

int num;

public:

bst():root(NULL),num(0){}

void clear(Node* t){

if(t==NULL) return;

clear(t->L);

clear(t->R);

delete t;

}

~bst(){clear(root);}

void clear(){

clear(root);

num = 0;

root = NULL;

}

bool empty(){return root==NULL;} int size(){return num;}

T getRoot(){

if(empty()) throw "empty tree"; return root->data;

}

void travel(Node* tree){

if(tree==NULL) return;

travel(tree->L);

cout << tree->data << ' ';

travel(tree->R);

}

void travel(){

travel(root);

cout << endl;

}

int height(Node* tree){

if(tree==NULL) return 0;

int lh = height(tree->L);

int rh = height(tree->R);

return 1+(lh>rh?lh:rh);

}

int height(){

return height(root);

}

void insert(Node*& tree, const T& d){ if(tree==NULL)

tree = new Node(d);

else if(ddata)

insert(tree->L, d);

else

insert(tree->R, d);

}

void insert(cons t T& d){

insert(root, d);

num++;

}

Node*& find(Node*& tree, const T& d){ if(tree==NULL) return tree;

if(tree->data==d) return tree;

if(ddata)

return find(tree->L, d);

else

return find(tree->R, d);

}

bool find(const T& d){

return find(root, d)!=NULL;

}

bool erase(const T& d){

Node*& pt = find(root, d);

if(pt==NULL) return false;

combine(pt->L, pt->R);

Node* p = pt;

pt = pt->R;

delete p;

num--;

return true;

}

void combine(Node* lc, Node*& rc){

if(lc==NULL) return;

if(rc==NULL) rc = lc;

else combine(lc, rc->L);

}

bool update(const T& od, const T& nd){ Node* p = find(root, od);

if(p==NULL) return false;

erase(od);

insert(nd);

return true;

}

};

int main()

{

bst b;

cout << "input som e integers:";

for(;;){

int n;

cin >> n;

b.insert(n);

if(cin.peek()=='\n') break;

}

b.travel();

for(;;){

cout << "input data pair:";

int od, nd;

cin >> od >> nd;

if(od==-1&&nd==-1) break;

b.update(od, nd);

b.travel();

}

}

[/code]

实验报告 分治与递归

实验报告分治与递归 中国矿业大学计算机科学与技术学院孟靖宇 一、实验目的与要求 1、熟悉C/C++语言的集成开发环境; 2、通过本实验加深对递归过程的理解 二、实验内容: 掌握递归算法的概念和基本思想,分析并掌握“整数划分”问题的递归算法。 三、实验题 任意输入一个整数,输出结果能够用递归方法实现整数的划分。 四、算法思想 对于数据n,递归计算最大加数等于x 的划分个数+最大加数不大于x-1的划分个数。最大加数x 从n 开始,逐步变小为n-1, (1) 考虑增加一个自变量:对于数据n,最大加数n1不大于m 的划分个数记作),(m n q 。则有: ???????>>=<==-+--+=1 1,1),()1,()1,(1),(1),(m n m n m n m n m m n q m n q n n q n n q m n q 五、代码实现 #include "stdafx.h" #include #include #include using namespace std; int q(intn,int m); int main(){ int n; cout<<"请输入要划分的整数:"<>n; int p=q(n,n); cout<<"正整数"<

return 0; } int q(intn,int m){ if((n<1)||(m<1)) return 0; if((n==1)||(m==1)) return 1; if(n

递归与分治

分治算法 一、分治算法 分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。 分治法解题的一般步骤: (1)分解,将要解决的问题划分成若干规模较小的同类问题; (2)求解,当子问题划分得足够小时,用较简单的方法解决; (3)合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。 当我们求解某些问题时,由于这些问题要处理的数据相当多,或求解过程相当复杂,使得直接求解法在时间上相当长,或者根本无法直接求出。对于这类问题,我们往往先把它分解成几个子问题,找到求出这几个子问题的解法后,再找到合适的方法,把它们组合成求整个问题的解法。如果这些子问题还较大,难以解决,可以再把它们分成几个更小的子问题,以此类推,直至可以直接求出解为止。这就是分治策略的基本思想。下面通过实例加以说明。 【例1】[找出伪币] 给你一个装有1 6个硬币的袋子。1 6个硬币中有一个是伪造的,并且那个伪造的硬币比真的硬币要轻一些。你的任务是找出这个伪造的硬币。为了帮助你完成这一任务,将提供一台可用来比较两组硬币重量的仪器,利用这台仪器,可以知道两组硬币的重量是否相同。比较硬币1与硬币2的重量。假如硬币1比硬币2轻,则硬币1是伪造的;假如硬币2比硬币1轻,则硬币2是伪造的。这样就完成了任务。假如两硬币重量相等,则比较硬币3和硬币4。同样,假如有一个硬币轻一些,则寻找伪币的任务完成。假如两硬币重量相等,则继续比较硬币5和硬币6。按照这种方式,可以最多通过8次比较来判断伪币的存在并找出这一伪币。 另外一种方法就是利用分而治之方法。假如把1 6硬币的例子看成一个大的问题。第一步,把这一问题分成两个小问题。随机选择8个硬币作为第一组称为A组,剩下的8个硬币作为第二组称为B组。这样,就把1 6个硬币的问题分成两个8硬币的问题来解决。第二步,判断A和B组中是否有伪币。可以利用仪器来比较A组硬币和B组硬币的重量。假如两组硬币重量相等,则可以判断伪币不存在。假如两组硬币重量不相等,则存在伪币,并且可以判断它位于较轻的那一组硬币中。最后,在第三步中,用第二步的结果得出原先1 6个硬币问题的答案。若仅仅判断硬币是否存在,则第三步非常简单。无论A组还是B组中有伪币,都可以推断这1 6个硬币中存在伪币。因此,仅仅通过一次重量的比较,就可以判断伪币是否存在。

算法分析实验报告--分治策略

《算法设计与分析》实验报告 分治策略 姓名:XXX 专业班级:XXX 学号:XXX 指导教师:XXX 完成日期:XXX

一、试验名称:分治策略 (1)写出源程序,并编译运行 (2)详细记录程序调试及运行结果 二、实验目的 (1)了解分治策略算法思想 (2)掌握快速排序、归并排序算法 (3)了解其他分治问题典型算法 三、实验内容 (1)编写一个简单的程序,实现归并排序。 (2)编写一段程序,实现快速排序。 (3)编写程序实现循环赛日程表。设有n=2k个运动员要进行网球循环赛。现 要设计一个满足以下要求的比赛日程表:(1)每个选手必须与其它n-1个选手各赛一次(2)每个选手一天只能赛一场(3)循环赛进行n-1天 四、算法思想分析 (1)编写一个简单的程序,实现归并排序。 将待排序元素分成大小大致相同的2个子集合,分别对2个子集合进行 排序,最终将排好序的子集合合并成为所要求的排好序的集合。 (2)编写一段程序,实现快速排序。 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有 数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数 据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据 变成有序序列。 (3)编写程序实现循环日赛表。 按分治策略,将所有的选手分为两组,n个选手的比赛日程表就可以通

过为n/2个选手设计的比赛日程表来决定。递归地用对选手进行分割, 直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让 这2个选手进行比赛就可以了。 五、算法源代码及用户程序 (1)编写一个简单的程序,实现归并排序。 #include #include #define MAX 10 using namespace std; void merge(int array[],int p,int q,int r) { int i,k; int begin1,end1,begin2,end2; int* temp = new int[r-p+1]; begin1 = p; end1 = q; begin2 = q+1; end2 = r; k = 0; while((begin1 <= end1)&&(begin2 <= end2)) { if(array[begin1] < array[begin2]) { temp[k] = array[begin1]; begin1++; } else { temp[k] = array[begin2]; begin2++; } k++; } while(begin1 <= end1) {

算法设计与分析:递归与分治法-实验报告

应用数学学院信息安全专业班学号姓名 实验题目递归与分治法 综合实验评分表

实验报告 一、实验目的与要求 1.掌握递归算法的设计思想 2.掌握分治法设计算法的一般过程 3.理解并掌握算法渐近时间复杂度的分析方法 二、实验内容 1、折半查找的递归算法 (1)源程序代码 #include #include using namespace std; int bin_search(int key[],int low, int high,int k) { int mid; if(low>high) return -1; else{ mid = (low+high) / 2; if(key[mid]==k) return mid; if(k>key[mid]) return bin_search(key,mid+1,high,k); else return bin_search(key,low,mid-1,k); } } int main() { int n , i , addr; int A[10] = {2,3,5,7,8,10,12,15,19,21}; cout << "在下面的10个整数中进行查找" << endl; for(i=0;i<10;i++){ cout << A[i] << " " ; } cout << endl << endl << "请输入一个要查找的整数" << endl; cin >> n; addr = bin_search(A,0,9,n);

if(-1 != addr) cout << endl << n << "是上述整数中的第" << addr << "个数" << endl; else cout << endl << n << "不在上述的整数中" << endl << endl; getchar(); return 0; } (2)运行界面 ①查找成功 ②查找失败

递归与分治实验报告

递归与分治实验报告 班级:计科1102 姓名:赵春晓学号:2011310200631 实验目的:进一步掌握递归与分治算法的设计思想,通过实际问题来应用递归与分治设计算法。 实际问题:1集合划分问题,2输油管道问题,3邮局选址问题,4整数因子分解问题,5众数问题。 问题1:集合划分 算法思想:对于n个元素的集合,可以划分为由m个子集构成的集合,例如{{1,2}{3,4}}就是由2个子集构成的非空子集。假设f(n,m)表示将n个元素划分成由m个子集构成的集合的个数。那么1)若m == 1 ,则f(n,m)= 1 ;2)若n == m ,则f(n,m)= 1 ;3)若不是上面两种情况则有下面两种情况构成:3.1)向n-1个元素划分成的m个集合里面添加一个新的元素,则有m*f(n-1,m)种方法;3.2)向n-1个元素划分成的m-1个集合里添加一个由一个元素形成的独立的集合,则有f(n-1,m-1)种方法。 实验代码: #include #include using namespace std ; int jihehuafen( int n , int m ) { if( m == 1 || n == m ) return 1 ; else return jihehuafen( n - 1 , m - 1 ) + m*jihehuafen( n - 1 , m ) ; } int main() { ifstream fin("C:/input.txt") ; ofstream fout("C:/output.txt") ; int N , M , num ; fin >> N >> M ; num = jihehuafen( N , M) ; fout << num << endl ; return 0 ; } 问题2:输油管道 算法思想:由于主管道由东向西铺设。故主管道的铺设位置只和各油井的y坐标有关。要使主管道的y坐标最小,主管道的位置y坐标应是各个油井y坐标的中位数。先用快速排序法把各个油井的y坐标排序,然后取其中位数再计算各个油

算法分析与设计实验一递归与分治策略

实验一递归与分治策略 实验目的 1.了解并掌握递归的概念,递归算法的基本思想; 2.掌握分治法的基本思想方法; 3.了解适用于用分治法求解的问题类型,并能用递归或非递归的方式设计相应的分治法算法; 4.掌握分治法复杂性分析方法,比较同一个问题的递归算法与循环迭代算法的效率。预习与实验要求 1.预习实验指导书及教材的有关内容,掌握分治法的基本思想; 2.严格按照实验内容进行实验,培养良好的算法设计和编程的习惯; 3.认真听讲,服从安排,独立思考并完成实验。 实验原理 简单说来,当一个函数用它自己来定义时就称为递归。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。因此,在考虑使用递归算法编写程序时,应满足两点:1)该问题能够被递归形式描述;2)存在递归结束的边界条件。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。一般说来,一个递归算法可以转换称为一个与之等效的非递归算法,但转换后的非递归算法代码将成倍地增加。 分治是一种被广泛应用的有效方法,它的基本思想是把最初的问题分解成若干子问题,然后在逐个解决各个子问题的基础上得到原始问题的解。所谓分治就是“分而治之”的意思。由于分解出的每个子问题总是要比最初的问题容易些,因而分治策略往往能够降低原始问题的难度,或者提高解决原始问题的效率。 根据如何由分解出的子问题求出原始问题的解,分治策略又可分为两种情形:第一,原始问题的解只存在于分解出的某一个子问题中,则只需要在原始问题的一个划分中求解即可;第二,原始问题的解需要由各个子问题的解再经过综合处理得到。无论是哪一种情况,分治策略可以较快地缩小问题的求解范围,从而加快问题求解的速度。 分治策略运用于计算机算法是,往往会出现分解出来的子问题与原始问题类型相同的现象,而与原问题相比,各个子问题的规模变小了,这刚好符合递归的特征。因此分治策略往往是和递归联系在一起的。

算法之2章递归与分治

算法分析(第二章):递归与分治法 一、递归的概念 知识再现:等比数列求和公式: 1、定义:直接或间接地调用自身的算法称为递归算法。 用函数自身给出定义的函数称为递归函数。 2、与分治法的关系: 由分治法产生的子问题往往是原问题的较小模式,这就为使用递归技术提供了方便。在这种情况下,反复应用分治手段,可以使子问题与原问题类型一致而其规模却不断缩小,最终使子问题缩小到很容易直接求出其解。这自然导致递归过程的产生。分治与递归经常同时应用在算法设计之中,并由此产生许多高效算法。 3、递推方程: (1)定义:设序列01,....n a a a简记为{ n a},把n a与某些个() i a i n <联系起来的等式叫做关于该序列的递推方程。 (2)求解:给定关于序列{n a}的递推方程和若干初值,计算n a。 4、应用:阶乘函数、Fibonacci数列、Hanoi塔问题、插入排序 5、优缺点: 优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法、调试程序带来很大方便。 缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储空间都比非递归算法要多。 二、递归算法改进: 1、迭代法: (1)不断用递推方程的右部替代左部 (2)每一次替换,随着n的降低在和式中多出一项 (3)直到出现初值以后停止迭代 (4)将初值代入并对和式求和 (5)可用数学归纳法验证解的正确性 2、举例: -----------Hanoi塔算法----------- ---------------插入排序算法----------- ()2(1)1 (1)1 T n T n T =?+ = ()(1)1 W n W n n W =?+? (1)=0

实验1++递归与分治算法

淮海工学院计算机工程学院实验报告书 课程名:《算法分析与设计》 题目:实验1 递归与分治算法 班级: 学号: 姓名:

实验1 递归与分治算法 实验目的和要求 (1)进一步掌握递归算法的设计思想以及递归程序的调试技术; (2)理解这样一个观点:分治与递归经常同时应用在算法设计之中。 (3)分别用蛮力法和分治法求解最近对问题; (4)分析算法的时间性能,设计实验程序验证分析结论。 实验内容 设p1=(x1, y1), p2=(x2, y2), …, pn=(xn, yn)是平面上n个点构成的集合S,设计算法找出集合S中距离最近的点对。 实验环境 Turbo C 或VC++ 实验学时 2学时,必做实验 数据结构与算法 核心源代码 蛮力法: #include #include #include int ClosestPoints(int x[ ], int y[ ], int n); int main() { int x[3],y[3]; printf("请输入各点的横坐标: "); for(int i=0;i<4;i++) { scanf("%d",&x[i]); } printf("请输入各点的纵坐标: "); for(int j=0;j<4;j++)

{ scanf("%d",&y[i]); } ClosestPoints(x,y,4); return 0; } int ClosestPoints(int x[ ], int y[ ], int n) { int index1, index2; //记载最近点对的下标 int d, minDist = 1000; //假设最大距离不超过1000 for (int i = 0; i < n - 1; i++) for (int j = i + 1; j < n; j++) //只考虑i<j的点对 { d =sqrt ((x[i]-x[j])* (x[i]-x[j]) + (y[i]-y[j])* (y[i]-y[j])); if (d < minDist) { minDist = d; index1 = i; index2 = j; } } cout<<"最近的点对是:"< #include const int n = 4; struct point //定义点的结构体 { int x, y; };

递归与分治策略

第2章递归与分治策略 实验2 分治算法的递归程序实现与时间复杂度测试 1. 实验目的 编程实现合并排序和快速排序算法,理解分治算法设计的基本思想、递归程序实现的基本方法,加深对分治算法设计与分析思想的理解。通过程序的执行时间测试结果,与理论上的时间复杂度结论进行对比、分析和验证。 2. 原理解析 分治算法的基本思想 分治算法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题,这些子问题相互独立且与原问题性质相同。求出子问题的解,就可得到原问题的解。分治算法设计的一般步骤包括: (1) 分解,将要解决的问题划分成若干规模较小的同类问题; (2) 求解,当子问题划分得足够小时,用较简单的方法解决; (3) 合并,按原问题的要求,将子问题的解逐层合并构成原问题的解。 分治法的基本设计范式如下: DivideAndConquer(data,n,solution) if(n≤SizeLimit) then DirectSolution(data,n,solution) else DivideInput(data,n,smallerSets,smallerSizes,numberSmaller) for i=1 to numberSmaller do DivideAndConquer(smallerSets[i],smallerSizes[i],smallerSol ution[i]) end for CombineSolutions(smallerSolution,numberSmaller,solution) end if

测试算法 不同问题的分治算法在分解与合并步骤可能有所不同,例如合并排序和快速排序这两个有代表性的分治算法中,合并排序算法没有分解、只有合并,快速排序算法没有合并、只有分解;这两个算法的计算时间分别取决于合并与分解步骤。这两个算法分别如下: 1、MergeSort(list, first, last) if first

分治与递归 循环赛编程

实验一:分治与递归 【实验目的】 深入理解分治法算法思想,并采用分治法进行程序设计。 【实验性质】 验证性实验。 【实验内容与要求】 设有n=2k个运动员要进行网球循环赛。现要设计一个满足以下要求的比赛日程表:⑴每个选手必须与其他n-1个选手各赛一次;⑵每个选手一天只能赛一次;⑶循环赛一共进行n-1天。按此要求可将比赛日程表设计-成有n行和n-l列的一个表。在表中第i行和第j列处填入第i个选手在第j天所遇到的选手。用分治法编写为该循环赛设计一张比赛日程表的算法并运行实现、对复杂度进行分析。 算法思想:按分治策略,我们可以将所有选手对分为两组,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地用这种一分为二的策略对选手进行分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单。这时只要让这2个选手进行比赛就可以了。 下图所列出的正方形表是4个选手的比赛日程表。其中左上角与左下角的两小块分别为选手1至选手2和选手3至选手4第1天的比赛日程。据此,将左上角小块中的所有数字按其相对位置抄到右下角,将左下角小块中的所有数字按其相对位置抄到右上角,这样我们就分别安排好了选手1至选手2和选手3至选手4在后2天的比赛日程。这种安排是符合要求的。 程安排表。

#include #include #define x 16 int a[x][x]; void gamecal(int k,int m); void main() { int i,j,m; // int a[x][x]={0}; printf("请输入参赛人数(2^x):"); scanf_s("%d",&m); gamecal(1,m); printf("d:"); for(i=1;i

使用分治策略递归和非递归和递推算法解决循环赛日程表课程设计报告

《算法设计与分析》 课程设计报告 题目:循环赛日程表 院(系):信息科学与工程学院 专业班级:软工 学生姓名: 学号: 指导教师: 2018 年 1 月 8 日至 2018 年 1 月 19 日

算法设计与分析课程设计任务书

目录 1 常用算法 (1) 1.1分治算法 (1) 基本概念: (1) 1.2递推算法 (2) 2 问题分析及算法设计 (5) 2.1分治策略递归算法的设计 (5) 2.2 分治策略非递归算法的设计 (7) 2.3 递推策略算法的设计 (8) 3 算法实现 (9) 3.1分治策略递归算法的实现 (9) 3.2 分治策略非递归算法的实现 (10) 3.3 递推策略算法的实现 (12) 4 测试和分析 (15) 4.1分治策略递归算法测试 (15) 4.2分治策略递归算法时间复杂度的分析 (16) 4.3 分治策略非递归算法测试 (16) 4.4分治策略非递归算法时间复杂度的分析 (17) 时间复杂度为:O(5^(n-1)) (17) 4.5 递推策略算法测试 (17) 4.6 递推策略算法时间复杂度的分析 (18) 时间复杂度为:O(5^(n-1)) (18) 4.7 三种算法的比较 (18) 5 总结 (19) 参考文献 (20)

1 常用算法 1.1分治算法 基本概念: 在计算机科学中,分治法是一种很重要的算法。字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)…… 任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算。n=2时,只要作一次比较即可排好序。n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。 基本思想及策略: 分治法的设计思想是:将一个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。 分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。 如果原问题可分割成k个子问题,1

算法设计与分析习题答案1-6章

习题1 1. 图论诞生于七桥问题。出生于瑞士的伟大数学家欧拉(Leonhard Euler ,1707—1783)提出并解决了该问题。七桥问题是这样描述的:一个人是否能在一次步行中穿越哥尼斯堡(现在 叫加里宁格勒,在波罗的海南岸)城中全部的七座桥后回到起点,且每座桥只经过一次,图是这条河以及河上的两个岛和七座桥的草图。请将该问题的数据模型抽象出来,并判断此问题是否有解。 七桥问题属于一笔画问题。 输入:一个起点 输出:相同的点 1, 一次步行 2, 经过七座桥,且每次只经历过一次 3, 回到起点 该问题无解:能一笔画的图形只有两类:一类是所有的点都是偶点。另一类是只有二个奇点的图形。 2.在欧几里德提出的欧几里德算法中(即最初的欧几里德算法)用的不是除法而是减法。请用伪代码描述这个版本的欧几里德算法 =m-n 2.循环直到r=0 m=n n=r r=m-n 图 七桥问题 南区

3 输出m 3.设计算法求数组中相差最小的两个元素(称为最接近数)的差。要求分别给出伪代码和C++描述。 编写程序,求n至少为多大时,n个“1”组成的整数能被2013整除。 #include using namespace std; int main() { double value=0; for(int n=1;n<=10000 ;++n) { value=value*10+1; if(value%2013==0) { cout<<"n至少为:"< using namespace std; int main () {

实验一 分治与递归

实验一分治与递归 一、实验目的与要求 1、熟悉C/C++语言的集成开发环境; 2、通过本实验加深对递归过程的理解 二、实验内容: 掌握递归算法的概念和基本思想,分析并掌握“整数划分”问题的递归算法。 三、实验题 任意输入一个整数,输出结果能够用递归方法实现整数的划分。 四、实验步骤 1.理解算法思想和问题要求; 2.编程实现题目要求; 3.上机输入和调试自己所编的程序; 4.验证分析实验结果; 5.整理出实验报告。 五.实验源代码: (1)//基本递归算法整数划分 #include #include using namespace std; //int n; int integer_split(int n,int m) { if(m==1||n==1) { return 1; } if(n

return integer_split(n-m,m)+integer_split(n,m-1); } int main() { int n; scanf("%d",&n); int count=0; //for(int m=n;m>=1;m--) //{ count=integer_split(n,n); //} printf("%d",count); return 0; } (2)运行结果: Input:请输入一个待划分的整数 Output:输出有多少种划分 样例: Input:6 Output:11; (3)算法思路: 首先要找出递归的公式来,首先分析几种简单的情况,n==1||m==1可以直接得出结果为1;而当n

实验一 递归与分治策略算法设计与实现实验报告

华北水利水电学院算法分析与设计实验报告 20010~2011学年第二学期2008级计算机科学与技术专业 班级:2008109 学号:200810906 姓名:刘景超 实验一递归与分治算法的设计与实现 一、实验目的: 1、了解递归、分治算法的设计思路与设计技巧,理解递归的概念,掌握设计有效算法的 分治策略。 2、通过实际案例,领会算法的执行效率 二、试验内容: 棋盘覆盖、最接近点对、排序算法、矩阵乘法等,(也可选作其它问题); 三、核心程序源代码: #include #include void main() { void hanoi(int n,char one,char two,char three); int m; cout<<"请输入要移动的盘子的数目:"<>m; cout<<"盘子的数目为:"<"<

五、小结 本想用MFC采用图形的方式展示移动的过程,可惜水平有限,实在是写不出来,只好采用控制台程序了。采用控制台程序表述还是很简单的,算法也不复杂。这次实验让我认识到我在MFC方面基础还很薄弱,还需要多多练习,慢慢提升自己。

分治与递归算法实验

实验二分治与递归算法的应用 一、实验目的 1.掌握分治算法的基本思想(分-治-合)、技巧和效率分析方法。 2.熟练掌握用递归设计分治算法的基本步骤(基准与递归方程)。 3.学会利用分治算法解决实际问题。 二、实验内容 1.问题描述: 题目一:线性时间选择 给定n个元素和一个整数k,要求用O(n)时间找出这n个元素中第k小元素。 题目二:金块问题 老板有一袋金块(共n块,n是2的幂(n≥2)),最优秀的雇员得到其中最重的一块,最差的雇员得到其中最轻的一块。假设有一台比较重量的仪器,希望用最少的比较次数找出最重和最轻的金块。并对自己的程序进行复杂性分析。 【输入输出样例】 题目三:求最大两个数和最小两个数 利用分治法求一组数据中最大的两个数和最小的两个数。 2.数据输入:个人设定,由键盘输入。 3.要求: 1)上述题目任选其二。上机前,完成程序代码的编写

2)独立完成实验及实验报告 三、实验步骤 1.理解算法思想和问题要求; 2.编程实现题目要求; 3.上机输入和调试自己所编的程序; 4.验证分析实验结果; 5.整理出实验报告。

一.实验目的 二.问题描述 三.算法设计 包含:数据结构与核心算法的设计描述、函数调用及主函数设计、主要算法流程图等 1.金块问题:考虑到可能输入数据有一个或者两个这种情况, 所以解决问题时分三种情况考虑,然后通过函数调用来实现寻 找最大最小的数值。复杂性分析:当n是2的幂时,即对于 某个正整数k,n等于2的k次方,可以证明,任何以元素比 较为基础的找最大和最小元素的算法,其元素比较下界均为 [3n/2]-2次。因此,过程maxmin在这种意义上是最优的。 T(n)=2T(n/2)+2

实验一 递归与分治策略

实验一 递归与分治策略 一、实验目的 (1)理解递归与分治策略算法设计思想和方法; (2)培养学生的动手能力。 二、实验工具 (1)JDK1.8 (2)Eclipse IDE for Java EE Developers 三、实验题: 1、设n 个不同的整数排好序后存于T[0:n-1]中。若存在下标i ,n i <≤0,使得T[i]=i ,设计一个有效算法找到这个下标。要求算法在最坏情况下的计算时间为)(log n O 。 2、设子数组]1-:0[k a 和]1:[-n k a 已排好序10-≤≤n k 。试设计一个合并这两个子数组为排好序的数组]1:0[-n a 的算法,要求算法在最坏情况下的计算时间为)(n O ,且只用到)1(O 的辅助空间。 三、实验提示: 1、由于n 个整数是不同的,因此对任意0≤i <n-1 有T[i]≤T[i+1]-1。 (1) 对于0<i <n ,当T[i]>i 时,对任意的i ≤j ≤n-2 有T[j]≥T[i]+j-i>i+j-i=j 。 (2) 对于0<i <n,当T[i]<i 时,对任意的0≤j ≤i 有T[j]≤T[i] -i+j <i-i +j =j 。 由①和②可知,用二分搜索算法可以在)(log n O 时间内找到所要求的下标,伪代码如下: SEARCH(A,n) low <-- 0 high <-- n-1 while low < high do if A[middle] = middle then return middle if A[middle] < middle then low <-- middle + 1 else high <-- middle - 1

递归与分治策略应用基础

《算法设计与分析》实验报告实验一递归与分治策略应用基础 学号: 姓名: 班级:

一、实验目的 1、熟悉递归的概念和分治法。 2、对递归与分治算法时间空间复杂度分析,以及问题复杂性分析方法。递归与分治策略的问题类型,并能设计相应的分治策略算法。 二、实验内容 任务:以下题目要求应用递归与分治策略设计解决方案,本次实验成绩按百分制计,完成各小题的得分如下,每小题要求算法描述准确且程序运行正确。 1、求n个元素的全排。(30分) 算法分析:用递归的方法,先将n个数分成两个部分,然后将两个部分交换位子,然后再将这两个部分继续再分成四个部分,然后再将每个部分进行交换,然后就重复刚才的过程,直到不能再分为止,在这个过程中所产生的所有结果就是我们要求的全排列。 代码实现: #include int n = 0; void swap(int *a, int *b) { int m; m = *a; *a = *b;

*b = m; } void perm(int list[], int k, int m) { int i; if(k > 2) { for(i = 0; i <= 2; i++) printf("%d ", list[i]); printf("\n"); n++; } else { for(i = k; i <= 2; i++) { swap(&list[k], &list[i]); perm(list, k + 1, 4); swap(&list[k], &list[i]); } } }

int main() { int list[] = {1, 2, 3,4}; perm(list, 0, 2); printf("total:%d\n", n); return 0; } 2、解决一个2k*2k的特殊棋牌上的L型骨牌覆盖问题。(30分)算法分析:用分治策略,将大的棋盘分割为下一级的棋盘,直到不能再分为止,然后再将每一个小的棋盘填满,接着将一个一个小的棋盘再又合并成一个大的棋盘。 代码实现: #include "iostream" using namespace std; int board[1025][1025]; int tile = 1; //tr,tc棋盘左上角方格坐标, dr, dc特殊方格所在坐标, size 为行数

递归与分治相关实验及代码

实验目的: 掌握递归与分治算法的基本原理和应用以及软件实现。 实验准备: 1.在开始本实验之前,请回顾教科书的相关内容; 2.需要一台准备安装Windows XP Professional操作系统和装有VC++6.0的计算机。 实验内容及要求 内容:完成递归与分治常见实例的实现。 要求: 1,熟悉C++的相关语法和编制独立的子程序。 2,输入多组数据都能够给出正确的结果。 实验过程: 1.1问题分析 递归算法是把问题转化为规模缩小了的同类问题的子问题。然后递归调用函数(或过程)来表示问题的解。一般通过函数或子过程来实现,在函数或子过程的内部,直接或者间接地调用自己的算法。该算法具有以下特点:(1) 递归就是在过程或函数里调用自身。(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。该算法所体现的“重复”一般有三个要求:一是每次调用在规模上都有缩减; 二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备; 三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。 通常该算法的时间复杂度很大,所以要在适当的条件下使用。在该实验中,采用递归算法得到的算法有:阶乘,斐波拉齐,数的排列等。 分治算法的基本思想是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原问题性质相同,求出子问题的解,就可得到原问题的解。利用分治策略求解时,所需时间取决于分解后子问题的个数、子问题的规模大小等因素,而二分法,由于其划分的简单和均匀的特点,是经常采用的一种有效的方法,例如二分法检索。分治法解题的一般步骤: (1)分解,将要解决的问题划分成若干个规模较小的同类问题; (2)求解,当子问题划分得足够小时,用较简单的方法解决;

实验一分治与递归算法(Lu)

实验一分治与递归算法的应用 一、实验目的 1.掌握分治算法的基本思想(分-治-合)、技巧和效率分析方法。 2.熟练掌握用递归设计分治算法的基本步骤(基准与递归方程)。 3.学会利用分治算法解决实际问题。 二、实验内容 1.问题描述: 题目一:大整数乘法 用分治算法编程实现两个n位十进制大整数的乘法运算。 题目二:线性时间选择 给定n个元素和一个整数k,要求用O(n)时间找出这n个元素中第k小元素。 题目三:二分搜索算法 设a[0:n-1]是一个已排好序的数组。请改写二分搜索算法,使得当搜索元素x不在数组中时,返回小于x的最大元素的位置i和大于x的最小元素位置j。当搜索元素在数组中时,i和j相同,均为x在数组中的位置。并对自己的程序进行复杂性分析。 题目四:找最小向量问题 给定两个向量X=(x1,x2,… ,x n)和Y=(y1,y2,…,y n)。如果存在一个i,1≤i≤n,使得对于1≤j

题目五:找数 设n个不同的整数排好序后存于T[0:n-1]中。若存在一个下标0≤i

相关文档
相关文档 最新文档