第五讲 穷举算法

第五讲  穷举算法
第五讲  穷举算法

第五讲穷举算法

学习重点:

1、了解穷举法的基本概念及用穷举法设计算法的基本过程。

2、能够根据具体问题的要求,使用穷举法设计算法,编写程序求解问题。

3、能对穷举法编写的程序进行优化

学习过程:

穷举算法是学生在学完了QB基本语句后最早接触到的算法。一些简单的穷举算法题目如求水仙花数、找出缺失的数字等和小学生的数学学习紧密结合,程序也比较容易实现,因此学生的学习兴趣还是很高的。近几年的省小学生程序设计竞赛中也常出现穷举算法的题目,如:2001年题四算24;2002年题三求素数个数与素数个数最多的排列;2005年回文数个数等题目,有些题虽然说用穷举算法实现比较勉强(如2002年题三的后半题求出素数个数最多的排列),但在考试时,如果一时想不出更好的办法,用穷举算法也不失为一种明智的选择。

穷举法,常常称之为枚举法,是指从可能的集合中一一穷举各个元素,用题目给定的约束条件判定哪些是无用的,哪些是有用的。能使命题成立者,即为问题的解。

穷举是最简单,最基础,也是通常被认为非常没效率的算法,但是。穷举拥有很多优点,它在算法中占有一席之地。首先,穷举具有准确性,只要时间足够,正确的穷举得出的结论是绝对正确的;其次,穷举拥有全面性,因为它是对所有方案的全面搜索,所以,它能够得出所有的解。

采用穷举算法解题的基本思路:

(1)确定穷举对象、穷举范围和判定条件;

(2)一一列举可能的解,验证是否是问题的解

一、穷举算法的实现

在前面基础语句(for语句)的学习中,其实我们就用到了穷举。比如培训教材p77【例5-7】打印九九乘法表中,被乘数A和乘数B都从1-9一一列举。这样,九九乘法表中就不会遗失任何一句乘法口诀;在p79【例5-9】的数学灯谜题中,我们也是用了一一列举的方法,找出了A、B、C、D的取值范围。

下面我们再看两道例题:

1、搬运砖头

【问题描述】36 块砖, 36 人搬。男搬 4 ,女搬 3 ,两个小儿抬一砖。要求一次全

搬完。问需男、女、小儿各若干?

【问题分析】题目要我们找出符合条件的男生、女生和小孩的人数。答案显然是一组数据。首先分析一下问题所涉及的情况。对于男生来说,至少要有一人;每个男生可以搬4 块砖,那么 36 块砖最多 9 个男生足够,共有 9 种不同取值。同样,女生有 12 种不同取值。两个小孩抬一块砖,至少要有两个小孩,最多 36 个,并且小孩的人数必须是个偶数,所以小孩的人数可以取 18 种不同的值。最坏情况下,男生、女生和小孩的人数可以是9 × 12 × 18 = 1944 种不同组合。假设男生人数为 x ,女生人数为 y ,小孩人数为 z 。可以构建一个三重循环求出最终结果。

【程序清单】 rem 5_1.bas

for x=1 to 9

for y=1 to 12

for z=2 to 36 step 2

if x*4+y*3+z/2=36 then print x,y,z

next z

next y

next x

end

2、方格内填字符

【问题描述】在5个连成一串的方格内填入“a”和“b”,但“b”不能填在相邻两格内。打印出所有填法和总方案数。

【问题分析】(1)用五重循环列举;(2)由于QB中FOR语句不能直接列举字符,所以用“A”和“B”的ASCII码作为循环的初值和终值;(3)需排除含“BB”、“AAAAA”的各种情况。

【程序清单】

REM 5_2.bas

s = 0

bb = 132: aaaaa = 325 ’连续填“BB”的ASCII和为132,“AAAAA”为325;FOR a = 65 TO 66

FOR b = 65 TO 66

FOR c = 65 TO 66

FOR d = 65 TO 66

FOR e = 65 TO 66

x = a + b + c + d + e: ab = a + b: bc = b + c: cd = c + d: de = d + e IF x <> 325 AND ab <> bb AND bc <> bb AND cd <> bb AND de <> bb THEN PRINT CHR$(a); CHR$(b); CHR$(c); CHR$(d); CHR$(e): s = s + 1

NEXT e, d, c, b, a

PRINT s

3、简单的24点

【问题描述】从键盘输入4个整数(每个数均大于等于1),算一算能否凑成24点。(说明:数字的顺序不能改变,并按从左到右的次序运算,不考虑运算符的优先级别)例如:输入2,2,6,1

则输出为:

2+2*6*1

2+2*6/1

2*2*6*1

2*2*6/1

输入:4,8,10,2

则输出:4+8+10+2

4*8-10+2

【问题分析】4个数中需填入3处运算符,每一处运算符都应该有“+”、“-”、“*”、“/”四种可能的情况,因此,可以用三重循环一一列举;每一处运算符确定后,与它相邻的两个数就有一个结果,这个结果根据运算符来定,可能是两数的和或差或积或商,我们用SELECT CASE语句来处理;最后打印结果时,为了能打印出运算符,还是需要SELECT CASE 语句。

【程序清单】

Rem 5_3.bas

INPUT a, b, c, d

FOR i = 1 TO 4 ’列举第一处的运算符

SELECT CASE i

CASE 1: x = a + b

CASE 2: x = a - b

CASE 3: x = a * b

CASE 4: x = a / b

END SELECT

FOR j = 1 TO 4 ’列举第二处的运算符

SELECT CASE j

CASE 1: y = x + c

CASE 2: y = x - c

CASE 3: y = x * c

CASE 4: y = x / c

END SELECT

FOR k = 1 TO 4 ’列举第三处的运算符 SELECT CASE k

CASE 1: z = y + d

CASE 2: z = y - d

CASE 3: z = y * d

CASE 4: z = y / d

END SELECT

IF z = 24 THEN

PRINT a;

SELECT CASE i

CASE 1: PRINT "+";

CASE 2: PRINT "-";

CASE 3: PRINT "*";

CASE 4: PRINT "/";

END SELECT

PRINT b;

SELECT CASE j

CASE 1: PRINT "+";

CASE 2: PRINT "-";

CASE 3: PRINT "*";

CASE 4: PRINT "/";

END SELECT

PRINT c;

SELECT CASE k

CASE 1: PRINT "+";

CASE 2: PRINT "-";

CASE 3: PRINT "*";

CASE 4: PRINT "/";

END SELECT

PRINT d

END IF

NEXT k

NEXT j

NEXT i

END

【想一想】能不能简化打印语句,去掉里面的三个SELECT CASE语句?

【教法指导】在本单元的学习中,对我们的教学对象——小学生进行该算法教学的时候,我们首先应该让他们了解什么是穷举法?

教学的设计可以从游戏入手:

(1)请一个小朋友(小X)任意想一个4位数,写在纸上;

(2)请全体同学猜,这个数是几?

(3)每次说出一个数,裁判(老师)回答“对或错”

在所有同学猜过一遍后(可能会有同学猜出这个数,可以多次重复玩这个游戏),老师可以请同学们思考,怎样才能百发百中地猜中这个数呢?(老师可以将他们的回答引导到从1000-9999,一个数不漏地猜这样的结论上来)。游戏结束,老师布置作业,请同学们编一个程序,使用随机函数,模拟刚才的游戏过程。

程序清单:

Randomize timer

X=int(rnd*9000)+1000

I=1000

Do while I<>x

I=I+1

loop

print “zhe ge shu shi :”;i

End

老师可以根据这个程序说明什么叫“穷举算法”。

二、穷举算法的优化

4、九头鸟问题(培训教材P205例10-61)

【问题分析】

穷举对象:九头鸟、鸡、兔;

