文档库 最新最全的文档下载
当前位置:文档库 › Ackerman(n_m)函数的非递归算法

Ackerman(n_m)函数的非递归算法

Ackerman(n_m)函数的非递归算法
Ackerman(n_m)函数的非递归算法

题目:已知Ackerman函数的定义如下:

A(1,0)=2 n=1,m=0 Ackerman= A(0,m)=1 n=0,m>=0

A(n,0)=n+2 m=0,n>=2

A(A(n-1,m),m-1)m,n>=1

设计思想:

1.m,n成对出现,将其作为一个组合,通过栈保存。

2.然后分4部分处理(如题所示);

通过笔算研究规律:

I、当计算“m,n>=1”时,总是先n--(“m--”是到出口返回才计算的),直到算到“n=0,m>=0”的第一个出口;

II、此时进入第二段函数,开始返回计算,相当于A(n-1,m)置1,m--;

III、当m减到0时,如果n=1,进入第一段函数;

如果n>=2,进入第三段;

4

2 2

,

2 2 2

4

4

n=2,m=3 . . . A(A(1,3),2) (2, n=1,m=3 . . . A(A(0,3),2) (1,

n=0,m=3

.

.

. A(1,2)

n=1,m=2 . . . A(A(0,2),1)

(1, n=0,m=2 . . .

A(1,1) n=1,m=1

.

.

. A(A(0,1),0) (1, n=0,m=1 . . . A(1,0) 2

n=1,m=0 . . . 2 n=2,m=2 .

. . A(A(1,2),1) (2, n=2,m=1

. . .

A(A(1,1),0)

(2,

n=2,m=0

. . .

4

非递归算法:

#include

using namespace std;

class elem //栈中元素类型的定义{

public:

int n;

int m;

public:

elem(){}

elem(int x,int y)

{ n=x; m=y; }

void output()

{ cout<

};

class stack //栈的定义

{

private:

elem *e;

int msize;

int top;

public:

stack(int);

bool isempty();

bool isoverflow();

void push(elem);

int GetTop();

void pop();

elem GetElem(int);

void output();

};

stack::stack(int n) //构造函数

{

msize=n;

e=new elem[msize];

top=-1;

}

bool stack::isempty() //判断栈是否为空{

if(top==-1)

{

cout<<"该栈已空!"<<'\n';

return 1;

}

else

return 0;

}

bool stack::isoverflow() //判断栈是否溢出{

if(top==msize-1)

{

cout<<"该栈已满!"<<'\n';

return 1;

}

else

return 0;

}

void stack::push(elem x) //数据入栈

{

if(!isoverflow())

e[++top]=x;

}

int stack::GetTop() //获得top的值

{

return top;

}

void stack::pop() //数据出栈,不弹出元素。{

top--;

}

elem stack::GetElem(int top) //获得当前top值指向的数据元素{

return e[top];

}

void stack::output() //输出栈中的数据

{

for(int i=0;i<=top;i++)

e[i].output();

cout<<'\n';

}

int A(int n,int m) //Ackerman函数

{

elem u;

u.n=n; u.m=m;

stack s(20);

int t;

s.push(u);

while(s.GetTop()!=-1)

{

if(n<0 || m<0 ||(n>=3 && m>3) ||(n>=4 && m>=3))

//注意两个越界的条件(3,4)和(4,3){

cout<<'\n'<<"输入数据有误,请查证!"<<"\n\n";

exit(1);

}

if(u.n==1 && u.m==0) //用if/while皆可;

{

s.pop();

if(s.GetTop()==-1) //对"n=1,m=0"的情况特殊处理return 2;

u=s.GetElem(s.GetTop());

u.n=2;

u.m--;

s.pop();

s.push(u);

}

while(u.n==0 && u.m>=0) //用if/while皆可;

{

t=1;

s.pop();

u=s.GetElem(s.GetTop());

u.n=1;

u.m--;

s.pop();

s.push(u);

}

while(u.n>=2 && u.m==0) //必须用while

{

t=u.n+2;

s.pop();

u=s.GetElem(s.GetTop());

u.n=t;

u.m--;

s.pop();

s.push(u);

}

while(u.n>=1 && u.m>=1) //必须用while

{

u.n--;

s.push(u);

}

}

return t;

}

void main()

{

int n,m;

cout<<"请输入两个自然数,输入要求如下:"<<'\n';

cout<<"第一个数大于等于3时,第二个不能大于3;第一个大于等于4时,第二个不能大于等于3。"<<"\n\n";

cout<<"两个自然数,以空格为间隔:";

cin>>n>>m;

cout<<'\n'<<"A("<

此函数部分执行结果统计:

A(0,0)=1; A(0,1)=1; A(0,2)=1; A(0,3)=1; A(1,0)=2; A(1,1)=2; A(1,2)=2; A(1,3)=2; A(2,0)=4; A(2,1)=4; A(2,2)=4; A(2,3)=4; A(3,0)=5; A(3,1)=6; A(3,2)=8; A(3,3)=16; A(3,4)=∞

A(4,0)=6; A(4,1)=8; A(4,2)=16;

A(4,3)=∞

A(5,0)=7; A(5,1)=10; A(5,2)=32;

A(5,3)=∞

执行结果如下:

二○一三年三月二十三日星期六9

格林函数与输运

《多粒子物理学》读书报告:格林函数与输运 内容提要:1概述; 2单粒子性质的格林函数表述; 3用格林函数推导迁移率中1-α项 1概述 1. 1金属中电子输运特性 对于金属 * m e τμ- =, μσ0en -=, τ是输运驰豫时间,它的物理意义是处在某动量本征态的电子的平均寿命,即0=t 时一个处于某动量本征态的电子在τ=t 时完全失去了对其原有动量的记 忆。输运驰豫时间包括各种相互作用的贡献主要有杂质散射﹑电子-声子相互作用﹑电子-电子相互作用等等: ∑=--i i 11ττ 即输运驰豫时间由各种机构中i τ最小的决定。 绝对零度时,纯金属晶体中电子不受散射,具有无穷大电导。T >0时实际金属的电阻是由电子受到杂质和晶格振动的散射引起的。在室温时,典型金属的电阻率约为10-8Ω.m ,随着温度降低到室温以下,电阻近似线性地减小(图1,see, p.131 in Ref.[1]),在低温时水平地达到一定值。低温时的电阻率与试样的纯度密切相关,对于高纯度的退火单晶体,约可以达到室温电阻率的10-4倍。不纯试样中的附加电阻在整个温度范围内近似地与温度无关。这个事实叫做马赛厄司定则(Mathiessen rule ,又翻译为马提生定则(1862))。这个附加电阻是由于杂质引起的电子散射,在低温下它构成电阻的主要部分。杂质散射电阻与温度无关的事实暗示出可动电子的浓度与温度无关,这与半导体中电子浓度与温度呈指数函数关系大不一样。声子散射电阻依赖于温度,在高温时可变得很大。这两部分电阻具有可加性,因此可分别处理。 上述金属中的杂质不含磁性杂质。磁性杂质的散射将导致低温下电阻值的对数上升,称为近藤(Kondo)效应。 1. 2半导体输运特性 半导体中的散射仍可分为电离杂质和晶格振动的散射两大类。晶格振动的散射又分为声学波和光学波散射两种。声学波通过两种方式散射电子:引起密度变化从而产生形变势(声学声子形变势散射);在没有反演中心的极性晶体中引起压电极化(压电散射,长声学波明显)。光学波也通过两种方式散射电子:二种不

递归算法和非递归算法的区别和转换

递归算法向非递归算法转换 递归算法实际上是一种分而治之的方法,它把复杂问题分解为简单问题来求解。对于某些复杂问题(例如hanio塔问题),递归算法是一种自然且合乎逻辑的解决问题的方式,但是递归算法的执行效率通常比较差。因此,在求解某些问题时,常采用递归算法来分析问题,用非递归算法来求解问题;另外,有些程序设计语言不支持递归,这就需要把递归算法转换为非递归算法。 将递归算法转换为非递归算法有两种方法,一种是直接求值,不需要回溯;另一种是不能直接求值,需要回溯。前者使用一些变量保存中间结果,称为直接转换法;后者使用栈保存中间结果,称为间接转换法,下面分别讨论这两种方法。 1. 直接转换法 直接转换法通常用来消除尾递归和单向递归,将递归结构用循环结构来替代。 尾递归是指在递归算法中,递归调用语句只有一个,而且是处在算法的最后。例如求阶乘的递归算法: long fact(int n) { if (n==0) return 1; else return n*fact(n-1); } 当递归调用返回时,是返回到上一层递归调用的下一条语句,而这个返回位置正好是算法的结束处,所以,不必利用栈来保存返回信息。对于尾递归形式的递归算法,可以利用循环结构来替代。例如求阶乘的递归算法可以写成如下循环结构的非递归算法: long fact(int n) { int s=0; for (int i=1; i<=n;i++) s=s*i; //用s保存中间结果 return s; } 单向递归是指递归算法中虽然有多处递归调用语句,但各递归调用语句的参数之间没有关系,并且这些递归调用语句都处在递归算法的最后。显然,尾递归是单向递归的特例。例如求斐波那契数列的递归算法如下: int f(int n) {

树的遍历(递归和非递归)

二叉树的遍历 一、设计思想 二叉树的遍历分为三种方式,分别是先序遍历,中序遍历和后序遍历。先序遍历实现的顺序是:根左右,中序遍历实现的是:左根右,后续遍历实现的是:左右根。根据不同的算法分,又分为递归遍历和非递归遍历。 递归算法: 1.先序遍历:先序遍历就是首先判断根结点是否为空,为空则停止遍历,不为空则将左子作为新的根结点重新进行上述判断,左子遍历结束后,再将右子作为根结点判断,直至结束。到达每一个结点时,打印该结点数据,即得先序遍历结果。 2.中序遍历:中序遍历是首先判断该结点是否为空,为空则结束,不为空则将左子作为根结点再进行判断,打印左子,然后打印二叉树的根结点,最后再将右子作为参数进行判断,打印右子,直至结束。 3.后续遍历:指针到达一个结点时,判断该结点是否为空,为空则停止遍历,不为空则将左子作为新的结点参数进行判断,打印左子。左子判断完成后,将右子作为结点参数传入判断,打印右子。左右子判断完成后打印根结点。 非递归算法: 1.先序遍历:首先建立一个栈,当指针到达根结点时,打印根结点,判断根结点是否有左子和右子。有左子和右子的话就打印左子同时将右子入栈,将左子作为新的根结点进行判断,方法同上。若当前结点没有左子,则直接将右子打印,同时将右子作为新的根结点判断。若当前结点没有右子,则打印左子,同时将左子作为新的根结点判断。若当前结点既没有左子也没有右子,则当前结点为叶子结点,此时将从栈中出栈一个元素,作为当前的根结点,打印结点元素,同时将当前结点同样按上述方法判断,依次进行。直至当前结点的左右子都为

空,且栈为空时,遍历结束。 2.中序遍历:首先建立一个栈,定义一个常量flag(flag为0或者1),用flag记录结点的左子是否去过,没有去过为0,去过为1,默认为0.首先将指针指向根结点,将根结点入栈,然后将指针指向左子,左子作为新的结点,将新结点入栈,然后再将指针指向当前结点的左子,直至左子为空,则指针返回,flag置1,出栈一个元素,作为当前结点,打印该结点,然后判断flag,flag为1则将指针指向当前结点右子,将右子作为新的结点,结点入栈,再次进行上面的判断,直至当前结点右子也为空,则再出栈一个元素作为当前结点,一直到结束,使得当前结点右子为空,且栈空,遍历结束。 3.后续遍历:首先建立两个栈,然后定义两个常量。第一个为status,取值为0,1,2.0代表左右子都没有去过,1代表去过左子,2,代表左右子都去过,默认为0。第二个常量为flag,取值为0或者1,0代表进左栈,1代表进右栈。初始时指针指向根结点,判断根结点是否有左子,有左子则,将根结点入左栈,status置0,flag置0,若没有左子则判断结点有没有右子,有右子就把结点入右栈,status置0,flag置1,若左右子都没有,则打印该结点,并将指针指向空,此时判断flag,若flag为0,则从左栈出栈一个元素作为当前结点,重新判断;若flag为1则从右栈出栈一个元素作为当前结点,重新判断左右子是否去过,若status为1,则判断该结点有没有右子,若有右子,则将该结点入右栈,status置1,flag置1,若没有右子,则打印当前结点,并将指针置空,然后再次判断flag。若当前结点status为2,且栈为空,则遍历结束。若指针指向了左子,则将左子作为当前结点,判断其左右子情况,按上述方法处理,直至遍历结束。 二、算法流程图

汉诺塔非递归算法C语言实现

汉诺塔非递归算法C语言实现 #include #include #define CSZL 10 #define FPZL 10 typedef struct hanoi { int n; char x,y,z; }hanoi; typedef struct Stack { hanoi *base,*top; int stacksize; }Stack; int InitStack(Stack *S) { S->base=(hanoi *)malloc(CSZL*sizeof(hanoi)); if(!S->base) return 0; S->top=S->base; S->stacksize=CSZL; return 1; } int PushStack(Stack *S,int n,char x,char y,char z) { if(S->top-S->base==S->stacksize) { S->base=(hanoi *)realloc(S->base,(S->stacksize+FPZL)*sizeof(hanoi)); if(!S->base) return 0; S->top=S->base+S->stacksize; S->stacksize+=FPZL; } S->top->n=n; S->top->x=x; S->top->y=y; S->top->z=z; S->top++; return 1; } int PopStack(Stack *S,int *n,char *x,char *y,char *z) { if(S->top==S->base)

n!非递归算法的设计与实现

n!非递归算法的设计与实现 1 课题描述 尽管递归算法是一种自然且合乎逻辑的解决问题的方式,但递归算法的执行效率通常比较差。因此在求解许多问题时常采用递归算法来分析问题,用非递归方法来求解问题;另外一些程序不支持递归算法来求解问题,所以我们都会用非递归算法来求解问题。 本次课程设计主要内容是:用非递归算法实现n!的计算,由于计算机中数据的存储范围有限,而又要求出尽可能大的n的阶乘的值,用数组构造n的运算结果的存储结构,用栈的存储方式,最后输出n!的运算结果。 本次课程设计的目的是:通过本次课程设计,可以使大家了解缓存中数据的存储范围,提高自学能力,增强团队合作意识。

2 需求分析 本次n!非递归算法的课程设计中主要用到的知识有:数组、函数、栈,选择条件中的结构语句(if…else),和循环结构语句中的语句while()语句、do…while()语句和for()语句,选择语句if的运用。 对n!的非递归的算法,主要是运用非递归的算法实现n的阶乘。 限制条件: (1).要求的n必须是整数; (2). n的范围; (3). 数据类型和表数范围。

递归和非递归算法是相通的,递归是一种直接或间接调用自身的算法,而非递归不调用自身函数递推采用的是递归和归并法,而非递推只采用递归法。递推法一般容易溢出,所以一般都采用递推法分析,而用非递推法设计程序。 将n定义为float型,便于查看n是否为整数; 本次试验分为两个模块: (1).当n小于都等于12时,实现阶乘的模块m(n): 直接用sum*=i;实现求n的阶乘,相对简单,容易就算。 (2).当n大于12时,如果用long型结果就会溢出,所以实现阶乘需调用的模块f(n): 采用数组存放计算的结果,用队列输出运行结果。由于计算结果较大,将结果除以数组最大存储位数,将高位结果存放在数组的起始地址上,将低位的结果存放在数组的末端地址上,最后采用队列输出运行结果。 (3).模块调用关系如图3.1所示 图3.1 模块调用图

二叉树遍历C语言(递归,非递归)六种算法

数据结构(双语) ——项目文档报告用两种方式实现表达式自动计算 专业: 班级: 指导教师: 姓名: 学号:

目录 一、设计思想 (01) 二、算法流程图 (02) 三、源代码 (04) 四、运行结果 (11) 五、遇到的问题及解决 (11) 六、心得体会 (12)

一、设计思想 二叉树的遍历分为三种方式,分别是先序遍历,中序遍历和后序遍历。先序遍历实现的顺序是:根左右,中序遍历实现的是:左根右,后续遍历实现的是:左右根。根据不同的算法分,又分为递归遍历和非递归遍历。 递归算法: 1.先序遍历:先序遍历就是首先判断根结点是否为空,为空则停止遍历,不为空则将左子作为新的根结点重新进行上述判断,左子遍历结束后,再将右子作为根结点判断,直至结束。到达每一个结点时,打印该结点数据,即得先序遍历结果。 2.中序遍历:中序遍历是首先判断该结点是否为空,为空则结束,不为空则将左子作为根结点再进行判断,打印左子,然后打印二叉树的根结点,最后再将右子作为参数进行判断,打印右子,直至结束。 3.后续遍历:指针到达一个结点时,判断该结点是否为空,为空则停止遍历,不为空则将左子作为新的结点参数进行判断,打印左子。左子判断完成后,将右子作为结点参数传入判断,打印右子。左右子判断完成后打印根结点。 非递归算法: 1.先序遍历:首先建立一个栈,当指针到达根结点时,打印根结点,判断根结点是否有左子和右子。有左子和右子的话就打印左子同时将右子入栈,将左子作为新的根结点进行判断,方法同上。若当前结点没有左子,则直接将右子打印,同时将右子作为新的根结点判断。若当前结点没有右子,则打印左子,同时将左子作为新的根结点判断。若当前结点既没有左子也没有右子,则当前结点为叶子结点,此时将从栈中出栈一个元素,作为当前的根结点,打印结点元素,同时将当前结点同样按上述方法判断,依次进行。直至当前结点的左右子都为空,且栈为空时,遍历结束。 2.中序遍历:首先建立一个栈,定义一个常量flag(flag为0或者1),用flag记录结点的左子是否去过,没有去过为0,去过为1,默认为0.首先将指针指向根结点,将根结点入栈,然后将指针指向左子,左子作为新的结点,将新结点入栈,然后再将指针指向当前结点的左子,直至左子为空,则指针返回,flag置1,出栈一个元素,作为当前结点,打印该结点,然后判断flag,flag为1则将指针指向当前结点右子,将右子作为新的结点,结点入栈,再次进行上面的判断,直至当前结点右子也为空,则再出栈一个元素作为当前结点,一直到结束,使得当前结点右子为空,且栈空,遍历结束。 3.后续遍历:首先建立两个栈,然后定义两个常量。第一个为status,取值为0,1,2.0代表左右子都没有去过,1代表去过左子,2,代表左右子都去过,默认为0。第二个常量为flag,取值为0或者1,0代表进左栈,1代表进右栈。初始时指针指向根结点,判断根结点是否有左子,有左子则,将根结点入左栈,status置0,flag置0,若没有左子则判断结点有没有右子,有右子就把结点入右栈,status置0,flag置1,若左右子都没有,则打印该结点,并将指针指向空,此时判断flag,若flag为0,则从左栈出栈一个元素作为当前结点,重新判断;若flag为1则从右栈出栈一个元素作为当前结点,重新判断左右子是否去过,若status 为1,则判断该结点有没有右子,若有右子,则将该结点入右栈,status置1,flag置1,若没有右子,则打印当前结点,并将指针置空,然后再次判断flag。若当前结点status为2,且栈为空,则遍历结束。若指针指向了左子,则将左子作为当前结点,判断其左右子情况,按上述方法处理,直至遍历结束。

汉诺塔问题的非递归算法分析

汉诺塔递归与非递归算法研究 作者1,作者2,作者33 (陕西师范大学计算机科学学院,陕西西安 710062) 摘要: 摘要内容(包括目的、方法、结果和结论四要素) 摘要又称概要,内容提要.摘要是以提供文献内容梗概为目的,不加评论和补充解释,简明,确切地记述文献重要内容的短文.其基本要素包括研究目的,方法,结果和结论.具体地讲就是研究工作的主要对象和范围,采用的手段和方法,得出的结果和重要的结论,有时也包括具有情报价值的其它重要的信息.摘要应具有独立性和自明性,并且拥有与文献同等量的主要信息,即不阅读全文,就能获得必要的信息. 关键词:关键词1; 关键词2;关键词3;……(一般可选3~8个关键词,用中文表示,不用英文 Title 如:XIN Ming-ming , XIN Ming (1.Dept. of ****, University, City Province Zip C ode, China;2.Dept. of ****, University, City Province Zip C ode, China;3.Dept. of ****, University, City Province Zip C ode, China) Abstract: abstract(第三人称叙述,尽量使用简单句;介绍作者工作(目的、方法、结果)用过去时,简述作者结论用一般现在时) Key words: keyword1;keyword2; keyword3;……(与中文关键词对应,字母小写(缩略词除外)); 正文部分用小5号宋体字,分两栏排,其中图表宽度不超过8cm.。设置为A4页面 1 引言(一级标题四号黑体加粗) 这个问题当时老和尚和众僧们,经过计算后,预言当所有的盘子都从基柱A移到基座B上时,世界就将在一声霹雳中消灭,而梵塔、庙宇和众生也都将同归于尽。其实,不管这个传说的可信度有多大,如果考虑把64个盘子,由一个塔柱上移到另一根塔柱上,并且始终保持上小下大的顺序。假设有n个盘子,移动次数是f(n).显然f(1)=1,f(2)=3,f(3)=7,且f(k+1)=2*f(k)+1。此后不难证明f(n)=2n-1。n=64时, f(64)= 2^64-1=18446744073709551615 假如每秒钟一次,共需多长时间呢?一年大约有 31536926 秒,计算表明移完这些金片需要5800多亿年,比地球寿命还要长,事实上,世界、梵塔、庙宇和众生都早已经灰飞烟灭。 对传统的汉诺塔问题,目前还有不少的学者继续研究它的非递归解法,本文通过对递归算法的研究……. 提示:(1)可以定义问题的规模n,如盘子的数量;(2)塔柱的数量(目前有部分理论可以支撑,不妨用计算机实现)分析规模的变化与算法的复杂度比较。(3)可以对经典的汉诺塔问题条件放松、加宽,如在经典的汉诺塔问题中大盘只能在小盘下面,放松其他条件可以定义相邻两个盘子必须满足大盘只能在小盘下面。其它盘子不作要求。 2 算法设计 2.1 汉诺塔递归算法描述(二级标题小五黑体加粗) 用人类的大脑直接去解3,4或5个盘子的汉诺塔问题还可以,但是随着盘子个数的增多,问题的规模变的越来越大。这样的问题就难以完成,更不用说吧问题抽象成循环的机器操作。所以类似的问题可用递归算法来求解。下面n个盘的汉

先序遍历的非递归算法 C语言

先序遍历的非递归算法 #include #include #define MS 10 struct BTreeNode { char data; struct BTreeNode * left; struct BTreeNode * right; }; void InitBTree(struct BTreeNode * * BT) { * BT=NULL; } void CreatBTree(struct BTreeNode * * BT,char * a) { struct BTreeNode * p; struct BTreeNode * s[MS]; int top=-1; int k; int i=0; * BT=NULL; while(a[i]) { switch(a[i]) { case ' ':break; case '(': if(top==MS-1) { printf("栈空间太小,需增加MS的值!\n"); exit(1); } top++;s[top]=p;k=1; break; case ')': if(top==-1) {

printf("二叉树广义表字符串有错!\n"); exit(1); } top--;break; case ',' : k=2;break; default : if((a[i]>='a'&&a[i]<='z')||(a[i]>='A'&&a[i]<='Z')) { p=malloc(sizeof(struct BTreeNode)); p->data=a[i];p->left=p->right=NULL; if(* BT==NULL) * BT=p; else { if(k==1) s[top]->left=p; else s[top]->right=p; } } else {printf("二叉树广义表字符串有错!\n");exit(1);} } i++; } } void Preorder(struct BTreeNode * BT) { struct BTreeNode * s[10]; int top=-1; struct BTreeNode * p=BT; printf("先序遍历结点的访问序列为:\n"); while(top!=-1||p!=NULL) { while(p!=NULL) { top++; s[top]=p; printf("%c",p->data); p=p->left; } if(top!=-1) {

汉诺塔问题非递归算法详解

Make By Mr.Cai 思路介绍: 首先,可证明,当盘子的个数为n 时,移动的次数应等于2^n - 1。 然后,把三根桩子按一定顺序排成品字型(如:C ..B .A ),再把所有的圆盘按至上而下是从小到大的顺序放在桩子A 上。 接着,根据圆盘的数量确定桩子的排放顺序: 若n 为偶数,按顺时针方向依次摆放C ..B .A ; 若n 为奇数,按顺时针方向依次摆放B ..C .A 。 最后,进行以下步骤即可: (1)首先,按顺时针方向把圆盘1从现在的桩子移动到下一根桩子,即当n 为偶数时,若圆盘1在桩子A ,则把它移动到B ;若圆盘1在桩子B ,则把它移动到C ;若圆盘1在桩子C ,则把它移动到A 。 (2)接着,把另外两根桩子上可以移动的圆盘移动到新的桩子上。 即把非空桩子上的圆盘移动到空桩子上,当两根桩子都非空时,移动较小的圆盘。 (3)重复(1)、(2)操作直至移动次数为2^n - 1。 #include #include using namespace std; #define Cap 64 class Stake //表示每桩子上的情况 { public: Stake(int name,int n) { this->name=name; top=0; s[top]=n+1;/*假设桩子最底部有第n+1个盘子,即s[0]=n+1,这样方便下面进行操作*/ } int Top()//获取栈顶元素 { return s[top];//栈顶 } int Pop()//出栈 { return s[top--];

} void Push(int top)//进栈 { s[++this->top]=top; } void setNext(Stake *p) { next=p; } Stake *getNext()//获取下一个对象的地址 { return next; } int getName()//获取当前桩子的编号 { return name; } private: int s[Cap+1];//表示每根桩子放盘子的最大容量 int top,name; Stake *next; }; void main() { int n; void hanoi(int,int,int,int); cout<<"请输入盘子的数量:"; cin>>n; if(n<1) cout<<"输入的盘子数量错误!!!"<

非递归方式建树并按任一种非递归遍历次序输出二叉树中

//非递归方式建树,并按任一种非递归遍历次序输出二叉树中的所有结点; #include #include #include #define MaxSize 50 typedef char ElemType; typedef struct TNode{ ElemType data; struct TNode *lchild,*rchild; }BTree; //------------------------------------------------------------------------------ ElemType str[]="A(B(C(D,E(F,G(,H))),I(J,K(L))),M)"; //"A(B(D,E(G,H(I))),C(F))"; //------------------------------------------------------------------------------ void CreateBTree(BTree **T,ElemType *Str); //非递归建树; void TraverseBTree(BTree *T); //选择非递归算法的遍历方式; void PreOrderUnrec(BTree *T); //先序遍历非递归算法; void InOrderUnrec(BTree *T); //中序遍历非递归算法; void PostOrderUnrec(BTree *T); //后序遍历非递归算法; //------------------------------------------------------------------------------ int main(void) { BTree *T = NULL; printf("\n二叉树的广义表格式为:\n\t"); puts(str); CreateBTree(&T,str); TraverseBTree(T); system("pause"); return 0; } //------------------------------------------------------------------------------ void CreateBTree(BTree **T,ElemType *Str) { //按二叉树广义表建立对应的二叉树存储结构; BTree *p = NULL,*Stack[MaxSize];//数组为存储树根结点指针的栈,p为指向树结点的指针; int top = -1; //top为Stack栈的栈顶指针; char flag; //flag为处理结点的左子树(L)和右子树(R)的标记; *T = NULL; while(*Str) { if (*Str == '(') {Stack[++top] = p;flag = 'L';} //入栈; else if(*Str == ')') --top; //出栈; else if(*Str == ',') flag = 'R'; else { if(!(p = (BTree *)malloc(sizeof(BTree)))) exit (1); p->data = *Str; p->lchild = p->rchild = NULL; //初始化新结点;

马踏棋盘非递归算法

#include struct point { int x,y;//马的位置 int dir;//这一次马行走的方向 }; struct stack { point p[64];//存储马的位置,方便回溯 }; int board [8][8]; int Htry1[8]={-2,-1,1,2,2,1,-1,-2}; int Htry2[8]={1,2,2,1,-1,-2,-2,-1}; bool chech[8][8]={0};//标记位置是否已经被占用 int main() { int i,j; int top=0; int z; cout<<"请输入马的初始位置"; cin>>i; cin>>j; stack sta; sta.p[top].x=i; sta.p[top].y=j; board [i][j]=top; chech [i][j]=true; int nx; int ny; for(int u=0;u<64;u++) sta.p[u].dir=0;//把每个结点的dir清零 for(z=0;;) { if(sta.p[top].x+Htry1[z]>=0&&sta.p[top].x+Htry1[z]<8&& sta.p[top].y+Htry2[z]>=0&&sta.p[top].y+Htry2[z]<8&& !chech [sta.p[top].x+Htry1[z]][sta.p[top].y+Htry2[z]]//检查要走的下个位置是否可行 ) { nx=sta.p[top].x+Htry1[z];

ny=sta.p[top].y+Htry2[z]; sta.p[top].dir=z; top++; sta.p[top].x=nx; sta.p[top].y=ny; board [nx][ny]=top; chech [nx][ny]=true; z=-1; } else if(z==7)//如果不可行,而且是最好一次检查 { chech [sta.p[top].x][sta.p[top].y]=false; top--; while(1) { z=sta.p[top].dir; if(z!=7) break; else { chech [sta.p[top].x][sta.p[top].y]=false; top--; } } } if(top==-1||top==63)break;//如果回溯到-1,或者栈满,则退出循环 z++; } for(i=0;i<8;i++) { for(j=0;j<8;j++) cout<

后序遍历的非递归算法.doc

第六章树二叉树 后序遍历的非递归算法。在对二叉树进行后序遍历的过程中,当指针p 指向某一个结点时,不能马上对它进行访问,而要先遍历它的左子树,因而要将此结点的地址进栈保存。当其左子树遍历完毕之后,再次搜索到该结点时(该结点的地址通过退栈得到) ,还不能对它进行访问,还需要遍历它的右子树,所以,再一次将此结点的地址进栈保存。为了区别同一结点的两次进栈,引入一个标志变量nae,有0 表示该结点暂不访问 1 表示该结点可以访问标志flag 的值随同进栈结点的地址一起进栈和出栈。因此,算法中设置两个空间足够的堆栈,其中, STACKlCM] 存放进栈结点的地址, STACK2[M] 存放相应的标志n 昭的值, 两个堆栈使用同一栈顶指针top , top 的初值为— 1 。 具体算法如下: #defineH 100 /?定义二叉树中结点最大数目。/ voidPOSTOiRDER(BTREET) { / *T 为二叉树根结点所在链结点的地址。/ BTREESTACKl[H] , p=T ;intSTACK2[M] , flag,top= —1;if(T!=NULL) d0{ while(p!=NULL){ STACK/[++top]=p ; /?当前p所指结点的地址进栈?/ STACK2[top]= 0 ; /,标志0 进栈?/ p=p->lchild ;/?将p 移到其左孩子结点x/ } p=STACKl[top) ;flag=STACK2[top--] ;if(flag==0){ STACKl[++top]=p ; /,当前p所指结点的地址进栈。/ STACK2[toP]=1 ; /?标志1 进栈?/ p=p->rchild ; /x将p移到其右孩子结点o/ } else{ VISIT(p) ; /x访问当前p所指的结点x/ p=NULL ; } }while(p!=NULLtttop!=-1) ; } 不难分析,上述算法的时间复杂度同样为O(n) 7.6.3 二叉树的线索化算法 对--X 树的线索化,就是把二叉树的二叉链表存储结构中结点的所有空指针域改造成指向某结点在某种遍历序列中的直接前驱或直接后继的过程, 因此, 二叉树的线索化过程只能 在对二叉树的遍历过程中进行。 下面给出二叉树的中序线索化的递归算法。算法中设有指针pre,用来指向中序遍历过 程中当前访问的结点的直接前驱结点,pre的初值为头结点的指针;T初始时指向头结点, 但在算法执行过程中,T总是指向当前访问的结点。voldlNTHREAD(TBTREET) { TBTREE pre ; if(T!=Null){ INTHREAD(T —>lchild); if(T —>rchild==NULL)

用递归非递归两种方法遍历二叉树

数据结构(双语) ——项目文档报告 用递归、非递归两种方法遍历二叉树 专业:计算机科学与技术 班级: 指导教师: 姓名:

学号: 目录 一、设计思想 (03) 二、算法流程图 (04) 三、源代码 (06) 四、运行结果 (12) 五、遇到的问题及解决 (14) 六、心得体会 (15)

一、设计思想 1.递归: (1)主函数main()主程序要包括:定义的二叉树T、建树函数、先序遍历函数、中序遍历函数、后序遍历函数。 (2)建树函数定义一个输入的数是字符型的,当ch为空时,T就为空值,否则的话就分配空间给T,T就指向它的结点,然后左指针域指向左孩子,右指针指向右孩子,若还有,继续调用,依次循环下去,直到ch遇到空时,结束。最后要返回建立的二叉树T。 (3)先序遍历函数根据先序遍历规则,当T为非空时,先输出结点处的数据,指针指向左、右孩子,依次进行下去。 (4) 中序遍历函数根据中序遍历规则,当T为非空时,先左指针指向左孩子数据,然后输出结点处的数据,再右指针指向右孩子,依次进行下去。 (5)后序遍历函数根据后序遍历规则,当T为非空时,先右指针指向右孩子,然后左指针指向左孩子,最后输出结点处的数据,依次进行下去。 2.非递归: (1)跟递归遍历二叉树的前提一样,首先应该创建一个二叉树,同样使用先序递归的方式创建二叉树。 (2)然后是中序,先序,后序非递归遍历二叉树。 (3)中序非递归遍历二叉树的思想是:首先是根节点压栈,当根节点的左子树不是空的时候,左子树压栈。直到左子树为空的时候,不再压栈。将栈顶元素出栈,访问栈顶元素,并将栈顶的右子树进栈。当右子树的左子树不是空的时候,左子树一直进栈,直到左子树为空,则不再进栈。重复上面的操作,直到栈空的时候。 (4)先序非递归遍历二叉树的思想是:首先是根节点进栈,然后当栈不为空的时候,将栈顶元素出栈,然后访问。同时将出栈元素的右子树进栈,左子树进栈。重复上面的操作,直到栈为空。 (5)后序非递归遍历二叉树的思想:首先是根节点进栈,当根节点的左子树不为空的时候,左子树进栈,直到左为空的时候,左子树不再进栈。指针指向的是右子树,当右子树为空的时候,直接访问根节点。当右子树不为空的时候,则右子树的指针进栈,当右子树的左子树不为空的时候,则左也进栈,直到左为空。重复上面的操作,直到栈为空的时候,则遍历树完成。