穷举范围:九头鸟:1~100

鸡:1~100

兔:1~100

判定条件:头和脚都等于100;

(程序见p205 REM L10-6A)

这段程序是没有优化的程序,在教学中,老师要分析最糟糕的情况下(找不到合适的解)需循环的次数,然后让同学们上机试一下,体会一下运行时间。

然后按p206 REM L10-6B 减少循环次数及REM L10-6C 减少穷举对象来优化程序。

从程序的优化过程中,学生们能体会到使用穷举算法时,对程序优化的重要性。

书上的三段程序建议让学生都能上机试验,加深体会。P207的程序可以布置数学基础好的同学自己学习。

5、巧填数字

【问题描述】

将1~6这六个数字分别填到下面的圆圈中,使三角形的每边上的三个数的和相等,一共有多少种方案?编程打印这些方案。(不需要按题目的格式打印)

【问题分析】

穷举对象:A,B,C,D,E,F

穷举范围:每一个对象都从1~6

判定条件:(1)A、B、C、D、E、F互不相等

(2)A+B+C=C+D+E=A+F+E

对于小学生来说,如何判定6个变量的取值分别是1~6的数,并且互不相等可能是这题的难点。在学习了一唯数组后,很容易想到的是:把这6个简单变量分别赋值给X(1)~X(6),然后用一个二重循环来判断有没有重复的值:

Flag=0 (标记)

For i=1 to 5

For j=i+1 to 6

If a(i)=a(j) then flag=1

Next j,i

这段小程序的适用范围很广,它可以用来判断出任意六个数是否互不相等。但在本题,由于已知的数是1~6的连续整数,因此可用更少的语句来实现。只要满足:A+B+C+D+E+F=21且A*B*C*D*E*F=720 就能判别出A~F一定是互不相等的数。

【程序清单】

Rem 5_5.bas

S = 0

FOR A = 1 TO 6

FOR B = 1 TO 6

FOR C = 1 TO 6

FOR D = 1 TO 6

FOR E = 1 TO 6

FOR F = 1 TO 6

X = A + B + C + D + E + F

Y = A * B * C * D * E * F

IF (X = 21) AND (Y = 720) AND (A + B + C = C + D + E) AND (A + B + C = A + F + E) THEN PRINT A; B; C; D; E; F : S = S + 1

NEXT F, E, D, C, B, A

PRINT "S="; S

END

程序的优化:在小学数学的范围内,学生们可以做的改进是:减少一个循环语句,从而使效率提高6倍。程序留给老师们自己编写。

三、穷举对象的选择

在上题中,如果数学知识扩充的话,只要3重循环就能解决问题。这就涉及到穷举对象的选择问题。上题中,穷举对象分别取A、C、E就可以了;判定条件只要6个数互不相等。

【问题分析】

根据已知条件:A+B+C+D+E+F=21,则三条边的和相加为:(A+B+C)+(C+D+E)+(E+F+A)=(A+C+E)+21。每一条边的和为:1/3*(A+C+E)+7,这样就有下面三组等式:A+B+C=1/3*(A+C+E)+7

C+D+E=1/3*(A+C+E)+7

E+F+A=1/3*(A+C+E)+7

上述三个式子化简后,就得到了:

b = e / 3 - a / 3 * 2 -

c / 3 * 2 + 7

d = a / 3 - c / 3 * 2 -

e / 3 * 2 + 7

f = c / 3 - a / 3 * 2 - e / 3 * 2 + 7

【程序清单】

REM 5_5_2.bas

FOR a = 1 TO 6

FOR c = 1 TO 6

FOR e = 1 TO 6

b = e / 3 - a / 3 * 2 -

c / 3 * 2 + 7

d = a / 3 - c / 3 * 2 -

e / 3 * 2 + 7

f = c / 3 - a / 3 * 2 - e / 3 * 2 + 7

p = a * b * c * d * e * f: s = a + b + c + d + e + f

IF b = INT(b) AND d = INT(d) AND f = INT(f) AND s = 21 AND p = 720 THEN PRINT a; b; c; d; e; f: q = q + 1

NEXT e

NEXT c

NEXT a

PRINT q

从例2中我们可以看到,在穷举算法中,穷举对象的选择也是非常重要的,它直接影响着算法的时间复杂度,选择适当的穷举对象可以获得更高的效率。我们再举一个例子:

6、成比例的三位数

【问题描述】

将1,2...9共9个数分成三组,分别组成三个三位数,且使这三个三位数构成1:2:3的比例,试求出所有满足条件的三个三位数.

例如:三个三位数192,384,576满足以上条件.

【问题分析】

这是1998年全国分区联赛普及组试题。此题数据规模不大,可以进行穷举,如果我们不假思索地以每一个数位为穷举对象,一位一位地去穷举:

for a =1 to 9

for b=1 to 9

………

for i=1 to 9

这样下去,穷举次数就有99次。如果我们分别设三个数为x,2x,3x,以x为穷举对象,穷举的范围就减少为9*9*9,在细节上再进一步优化,穷举范围就更少了。程序如下:【程序清单】

FOR x = 123 TO 321 ’穷举所有可能的解

y = 2 * x

z = 3 * x

GOSUB 1000 ’分解数字

GOSUB 2000 ’判断数字是否为1-9的互不重复的数

IF flag = 0 THEN PRINT x, y, z

NEXT x

END

1000 :

a(1) = x \ 100: a(2) = (x - a(1) * 100) \ 10: a(3) = x MOD 10

a(4) = y \ 100: a(5) = (y - a(4) * 100) \ 10: a(6) = y MOD 10

a(7) = z \ 100: a(8) = (z - a(7) * 100) \ 10: a(9) = z MOD 10

RETURN

2000 :

flag = 0

FOR i = 1 TO 9: b(i) = 0: NEXT i

FOR i = 1 TO 9

b(a(i)) = b(a(i)) + 1

NEXT i

FOR i = 1 TO 9

IF b(i) <> 1 THEN flag = 1

NEXT i

RETURN

在本程序中,判断不重复的数字用的是子程序2000,当然,用前面讲过的方法都是可以的,在此只是多提供一种方法给学生。优化以后的程序循环不到200次,运行时间大大缩短了。

四、判定条件的确定

在穷举法解题中,判定条件的确定也是很重要的,如果约束条件不对或者不全面,就穷举不出正确的结果。有些时候,我们编写的程序,从理论上来说,完全是正确的,但就是得不到正确的结果,或者会漏掉一些结果,这和判定条件是有一定关系的。我们再看看下面的例子。

7、一元三次方程求解(作为阅读材料)

【问题描述】

有形如:ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数(a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在-100至100之间),且根与根之差的绝对值>=1。

要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后2位。

提示:记方程f(x)=0,若存在2个数x1和x2,且x1

样例

输入:1 -5 -4 20

输出:-2.00 2.00 5.00

【问题分析】

由题目的提示很符合二分法求解的原理,所以此题可以用二分法。用二分法解题相对于穷举法来说很要复杂很多。此题是否能用穷举法求解呢?再分析一下题目,根的范围在-100到100之间,结果只要保留两位小数,我们不妨将根的值域扩大100倍

(-10000<=x<=10000),再以根为穷举对象,穷举范围是-10000到10000,用原方程式进行一一验证,找出方程的解。

有的同学在比赛中是这样做

Input a,b,c,d

for i=-10000 to 10000

x=i/100

if a*x*x*x+b*x*x+c*x+d=0 then ?x

next i

end

用这种方法,很快就可以把程序编出来,再将样例数据代入测试也是对的,等成绩下来才发现这题没有全对,只得了一半的分。

这种解法为什么是错的呢?错在哪里?前面的分析好像也没错啊,难道这题不能用穷举法做吗?看到这里大家可能有点迷惑了。