非平衡格林函数和介观输运理论2

3)、Kondo效应: W.G. van der Wiel, et.al. Science 289, 2105 (2000)

非平衡格林函数和介观输运理论 一、Green函数的定义和一些基本关系: 二、关于Green函数的三个主要方程: 三、电流与Green函数的关系: 四、几个用Green函数计算电流的例子: 参考书: 1、H. Haug, A.-P. Jauho, Quantum Kinetics in transport and optics of semiconductors, Springer-Werlag, 1998 2、G.D. Mahan, Many-Particle Physics.

非平衡格林函数和介观输运理论 一、Green函数的定义和一些基本关系: 二、关于Green函数的三个主要方程: 三、电流与Green函数的关系: 四、几个用Green函数计算电流的例子: 参考书: 1、H. Haug, A.-P. Jauho, Quantum Kinetics in transport and optics of semiconductors, Springer-Werlag, 1998 2、G.D. Mahan, Many-Particle Physics.

二、关于Green 函数的三个主要方程: 1、运动方程; 2、Dyson 方程; 1)、把H 分成:2)、从海森伯表象->相互作用表象; 3)、wick 定理展开,费马图表示; 4)、连接图与非连接图 可约自能与不可约自能; 5)、得到Dyson 方程 3、Keldysh 方程; 0I H H H =+

用递归和非递归算法实现二叉树的三种遍历

○A ○C ○D ○B ○E○F G 《数据结构与算法》实验报告三 ——二叉树的操作与应用 一.实验目的 熟悉二叉链表存储结构的特征,掌握二叉树遍历操作及其应用 二. 实验要求(题目) 说明:以下题目中(一)为全体必做,(二)(三)任选其一完成 (一)从键盘输入二叉树的扩展先序遍历序列,建立二叉树的二叉链表存储结构;(二)分别用递归和非递归算法实现二叉树的三种遍历; (三)模拟WindowsXP资源管理器中的目录管理方式,模拟实际创建目录结构,并以二叉链表形式存储,按照凹入表形式打印目录结构(以扩展先序遍历序列输入建立二叉链表结构),如下图所示: (基本要求:限定目录名为单字符;扩展:允许目录名是多字符组合) 三. 分工说明 一起编写、探讨流程图,根据流程图分工编写算法,共同讨论修改,最后上机调试修改。 四. 概要设计 实现算法,需要链表的抽象数据类型: ADT Binarytree { 数据对象:D是具有相同特性的数据元素的集合 数据关系R: 若D为空集,则R为空集,称binarytree为空二叉树;

若D不为空集,则R为{H},H是如下二元关系; (1)在D中存在唯一的称为根的数据元素root,它在关系H下无前驱; (2)若D-{root}不为空,则存在D-{root}={D1,Dr},且D1∩Dr为空集; (3)若D1不为空,则D1中存在唯一的元素x1,∈H,且存在D1上的关系H1是H的子集;若Dr不为空集,则Dr中存在唯一的元素 Xr,∈H,且存在Dr上的关系Hr为H的子集;H={,,H1,Hr}; (4) (D1,{H1})是一颗符合本定义的二叉树,称为根的左子树,(Dr,{Hr}) 是一颗符合本定义的二叉树,称为根的右子树。 基本操作: Creatbitree(&S,definition) 初始条件:definition给出二叉树S的定义 操作结果:按definition构造二叉树S counter(T) 初始条件:二叉树T已经存在 操作结果:返回二叉树的总的结点数 onecount(T) 初始条件:二叉树T已经存在 操作结果:返回二叉树单分支的节点数 Clearbintree(S) 初始条件:二叉树S已经存在 操作结果:将二叉树S清为空树 Bitreeempty(S) 初始条件:二叉树S已经存在 操作结果:若S为空二叉树,则返回TRUE,否则返回FALSE Bitreedepth(S,&e) 初始条件:二叉树S已经存在 操作结果:返回S的深度 Parent(S) 初始条件:二叉树S已经存在,e是S中的某个结点 操作结果:若e是T的非根结点,则返回它的双亲,否则返回空Preordertraverse(S) 初始条件:二叉树S已经存在,Visit是对结点操作的应用函数。 操作结果:先序遍历S,对每个结点调用函数visit一次且仅一次。 一旦visit失败,则操作失败。 Inordertraverse (S,&e) 初始条件:二叉树S已经存在,Visit是对结点操作的应用函数。

算法设计与分析习题

《算法设计与分析》习题 第一章算法引论 1、算法的定义? 答:算法是指在解决问题时,按照某种机械步骤一定可以得到问题结果的处理过程。 通俗讲,算法:就是解决问题的方法或过程。 2、算法的特征? 答:1)算法有零个或多个输入;2)算法有一个或多个输出; 3)确定性;4)有穷性 3、算法的描述方法有几种? 答:自然语言、图形、伪代码、计算机程序设计语言 4、衡量算法的优劣从哪几个方面? 答:(1) 算法实现所耗费的时间(时间复杂度); (2) 算法实现所所耗费的存储空间(空间复杂度); (3) 算法应易于理解,易于编码,易于调试等等。 5、时间复杂度、空间复杂度定义? 答:指的是算法在运行过程中所需要的资源(时间、空间)多少。 6、时间复杂度计算: {i=1; while(i<=n) i=i*2; } 答:语句①执行次数1次, 语句②③执行次数f(n), 2^f(n)<=n,则f(n) <=log2n; 算法执行时间: T(n)= 2log2n +1 时间复杂度:记为O(log2n) ; 7.递归算法的特点? 答:①每个递归函数都必须有非递归定义的初值;否则,递归函数无法计算;(递归终止条件) ②递归中用较小自变量函数值来表达较大自变量函数值;(递归方程式) 8、算法设计中常用的算法设计策略? 答:①蛮力法;②倒推法;③循环与递归;④分治法; ⑤动态规划法;⑥贪心法;⑦回溯法;⑧分治限界法 9、设计算法: 递归法:汉诺塔问题?兔子序列(上楼梯问题)? 整数划分问题? 蛮力法:百鸡百钱问题? 倒推法:穿越沙漠问题?

答:算法如下: (1) 递归法 ● 汉诺塔问题 void hanoi(int n, int a, int b, int c) {if (n > 0) { hanoi(n-1, a, c, b); move(a,b); hanoi(n-1, c, b, a); } } ● 兔子序列(fibonaci 数列 ) 递归实现: Int F(int n) { if(n<=2) return 1; else return F(n-1)+ F(n-2); } ● 上楼梯问题 Int F(int n) { if(n=1) return 1 if(n=2) return 2; else return F(n-1)+ F(n-2); } ● 整数划分问题 问题描述:将正整数n 表示成一系列正整数之和,n=n1+n1+n3+… 将最大加数不大于m 的划分个数,记作q(n,m)。正整数n 的划分数 p(n)=q(n,n)。 可以建立q(n,m)的如下递归关系: 递归算法: Int q( int n, int m){ if(n<1||m<1) return 0; If((n=1)||(m=1)) return 1; If (n>=<==-+--+=11,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

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