在上面的解法中,穷举范围和穷举对象都没有错,而是在验证穷举结果时,判定条件用错了。因为要保留二位小数,所以求出来的解不一定是方程的精确根,再代入

ax3+bx2+cx+d中,所得的结果也就不一定等于0,因此用原方程ax3+bx2+cx+d=0作为判断条件是不准确的。

我们换一个角度来思考问题,设f(x)=ax3+bx2+cx+d,若x为方程的根,则根据提示可知,必有f(x-0.005)*f(x+0.005)<0,如果我们以此为穷举判定条件,问题就逆刃而解。为了阅读程序的方便,我们先计算当x1=x-0.005,x2=x+0.005时函数的值。只要

(f(x-0.005)*f(x+0.005)<0),我们就认为在(x-0.005)到(x+0.005)中存在一个值,这个值就是我们需要的根。(我们用数字来举例说明问题:假设在50-0.005到50+0.005之间满足f(x-0.005)*f(x+0.005)<0,那么说明在49.995~50.005之间必定有一个根,这个根可能是49.995,49.996,49.997……50.004,50.005,根据题意,这些根中的任意一个经四舍五入后都是50 ,因此我们把50作为要求的一个根;另外,如果f(x-0.005)=0,那么说明x-0.005是方程的根,这时根据四舍5入,方程的根也为x。所以我们用

(f(x-0.005)*f(x+0.005)<0)和 (f(x-0.005)=0)作为判定条件。程序如下:【程序清单】

INPUT a, b, c, d

FOR i = -10000 TO 10000

x = i / 100

x1 = x - .005

x2 = x + .005

f1 = ((a * x1 + b) * x1 + c) * x1 + d

f2 = ((a * x2 + b) * x2 + c) * x2 + d

IF f1 = 0 OR f1 * f2 < 0 THEN PRINT x

NEXT i

END

用穷举法解题的最大的缺点是运算量比较大,解题效率不高,如果穷举范围太大(一般以不超过两百万次为限),在时间上就难以承受。但穷举算法的思路简单,程序编写和调试方便,比赛时也容易想到,在竞赛中,时间是有限的,我们竞赛的最终目标就是求出问题解,因此,如果题目的规模不是很大,在规定的时间与空间限制内能够求出解,那么我们最好是采用穷举法,而不需太在意是否还有更快的算法,这样可以使你有更多的时间去解答其他难题。

8、分鱼问题

【问题描述】

A 、

B 、

C 、

D 、

E 五人夜间合伙捕鱼,凌晨时都疲倦不堪,各自在河边的树丛中找地方睡着了。日上三竿, A 第一个醒来,他将鱼分作五份,把多余的一条扔回河中,拿自己的一份回家去了; B 第二个醒来,也将鱼分作五份,扔掉多余的一条,拿走自己的一份;接着 C 、 D 、 E 依次醒来,也都按同样的办法分鱼,问五人至少合伙捕了多少条鱼?试编程序算出。

【问题分析】

还记得我们书上p72[例5-3] 小猴吃桃那个题目吗?和这题很类似是吧?书上的题我们用的算法是迭代法,需要推出迭代公式。但这题,由于没有告诉我们最后一个人取走了几条鱼或最后剩下几条鱼,因此无法推出迭代公式。我们用穷举算法来做这道分鱼的题目。穷举对象:鱼

穷举范围:初始值为6(至少6条鱼),终值需求出

判定条件:(1)分了5次

(2)剩下的鱼丢掉1条后是否能正好分成5份(题目隐含)

我们用自顶向下,逐步求精的办法编写程序:

先确定大的结构:

鱼初值=6

Repeat

分鱼,判断条件(剩下的鱼丢掉1条后是否能正好分成5份) (1)

Until 分满5次

再将(1) 细化:

If (鱼-1) mod 5=0 then 算出剩下的鱼;次数+1 else 现在的鱼数=原来的鱼数+5;次数=0

这样,我们可以编出程序:

【程序清单】

yu = 6

s = 0

DO

IF (yu - 1) MOD 5 = 0 THEN

s = s + 1

yu = (yu - 1) / 5 * 4

ELSE

yu = yu + 5

s = 0

END IF

LOOP UNTIL s = 5

PRINT yu

End

经过上机调试,结果不对。问题出在哪里呢?

在重新经过步进运行(按F8)后,我们发现,问题出在yu这个变量上。拿初始状态yu = 6来跟踪,在经过了第一次分鱼后,剩下的yu=4,继续循环,由于不满足(yu - 1) MOD 5 = 0 这个判定条件而执行else语句中的yu = yu + 5,使yu=9,这和我们的初衷—--不能分鱼时,在原来yu的基础上+5(即yu=11)的设计思想是有出入的。为改变这个现象,我们引入变量yu1,参与循环中的运算,而将变量yu作为一旦分鱼不满足条件,yu = yu + 5,重新进入新的分鱼行动。

经修改后的程序:

yu = 6

yu1 = yu

s = 0

DO

IF (yu1 - 1) MOD 5 = 0 THEN

s = s + 1

yu1 = (yu1 - 1) / 5 * 4

ELSE

yu = yu + 5

yu1 = yu

s = 0

END IF

LOOP UNTIL s = 5

PRINT yu

End

从上面的例子中我们也能看出,穷举算法一般都是用for语句来实现的,但有时在无法确定终值的情况下,就用条件循环解决问题。

9、背包问题

【问题描述】

小明有一个最多只能装10斤重的网袋。现有白菜5斤、猪肉2斤、鱼3斤、酱油连瓶重1.7斤、白糖1斤、土豆5.1斤。设计一个程序使小明的网袋里装的物品总重量最大(每件物品要么装进袋子,要么不装),打印出这种方案。

【问题分析】

穷举对象:白菜(A)、猪肉(B)、鱼(C)、酱油(D)、白糖(E)、土豆(F)

穷举范围:0(不装)--1(装入)

判定条件:(1)A*5+B*2+C*3+D*1.7+E*1+F*5.1是否<=10

(2)若(1)成立,这种装法是否为最大

【程序清单】

m$(1) = "baicai 5 jin": m$(2) = "zhurou 2 jin": m$(3) = "yu 3.5 jin"

m$(4) = "jiangyou 1.7 jin": m$(5) = "baitang 1 jin": m$(6) = "tudou 5.1 jin" max = 0

FOR a = 0 TO 1

FOR b = 0 TO 1

FOR c = 0 TO 1

FOR d = 0 TO 1

FOR e = 0 TO 1

FOR f = 0 TO 1

x = a * 5 + b * 2 + c * 3.5 + d * 1.7 + e * 1 + f * 5.1

IF x <= 10 AND x > max THEN

max = x

x(1) = a

x(2) = b

x(3) = c

x(4) = d

x(5) = e

x(6) = f

END IF

NEXT f, e, d, c, b, a

PRINT "zhong zhong liang zui da wei :"; max; "jin"

FOR i = 1 TO 6

IF x(i) <> 0 THEN PRINT m$(i)

NEXT i

END

程序优化:

分析过程:本题考虑到最轻的5种物品的总重量为:5+2+3.5+1.7+1=13.2>10,因此,网袋中最多只能装下4件物品。这样,就可以考虑从所有物品的总重量中减去任意两种物品的重量,从而求得题目要求的结果。循环从6重变为2重,大大提高了效率。

s = 0

FOR i = 1 TO 6: READ a(i): s = s + a(i): NEXT I

FOR i = 1 TO 6: READ m$(i): NEXT I {为打印作准备}

max = 0

FOR i = 1 TO 5

FOR j = i + 1 TO 6

s1 = s {这个语句不能少}

s1 = s1 - a(i) - a(j)

IF s1 <= 10 AND s1 > max THEN b = i: c = j: max = s1 {满足条件要将数据纪录下来}

NEXT j

NEXT i

PRINT "zongzhongliang wei:"; max; " jin"

FOR i = 1 TO 6

IF i <> b AND i <> c THEN PRINT m$(i) {不是去掉的两个物品就打印} NEXT i

DATA 5,2,3.5,1.7,1,5.1

DATA"baicai 5 jin","zhurou 2 jin","yu 3.5 jin","jiangyou 1.7 jin" DATA"baitang 1 jin","tudou 5.1 jin"

10、 n种物品的背包问题(阅读材料)

【问题描述】

有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和最大。

【问题分析】

这种背包问题事先不知道物品的总件数,因此,用上面的解法是根本行不通的。设n 个物品的重量和价值分别存储于数组w()和v()中,限制重量为tw。考虑一个n元组

(x

0,x

1

,…,x

n-1

),其中x

i

=0 表示第i个物品没有选取,而x

i

=1则表示第i个物品被选

取。显然这个n元组等价于一个选择方案。用穷举法解决背包问题,需要穷举所有的选取方案,而根据上述方法,我们只要穷举所有的n元组,就可以得到问题的解。

显然,每个分量取值为0或1的n元组的个数共为2n个。而每个n元组其实对应了一个长度为n的二进制数,且这些二进制数的取值范围为0~2n-1。

根据上面的分析,如果把0~2n-1分别转化为相应的二进制数,则可以得到我们所需要的2n个n元组。我们以此作为穷举的范围。

【程序清单】

DIM a(100), b(100), x(100), w(100), v(100)

INPUT n, tw

FOR i = 1 TO n: INPUT w(i), v(i): NEXT i

p = 1

FOR i = 1 TO n: p = p * 2: NEXT

max = 0

FOR i = 0 TO p - 1

x = i: w = 0: v = 0

FOR j = 1 TO n: x(j) = 0: NEXT j

j = 0

DO {转化为二进制数}

j = j + 1

x(j) = x MOD 2

x = x \ 2

LOOP UNTIL x = 0

FOR k = 1 TO n

w = w + w(k) * x(k)

v = v + v(k) * x(k)

NEXT k

IF (w <= tw) AND (v > max) THEN

max = v {纪录最大价值的数据值}

FOR k = 1 TO n

b(k) = x(k)

NEXT k

w1 = w

END IF

NEXT i

FOR k = 1 TO n {输出最大价值的方案}

IF b(k) <> 0 THEN PRINT w(k), v(k)

NEXT k

PRINT "zong zhongliang:"; w1

PRINT "zong jiazhi:"; max

例11 见小学培训教程p208 [例10-8]

例12 见小学培训教程p209 [例10-9]

小结:

穷举算法是一种比较“笨”的方法,它通过列举所有情况然后逐一判断来得到结果。

穷举的思想很简单,但是可以引发我们很多的思考:

穷举什么?怎样穷举?能算出穷举方案的总数吗?运行速度够快吗?如果速度太慢,有什么优化方法吗?

希望大家在学完这一章节后,对这一算法能熟练掌握。

本讲作业

1、从3,5,7,9,11,13,15七个数中任取两个组成最简真分数,共有几个?都是什么数?

2、算24(2001年省小学组竞赛题四)。给出4个1-1000之间的整数,用这四个整数,通过+、-、*的运算而得到24,运算规则如下:

(1)每个数必须使用一次,只能使用一次。

(2)运算符无优先级之分,自左向右计算。

例如:输入4个数为2,9,3,1

则计算方法为3+9*2*1=24

3、求素数个数(2002年省小学组竞赛题三前半题)将1,2,…,n个数(n<=7)按顺时针方向排成一圈,然后从任意位置开始按顺时针方向连续取k个数字组成一个k位数。(k

例如:n=3 k=2按顺时针方向排成如下一圈:

1

3 2

此时可组成:12,23,31。其中的素数有23,31。

问题一:当给出n、k后,求出在n个k位数种有多少个素数?

问题二:将这n个数重新排列,找出能产生k位数中的素数最多的一种排列,并统计出可能产生的素数个数。

输入:n,k

输出:x1 ‘问题一的解

X2 ‘问题二的解(仅需个数,不用输出排列)

4、将2n个0和2n个1,排成一圈。从任一个位置开始,每次按逆时针的方向以长度为n+1的单位进行数二进制数。要求给出一种排法,用上面的方法产生出来的2n+1个二进制数都不相同。

第五讲 穷举算法

第五讲穷举算法 学习重点: 1、了解穷举法的基本概念及用穷举法设计算法的基本过程。 2、能够根据具体问题的要求,使用穷举法设计算法,编写程序求解问题。 3、能对穷举法编写的程序进行优化 学习过程: 穷举算法是学生在学完了QB基本语句后最早接触到的算法。一些简单的穷举算法题目如求水仙花数、找出缺失的数字等和小学生的数学学习紧密结合,程序也比较容易实现,因此学生的学习兴趣还是很高的。近几年的省小学生程序设计竞赛中也常出现穷举算法的题目,如:2001年题四算24;2002年题三求素数个数与素数个数最多的排列;2005年回文数个数等题目,有些题虽然说用穷举算法实现比较勉强(如2002年题三的后半题求出素数个数最多的排列),但在考试时,如果一时想不出更好的办法,用穷举算法也不失为一种明智的选择。 穷举法,常常称之为枚举法,是指从可能的集合中一一穷举各个元素,用题目给定的约束条件判定哪些是无用的,哪些是有用的。能使命题成立者,即为问题的解。 穷举是最简单,最基础,也是通常被认为非常没效率的算法,但是。穷举拥有很多优点,它在算法中占有一席之地。首先,穷举具有准确性,只要时间足够,正确的穷举得出的结论是绝对正确的;其次,穷举拥有全面性,因为它是对所有方案的全面搜索,所以,它能够得出所有的解。 采用穷举算法解题的基本思路: (1)确定穷举对象、穷举范围和判定条件; (2)一一列举可能的解,验证是否是问题的解 一、穷举算法的实现 在前面基础语句(for语句)的学习中,其实我们就用到了穷举。比如培训教材p77【例5-7】打印九九乘法表中,被乘数A和乘数B都从1-9一一列举。这样,九九乘法表中就不会遗失任何一句乘法口诀;在p79【例5-9】的数学灯谜题中,我们也是用了一一列举的方法,找出了A、B、C、D的取值范围。 下面我们再看两道例题: 1、搬运砖头 【问题描述】36 块砖, 36 人搬。男搬 4 ,女搬 3 ,两个小儿抬一砖。要求一次全

C语言实现二叉树的前序遍历(递归)

C语言实现二叉树的前序遍历算法实现一: #include #include typedef struct BiTNode//定义结构体 { char data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; void CreateBiTree(BiTree &T) //前序创建树 { char ch; scanf("%c",&ch); if(ch==' ') T=NULL; else { T=(struct BiTNode *)malloc(sizeof(struct BiTNode)); T->data=ch; CreateBiTree(T->lchild); CreateBiTree(T->rchild); } } int print(BiTree T)//前序遍历(输出二叉树) { if(T==NULL)return 0; else if(T->lchild==NULL && T->rchild==NULL)return 1; else return print(T->lchild)+print(T->rchild); } void main()//主函数 { BiTree T; CreateBiTree(T); printf("%d\n",print(T)); } 算法实现二: #include

#include struct BiTNode//定义结构体 { char data; struct BiTNode *lchild,*rchild; }; int num=0; void CreatBiTree(struct BiTNode *&p) //前序创建树 { char ch; scanf("%c",&ch); if(ch==' ') p=NULL; else { p=(struct BiTNode *)malloc(sizeof(struct BiTNode)); p->data=ch; CreatBiTree(p->lchild); CreatBiTree(p->rchild); } } void print(struct BiTNode *p) //前序遍历(输出二叉树){ if(p!=NULL) { if(p->lchild==NULL&&p->rchild==NULL) else { print(p->lchild); print(p->rchild); } } } void main()//主函数 { struct BiTNode *p; CreatBiTree(p); print(p); printf("%d\n",num); } 供测试使用的数据

二叉树遍历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.先序遍历非递归算法 #define maxsize 100 typedef struct { Bitree Elem[maxsize]; int top; }SqStack; void PreOrderUnrec(Bitree t) { SqStack s; StackInit(s); p=t; while (p!=null || !StackEmpty(s)) { while (p!=null) //遍历左子树 { visite(p->data); push(s,p); p=p->lchild; }//endwhile if (!StackEmpty(s)) //通过下一次循环中的内嵌while实现右子树遍历 { p=pop(s); p=p->rchild; }//endif }//endwhile }//PreOrderUnrec 2.中序遍历非递归算法 #define maxsize 100 typedef struct { Bitree Elem[maxsize];

int top; }SqStack; void InOrderUnrec(Bitree t) { SqStack s; StackInit(s); p=t; while (p!=null || !StackEmpty(s)) { while (p!=null) //遍历左子树 { push(s,p); p=p->lchild; }//endwhile if (!StackEmpty(s)) { p=pop(s); visite(p->data); //访问根结点 p=p->rchild; //通过下一次循环实现右子树遍历}//endif }//endwhile }//InOrderUnrec 3.后序遍历非递归算法 #define maxsize 100 typedef enum{L,R} tagtype; typedef struct { Bitree ptr; tagtype tag; }stacknode; typedef struct { stacknode Elem[maxsize]; int top; }SqStack; void PostOrderUnrec(Bitree t)

(完整word版)穷举法

用穷举法解决问题教学设计 【教材分析】 本节课选自教科版《算法与程序设计》选修第三章的第二节。本节课讲的是现实生活中解决问题的一种算法——穷举法,实际上是使用for-next循环语句来解决实际问题。本节要求学生初步了解穷举算法的思想,总结出穷举法解决问题的一般步骤,总结出哪一类的、具有什么特征的问题适合用穷举法来解决。本课内容是对算法学习的引入,为高中阶段算法的学习打下了基础。 【学情分析】 本节内容的教学对象是高二年级学生,他们已经具备了一定的逻辑思维、分析问题、表达思想等能力。同时,通过前两个章节的学习与实践,学生已经历了用计算机解决问题的过程与步骤,学会了对计算机程序进行调试,并掌握了顺序、选择、循环三种程序结构,为本节内容的学习提供了良好的基础。前一节的学习,学生掌握了如何用解析法解决问题,但现实生活中也有很多问题往往无法用解析法找到答案,这时候我们可以尝试采用另外一种方法“穷举法”,从而引出本课内容。因此对此类问题的归纳求解,学生应该掌握。 【教学目标】 知识与技能: 1、巩固for…next循环语句的格式和运用。 2、了解什么是穷举法以及用穷举法解决问题的一般步骤。 3、了解穷举法具有一定的适用范围。 4、能够根据具体问题的要求,使用穷举法设计算法。 过程与方法: 本节以“百钱买百鸡问题”入手,由浅入深讲解了穷举算法的思路。通过讨论、对比、总结,熟练掌握穷举算法求解问题的方法。在编程实践之后,对各种方案进行对比试验,加深穷举算法的理解。 情感态度与价值观: 了解算法和程序设计在计算机解决问题过程中的重要性;体验将算法转变为程序的过程,享受计算机解决问题的快乐;培养学生发现、探索和创新的能力。 【教学重、难点】 重点:用穷举法解决问题的一般步骤;能根据具体问题的要求,提高运用穷举法解决问题的能力。 难点:哪一类问题适合穷举法,确定穷举的范围以及评价穷举效率的高低。 【教学方法】 本节内容理论性和实践性都比较强,所以用演示、实践、讨论、任务驱动等多种形式的教学活动让枯燥的内容和生动有趣的任务结合起来。 【教学课时】 1课时 【教学环境】 硬件:机房一间,多媒体教学系统一套 软件:Visual Basic软件、自制的课件 【教学过程】 一、导入 上节课我们学习用解析法解决问题,用解析法解决问题的过程是:分析问题→抽取数学模型→导出解析表达式→设计算法→编写代码→调试运行程序。用解析法解决问题具有高效、快捷的特点,但是解析法也有“束手无策”的时候,有些问题即使可以用解析法,但求解过程和

二叉树遍历课程设计心得【模版】

目录 一.选题背景 (1) 二.问题描述 (1) 三.概要设计 (2) 3.1.创建二叉树 (2) 3.2.二叉树的非递归前序遍历示意图 (2) 3.3.二叉树的非递归中序遍历示意图 (2) 3.4.二叉树的后序非递归遍历示意图 (3) 四.详细设计 (3) 4.1创建二叉树 (3) 4.2二叉树的非递归前序遍历算法 (3) 4.3二叉树的非递归中序遍历算法 (4) 4.4二叉树的非递归后序遍历算法 (5) 五.测试数据与分析 (6) 六.源代码 (6) 总结 (10) 参考文献: (11)

一.选题背景 二叉树的链式存储结构是用指针建立二叉树中结点之间的关系。二叉链存储结构的每个结点包含三个域,分别是数据域,左孩子指针域,右孩子指针域。因此每个结点为 由二叉树的定义知可把其遍历设计成递归算法。共有前序遍历、中序遍历、后序遍历。可先用这三种遍历输出二叉树的结点。 然而所有递归算法都可以借助堆栈转换成为非递归算法。以前序遍历为例,它要求首先要访问根节点,然后前序遍历左子树和前序遍历右子树。特点在于所有未被访问的节点中,最后访问结点的左子树的根结点将最先被访问,这与堆栈的特点相吻合。因此可借助堆栈实现二叉树的非递归遍历。将输出结果与递归结果比较来检验正确性。。 二.问题描述 对任意给定的二叉树(顶点数自定)建立它的二叉链表存贮结构,并利用栈的五种基本运算(置空栈、进栈、出栈、取栈顶元素、判栈空)实现二叉树的先序、中序、后序三种遍历,输出三种遍历的结果。画出搜索顺序示意图。

三.概要设计 3.1.创建二叉树 3.2.二叉树的非递归前序遍历示意图 图3.2二叉树前序遍历示意图3.3.二叉树的非递归中序遍历示意图 图3.3二叉树中序遍历示意图

数学建模应该掌握的十大算法(汇编)

数学建模竞赛中应当掌握的十类算法 排名如下: 1、蒙特卡罗算法(该算法又称随机性模拟算法,是通过计算机仿真来解决问题的算法,同时可以通过模拟可以来检验自己模型的正确性,是比赛时必用的方法) 2、数据拟合、参数估计、插值等数据处理算法(比赛中通常会遇到大量的数据需要处理,而处理数据的关键就在于这些算法,通常使用Matlab作为工具) 3、线性规划、整数规划、多元规划、二次规划等规划类问题(建模竞赛大多数问题属于最优化问题,很多时候这些问题可以用数学规划算法来描述,通常使用Lindo、Lingo软件实现) 4、图论算法(这类算法可以分为很多种,包括最短路、网络流、二分图等算法,涉及到图论的问题可以用这些方法解决,需要认真准备) 5、动态规划、回溯搜索、分治算法、分支定界等计算机算法(这些算法是算法设计中比较常用的方法,很多场合可以用到竞赛中) 6、最优化理论的三大非经典算法:模拟退火法、神经网络、遗传算法(这些问题是用来解决一些较困难的最优化问题的算法,对于有些问题非常有帮助,但是算法的实现比较困难,需慎重使用) 7、网格算法和穷举法(网格算法和穷举法都是暴力搜索最优点的算法,在很多竞赛题中有应用,当重点讨论模型本身而轻视算法的时候,可以使用这种暴力方案,最好使用一些高级语言作为编程工具) 8、一些连续离散化方法(很多问题都是实际来的,数据可以是连续的,而计算机只认的是离散的数据,因此将其离散化后进行差分代替微分、求和代替积分等思想是非常重要的) 9、数值分析算法(如果在比赛中采用高级语言进行编程的话,那一些数值分析中常用的算法比如方程组求解、矩阵运算、函数积分等算法就需要额外编写库函数进行调用) 10、图象处理算法(赛题中有一类问题与图形有关,即使与图形无关,论文中也应该要不乏图片的,这些图形如何展示以及如何处理就是需要解决的问题,通常使用Matlab进行处理) 8.1 遗传算法的概念 是建立在自然选择和自然遗传学机理基础上的迭代自适应概率性搜索算法,在1975年由Holland教授提出。 生物的进化是一个奇妙的优化过程,它通过选择淘汰,突然变异,基因遗传等规律产生适应环境变化的优良物种。遗传算法是根据生物进化思想而启发得出的一种全局优化算法。 遗传算法的概念最早是由Bagley J.D在1967年提出的;而开始遗传算法的理论和方法的系统性研究的是1975年,这一开创性工作是由Michigan大学的 J.H.Holland所实行。当时,其主要目的是说明自然和人工系统的自适应过程。

二叉树的层次遍历算法

二叉树层次遍历算法实现 问题描述 对任意输入的表示某二叉树的字符序列,完成二叉树的层次遍历算法,并输出其遍历结果。 注:所需Queue ADT的实现见附录。 输入描述 从键盘上输入一串字符串,该字符串为二叉树的先序遍历结果,其中如果遍历到空树时用字符”#”代替。 输出描述 从显示器上输出二叉树的按层次遍历结果。 输入与输出示例 输入: +A##/*B##C##D## 输出: +A/*DBC 输入: ABD##GJ###CFH##I### 输出: ABCDGFJHI 附录(仅供参考): #include #include #define TRUE 1 #define FALSE 0 #define MAX_QUEUE_SIZE 100

//注:需要定义ElementType类型,如果是二叉树, // 则应定义为指向二叉树中结点的指针类型 //格式如: // typedef Tree ElementType; // 队列存储结构采用循环队列 struct QueueRecord; typedef struct QueueRecord *Queue; int IsEmpty(Queue Q); int IsFull(Queue Q); Queue CreateQueue(int MaxElements); void DisposeQueue(Queue Q); void MakeEmpty(Queue Q); int Enqueue(ElementType X, Queue Q); ElementType Front(Queue Q); int Dequeue(Queue Q, ElementType &X); #define MinQueueSize ( 5 ) struct QueueRecord { int Capacity; int Front; int Rear; ElementType *Array; }; int IsEmpty(Queue Q) { return ((Q->Rear + 1)% Q->Capacity == Q->Front); } int IsFull(Queue Q) { return ((Q->Rear + 2) % Q->Capacity == Q->Front); } Queue CreateQueue(int MaxElements) { Queue Q; if (MaxElements < MinQueueSize) return NULL; Q = (Queue)malloc(sizeof(struct QueueRecord));

常用算法(二)——穷举搜索法

常用算法——穷举搜索法 二、穷举搜索法 穷举搜索法是对可能是解的众多候选解按某种顺序进行逐一枚举和检验,并从众找出那些符合要求的候选解作为问题的解。 【问题】将A、B、C、D、E、F这六个变量排成如图所示的三角形,这六个变量分别取[1,6]上的整数,且均不相同。求使三角形三条边上的变量之和相等的全部解。如图就是一个解。 程序引入变量a、b、c、d、e、f,并让它们分别顺序取1至6的证书,在它们互不相同的条件下,测试由它们排成的如图所示的三角形三条边上的变量之和是否相等,如相等即为一种满足要求的排列,把它们输出。当这些变量取尽所有的组合后,程序就可得到全部可能的解。细节见下面的程序。 【程序1】 # include void main() { int a,b,c,d,e,f; for (a=1;a<=6;a++) for (b=1;b<=6;b++) { if (b==a) continue; for (c=1;c<=6;c++) { if (c==a)||(c==b) continue; for (d=1;d<=6;d++) { if (d==a)||(d==b)||(d==c) continue; for (e=1;e<=6;e++) { if (e==a)||(e==b)||(e==c)||(e==d) continue; f=21-(a+b+c+d+e); if ((a+b+c==c+d+e))&&(a+b+c==e+f+a)) { printf(“%6d,a); printf(“%4d%4d”,b,f); printf(“%2d%4d%4d”,c,d,e); scanf(“%*c”); } } } } } } 按穷举法编写的程序通常不能适应变化的情况。如问题改成有9个变量排成三角形,每条边有4个变量的情况,程序的循环重数就要相应改变。 对一组数穷尽所有排列,还有更直接的方法。将一个排列看作一个长整数,则所有排列对应着一组整数。将这组整数按从小到大的顺序排列排成一个整数,从对应最小的整数开始。按数列的递增顺序逐一列举每个排列对应的每个整数,这能更有效地完成排列的穷举。从一个排列找出对应数列的下一个排列可在当前排列的基础上作部分调整来实现。倘若当前排列

二叉树遍历算法的实现

二叉树遍历算法的实现 题目:编制二叉树遍历算法的实现的程序 一.需求分析 1.本演示程序中,二叉树的数据元素定义为非负的整型(unsigned int)数据,输 入-1表示该处没有节点 2.本演示程序输入二叉树数据均是按先序顺序依次输入 3.演示程序以用户和计算机对话方式执行,即在计算机终端上显示“提示信息” 之后,由用户在键盘上输入演示程序中规定的运算命令;相应的输入数据和运 算结果显示在其后 4.本实验一共包括三个主要程序,分别是:1)二叉树前序,中序,后序遍历递归 算法实现2)二叉树前序中序遍历非递归算法实现3)二叉树层次遍历算法实现 5.本程序执行命令包括:1)构建二叉树2)二叉树前序递归遍历3)二叉树中序 递归遍历4)二叉树后序递归遍历5)二叉树前序非递归遍历6)二叉树中序非 递归遍历7)二叉树层次遍历 6.测试数据 (1)7 8 -1 9 10 -1 -1 -1 6 11 -1 -1 12 13 -1 -1 14 -1 -1 (2)1 -1 -1 (3)7 8 -1 -1 9 -1 -1 二.概要设计 1.为实现二叉树的遍历算法,我们首先给出如下抽象数据类型 1)二叉树的抽象数据类型 ADT BiTree{ 数据对象D:D是具有相同特性的数据元素的集合 数据关系R: 若D=Φ,则R=Φ,称BiTree是空二叉树; 若D≠Φ,则R={H},H是如下二元关系: (1)在D中存在唯一的成为根的数据元素root,它在关系H下无前驱; (2)若D-{H}≠Φ,则存在D-{root}={D1,D r},且D1∩D r=Φ (3)若D1≠Φ,则D1中存在唯一的元素x1,∈H,且存在D1上的 关系H1?H;若Dτ≠Φ,则D r中存在唯一的元素x r,∈ H,且存在D r上的关系H r?H;H={,,H1,H r}; (4)(D1,{H1})是符合本定义的二叉树,成为根的左子树,(D r,{H r})是 一颗符合本定义的二叉树,成为根的右字树。 基本操作P: InitBiTree(&T); 操作结果:构造空二叉树 DestroyBiTree(&T) 初始条件;二叉树存在 操作结果:销毁二叉树 CreateBiTree(&T,definition);

实验 二叉树遍历算法及应用

实验二叉树遍历算法及应用 实验报告二叉树的遍历应用算法测试实验日期:______________ 学生姓 名:______________ 班级:_______________ 一、实习目的: 1、深入了解二叉树的存储结构及二叉树的遍历方法; 2、掌握二叉树的遍历算法及应用。 二、实习内容及要求 ----------------------------------------------------------------------------------------------------------------------------------------- 应用遍历思想,建立一棵如下图所示的二叉树,并能够完成如下操作: 1. 输出该二叉树的先序、中序、后序遍历序列; 2. 拷贝该树,生成一棵新树; 3. 将原树拆分成左右2棵树,并分别输出该二叉树左子树的遍历序列和右子树的遍历序列; 4. 利用遍历算法输出复制生成的树中结点总数、叶子总数、二叉树高度,并能够输出此二叉树中的叶子 结点。 ----------------------------------------------------------------------------------------------------------------------------------------- 附加:应用二叉树的顺序存储结构,实现建树。 并设计一个算法,实现能够输入一棵树中的双亲结点,输出该双亲结点的所有孩子结点的算法。

三、数据结构设计 (请将数据结构设计填写在此部分。) 四、测试 分别给出以下三棵树的测试结果

二叉树的遍历算法实验报告

二叉树实验报告 09信管石旭琳 20091004418 一、实验目的: 1、理解二叉树的遍历算法及应用 2、理解哈夫曼树及其应用。 3、掌握哈夫曼编码思想。 二、实验内容: 1、建立二叉树二叉链表 2、实现二叉树递归遍历算法(中序、前序、后序) 3、求二叉树高度 4、求二叉树结点个数 5、求二叉树叶子个数 6、将序号为偶数的值赋给左子树 三、主要程序: #include #include typedef int ElemType; struct BiTNode { ElemType data; struct BiTNode *lch,*rch; }BiTNode,*BiTree; struct BiTNode *creat_bt1(); struct BiTNode *creat_bt2(); void preorder (struct BiTNode *t); void inorder (struct BiTNode *t); void postorder (struct BiTNode *t); void numbt (struct BiTNode *t); int n,n0,n1,n2; void main() { int k; printf("\n\n\n"); printf("\n\n 1.建立二叉树方法1(借助一维数组建立)"); printf("\n\n 2.建立二叉树方法2(先序递归遍历建立)"); printf("\n\n 3.先序递归遍历二叉树"); printf("\n\n 4.中序递归遍历二叉树"); printf("\n\n 5.后序递归遍历二叉树"); printf("\n\n 6.计算二叉树结点个数"); printf("\n\n 7.结束程序运行");

二叉树的建立和遍历的实验报告

竭诚为您提供优质文档/双击可除二叉树的建立和遍历的实验报告 篇一:二叉树遍历实验报告 数据结构实验报告 报告题目:二叉树的基本操作学生班级: 学生姓名:学号: 一.实验目的 1、基本要求:深刻理解二叉树性质和各种存储结构的特点及适用范围;掌握用指针类型描述、访问和处理二叉树的运算;熟练掌握二叉树的遍历算法;。 2、较高要求:在遍历算法的基础上设计二叉树更复杂操作算法;认识哈夫曼树、哈夫曼编码的作用和意义;掌握树与森林的存储与便利。二.实验学时: 课内实验学时:3学时课外实验学时:6学时三.实验题目 1.以二叉链表为存储结构,实现二叉树的创建、遍历(实验类型:验证型)1)问题描述:在主程序中设计一个简单的菜单,分别调用相应的函数功能:1…建立树2…前序

遍历树3…中序遍历树4…后序遍历树5…求二叉树的高度6…求二叉树的叶子节点7…非递归中序遍历树0…结束2)实验要求:在程序中定义下述函数,并实现要求的函数功能:createbinTree(binTree structnode*lchild,*rchild; }binTnode;元素类型: intcreatebinTree(binTree voidpreorder(binTreevoidInorder(binTree voidpostorder(binTreevoidInordern(binTreeintleaf(bi nTree intpostTreeDepth(binTree 2、编写算法实现二叉树的非递归中序遍历和求二叉树高度。1)问题描述:实现二叉树的非递归中序遍历和求二叉树高度2)实验要求:以二叉链表作为存储结构 3)实现过程: 1、实现非递归中序遍历代码: voidcbiTree::Inordern(binTreeinttop=0;p=T;do{ while(p!=nuLL){ stack[top]=p;;top=top+1;p=p->lchild;}; if(top>0){ top=top-1;p=stack[top];

C#实现二叉树遍历算法

C#实现二叉树遍历算法 用C#2.0实现了二叉树的定义,怎么构造一颗已知的二叉树,用几种常规的算法(先序,中序,后序,层次)遍历二叉树。希望能给有需要人带来帮助,也希望能得到大家的指点。有关C#数据结构的书在书店里找到,网上也是极少,如果你有好的学习资源别忘了告诉我。先谢了。数据结构对一个程序员来说,现在是太重要了,数据结构学得好的人,逻辑思维一定很强,在程序设计的时候,就不会觉得太费劲了。而且是在设计多层应用程序的时候,真是让人绞尽脑汁啊。趁自己还年轻,赶紧练练脑子。哈哈,咱们尽快进入主题吧。 本程序中将用到一棵已知的二叉树如图(二叉树图)所示。 下面简单介绍一下几种算法和思路: 先序遍历: 1. 访问根结点 2. 按先序遍历左子树; 3. 按先序遍历右子树; 4. 例如:遍历已知二叉树结果为:A->B->D->G->H->C->E->F

中序遍历: 1. 按中序遍历左子树; 2. 访问根结点; 3. 按中序遍历右子树; 4. 例如遍历已知二叉树的结果:B->G->D->H->A->E->C->F 后序遍历: 1. 按后序遍历左子树; 2. 按后序遍历右子树; 3. 访问根结点; 4. 例如遍历已知二叉树的结果:G->H->D->B->E->F->C->A 层次遍历: 1. 从上到下,从左到右遍历二叉树的各个结点(实现时需要借辅助容器); 2. 例如遍历已知二叉树的结果:A->B->C->D->E->F->G->H 附加整个解决方案代码: 二叉遍历算法解决方案 using System; using System.Collections.Generic;

穷举算法及解题

穷举算法及解题 穷举算法及解题 例12-1古希腊人认为因子的和等于它本身的数是一个完全数(自身因子除外),例如28的因子是1、 2、4、7、14,且1+2+4+7+14=28,则28是一个完全数,编写一个程序求2~1000内的所有完全数。问题分析 (1)本题是一个搜索问题,搜索范围2~1000,找出该范围内的完全数;(2)完全数必须满足的条件:因子的和等于该数的本身; (3)问题关键在于将该数的因子一一寻找出来,并求出因子的和:分解因子的方法比较简单,采用循环完成分解因子和求因子的和。 程序如下: program p12_1; var a,b,s:integer; begin for a:=2to1000do

begin s:=0; for b:=1to a-1do if a mod b=0then s:=s+b; if a=s then begin write(a,'=',1,); for b:=2to a-1do if a mod b=0then write('+',b); writeln; end; end; end. 当程序运行后,输出结果: 6=1+2+3 28=1+2+4+7+14 496=1+2+4+8+16+31+62+124+248 例12-3 邮局发行一套票面有四种不同值的邮票,如果每封信所帖邮票张数不超过三枚,存在整数r,使得用不超过三枚的邮票,可以贴出连续的整数1、2、3、……、r来,找出这四种面值数,使得r值最大。 问题分析:本题则是 知道每封信邮票数的范围(<=3),邮票有四种类型,编程找出能使面值最

二叉树的遍历算法

实验三二叉树遍历算法 一、实验目的 1.进一步理解掌握二叉树二叉链表存储结构。 2.掌握二叉树遍历的递归与非递归算法。 二、实验要求 1.认真阅读和掌握(先序、中序、后序和层次)遍历的递归与非递归算法。2.上机调试(先序、中序、后序和层次)遍历的递归与非递归算法。 3.保存和打印出程序的运行结果,并结合程序进行分析。 4.上机后,认真整理源程序及其注释,完成实验报告(包括源程序、实验结果、算法分析、心得体会等)。 三、实验容 先序、中序、后序遍历的递归与非递归算法和层次遍历的算法实现 程序: #include "stdio.h" #include "stdlib.h" #include "conio.h" #define maxsize 100 typedef int datatype; typedef struct bnode{ datatype data; struct bnode *lchild,*rchild; }bnode,*btree; typedef struct { bnode *node; int flag; }DataType; typedef struct{ DataType data[maxsize]; int top; }SeqStack,*PSeqStack;

typedef struct { btree data[maxsize]; int front,rear; }SeqQueue,*PSeqQueue; typedef struct{ btree data[maxsize]; int top; }SeqStack1,*PSeqStack1; //建立一个二叉树 btree create() { btree t; char ch; scanf("%c",&ch); if(ch=='?') t=NULL; else { t=(btree)malloc(sizeof(bnode)); t->data=ch; t->lchild=create(); t->rchild=create(); } return t; } //先序遍历 //入栈操作 void push1(PSeqStack1 s,btree sq) { if(s->top==maxsize-1) printf("栈满不得入栈"); else { s->top++; s->data[s->top]=sq; } } //出栈操作 void pop1(PSeqStack1 s,btree *sq) { if(s->top==-1) printf("栈空不得出栈");

穷举法

第16章 穷举算法与实验 穷举方法是基于计算机特点而进行解题的思维方法。一般是在一时找不出解决问题的更好途径(即从数学上找不到求解的公式或规则)时,可以根据问题中的的部分条件(约束条件)将所有可能解的情况列举出来,然后通过一一验证是否符合整个问题的求解要求,而得到问题的解。这样解决问题的方法我们称之为穷举算法。穷举算法特点是算法简单,但运行时所花费的时间量大。因此,我们在用穷举方法解决问题时,应尽可能将明显的不符合条件的情况排除在外,以尽快取得问题的解。虽然穷举法效率并不高,但是适应一些没有明显规律可循的问题的解决。 因为穷举算法就是从所有可能的情况中搜索正确的答案,所以一般可按如下步骤: 第1步: 对于一种可能的情况,列举出来并计算其结果; 第2步:判断结果是否满足要求,如果不满足则执行第1步来搜索下一个可能的情况,如果满足要求,则表示寻找到一个正确的答案,执行下一步操作,如寻找其他正确(合适)的答案或者中断循环。 16.1三角形数问题 16.1.1 问题描述 将 ,F ,E ,D ,C ,B ,A 这六个变量排成如图所示的三角形,这六个变量分别取[1,6]上的 整数,且均不相同。求使三角形三条边上的变量之和相等的全部解。如图就是一个解。 A 6 B C 3 1 D F 2 4 E 5 16.1.2 问题分析 程序引入变量123456,,,,,i i i i i i ,代表,F ,E ,D ,C ,B ,A 并让它们分别顺序取1至6的正整数,在它们互不相同的前提条件下,测试由它们排成的如图所示的三角形三条边上的变量之和是否相等,如相等即为一种满足要求的排列,把它们输出。当这些变量取尽所有的组合后,程序就可得到全部可能的解。细节见下面的程序。 【程序1】 %穷举法解三角形数 for i1=1:6 for i2=1:6 if i1==i2 continue;

算法的程序实现——解析法、穷举法

算法的程序实现——解析法、穷举法 一、目标导学: 1、 认识并学会使用解析法、穷举法分析问题、解决问题; 2、 尝试编程实现解析法、穷举法实例。 二、自主探究: 1、解析法: 就是在分析具体问题的基础上,抽取出一个数学模型,这个数学模型能用若干解析表达式表示出来,解决了这些表达式,问题也就得以解决。 用解析法解决问题的关键是寻找________________。 ☆实例:画钻石图案(如右图,教师机展示) 分析:钻石图案是由一个圆周上的各个点的连线组成的,要首先建立一个坐标系,并求出各个点的坐标,然后画线(line 方法)。如右图:可以得出第一个点的坐标是(r*cos(θ),r*sin(θ)),第二个点的坐标是(r*cos(2*θ),r*sin(2*θ)),……依次类推,可得出所有点的坐标。 实现:(1)设置界面。在form1上添加picture1和command1。设置picture1的height 和width 属性相等,command1的caption 属性为“绘制钻石”。 (2)双击command1按钮,打开其代码窗口,输入相关代码。运行验证。

2、穷举法:(枚举法、列举法) 将求解对象一一列举出来,然后逐一加以分析、处理,并验证结果是否满足给定的条件,穷举完所有对象,问题最终得以解决。 ☆实例: 输出100~200间不能被3整除的数。 分析:验证100到200间所有的数,如果满足条件则输出。 实现:在窗体上添加command1按钮,在其代码窗口中输入代码,如右所示。 说明: (1)10个数打印一行,a 为计数变量。i 为要验证的数。 (2)“Print ”为打印一回车,光标跳至下一行;“Print i;” 为在当前位置打印,光标向后移动。 三、交流点拨: 思考:1、我们前面解决的以下问题用的是解析法还是穷举法? “韩信点兵”_________ “圆的周长、面积”__________“水仙花数”__________ 2、穷举法的适用问题的范围? 求解对象是________(有限/无限) 的,________(可/不可)按规则列举。 一元二次方程求根________(可/不可)用穷举法列举? 四、建构拓展: 五、效果评价:

数据结构C语言实现二叉树三种遍历

实验课题一:将下图中的二叉树用二叉链表表示: 1 用三种遍历算法遍历该二叉树,给出对应的输出结果; 2 写一个函数对二叉树搜索,若给出一个结点,根据其是否属于该树,输出true或者false。 3 写函数完成习题4.31(C++版)或4.28(C版教科书)。 #include "stdio.h" #include"malloc.h" typedef struct BiTNode { char data; struct BiTNode *lchild,*rchild; }BiTNode,*BiTree; BiTree Create(BiTree T) { char ch; ch=getchar(); if(ch=='#') T=NULL; else { T=(BiTNode *)malloc(sizeof(BiTNode)); T->data=ch; T->lchild=Create(T->lchild); T->rchild=Create(T->rchild); } return T; } int node(BiTree T) { int sum1=0,a,b; if(T) { if(T!=NULL)

sum1++; a=node(T->lchild); sum1+=a; b=node(T->rchild); sum1+=b; } return sum1; } int mnode(BiTree T) { int sum2=0,e,f; if(T) { if((T->lchild!=NULL)&&(T->rchild!=NULL)) sum2++; e=mnode(T->lchild); sum2+=e; f=mnode(T->rchild); sum2+=f; } return sum2; } void Preorder(BiTree T) { if(T) { printf("%c",T->data); Preorder(T->lchild); Preorder(T->rchild); } } int Sumleaf(BiTree T) { int sum=0,m,n; if(T) { if((!T->lchild)&&(!T->rchild)) sum++; m=Sumleaf(T->lchild); sum+=m; n=Sumleaf(T->rchild); sum+=n; } return sum;

相关文档
最新文档