实验目的和要求:
1.递归:掌握递归算法的两个基本组成、编程实现、时间分析;
使用turtle模块实现递归可视化。
2.分治:掌握分治法的设计思想、求解步骤、掌握用分治法解题的算法框架。
实验内容和原理:
1.递归:分形树(自相似递归图形)
问题描述:
分形是在不同尺度上都具有相似性的事物,树的树枝形状也具有分形的特点,我们能看出,一棵树的每个分叉和每条树枝,实际上都具有整棵树的外形特征。这样我们可以把树分解成三个部分:树干、左边的树枝、右边的树枝。这样的分解正符合递归的定义:对自身的调用。
编程任务:
用turtle模块+递归算法,设计自己的分形树
2.分治:Gray码问题
问题描述
Gray码是一个长度为2n的序列。序列中无相同的元素,每个元素都是长度为n位的串,相邻元素恰好只有一位不同。用分治策略设计一个算法对任意的n构造相应的Gray码。
编程任务
利用分治策略试设计一个算法对任意的n构造相应的Gray码。
数据输入
从键盘输入或程序自动产生随机数作为输入数据n。
结果输出
程序运行结束时,将得到的所有Gray码输出到屏幕
源程序:
1.分形树:
import turtle as tt
import random
#花朵
def point(n,m,s1,s2):#在当前位置和当前位置附近画点,m:附近距离、s1,s2:点的颜色——组合成一朵花
tt.dot(n, s1)#n:点的直径,s1:点的颜色
tt.penup()
tt.backward(m)#另一个位置画点
tt.pendown()
tt.dot(n//2, s2)#直径和颜色不一样
tt.penup()
tt.forward(m)#回到原来的位置
tt.pendown()
def branch(l):#产生4枝树枝
a=random.randint(0,l/2)#树枝长度随机
tt.forward(a)#随机长度枝干
tt.dot(8,"lightcoral")#树枝上画一个有颜色的点
tt.backward(a)#回到原来位置
#重复
b=random.randint(0,l/2)
tt.right(20)
tt.forward(b)
tt.dot(8, "lightcoral")
tt.backward(b)
tt.left(40)
c=random.randint(0,l/2)
tt.forward(c)
tt.dot(8, "lightcoral")
tt.penup()
tt.backward(c)
tt.right(20)
tt.pendown()
def tree(l,ps):
if l<=5:
# tt.froward(l)
point(17,3,"lightcoral","RosyBrown2")#画树枝上的花花
return
else:
if l <=150:
point(10,3, "sky blue", "RosyBrown2")
branch(l)
tt.color("LightSalmon4")
tt.pensize(ps)
tt.forward(l)
tt.right(20)#顺时针20度角
tree(l-30,ps*0.8)#子枝干的粗细是母枝的0.8,长度比母枝少30
tt.left(40)#逆时针40度角
tree(l-30,ps*0.8)
tt.right(20)
tt.backward(l)#回到枝干起始位置
tt.bgcolor(0.5,0.5,0.5)#设置黑色背景色
tt.penup()
tt.goto(0,-400)#起点位置
tt.speed(10)#画笔速度
tt.pendown()
tt.left(90)#设置画笔方向竖直
tree(200,5)#主干长度为200,主干粗细参数为5
# tt.hideturtle()
tt.done()
先画“树干”,每次画“树枝”时递归调用自身,并使规模减小,最后达到画树的结果。
2.Gray码:
# 构造w位格雷码,n为格雷码的个数
def gray(w,n):
# 如果格雷码宽度为1
if w == 1:
arr[0][0] = 0
arr[1][0] = 1
return
# 格雷码最高位
for i in range(int(n / 2)):
# 生成的格雷码前一半最高位填“0”
arr[i][int(w - 1)] = 0
# 后一半最高位位填“1”
arr[int(n / 2 + i)][int(w - 1)] = 1
# Output(arr)
gray(w - 1, int(n / 2))
# 生成w - 1位格雷码,填写到目标码高半部分
n1 = int(n / 2)
# print(n1)
for i in range(n1,n): # 填入格雷码低半部分
for j in range(w - 1):
arr[i][j] = arr[n - i - 1][j]
# 主函数
width = int(input("输入Gray码的宽度:"))
num = 2 ** width
arr = [[None for i in range(width)] for i in range(num)] # 定义Gray码的存储结构
# arr1=[]
# for k in range(0,width):
# arr1.append(0)
# arr=[]
# for k in range(0,num):
# arr.append(arr1)
gray(width,num)
for i in range(int(len(arr))):
# s=(str)(arr[i])
print(arr[i])
先将码分为上下两段,上段为上次递归结果,下段为上段的翻转,然后上段和下端处理后合并为最终结果
讨论、心得:
- 使用递归时可以简化算法思路,有时也能减小算法的时间复杂度。
- Turtle可以实现画图,用递归来减小问题规模,最终实现画树。
3.分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,如果子问题的答案都求出来了,就可以求出原问题的答案。
4.(n+1)位格雷码中的前个码字等于n位格雷码的码字,按顺序书写,加前缀0;
(n+1)位格雷码中的后个码字等于n位格雷码的码字,按逆序书写,加前缀1;
(n+1)位格雷码的集合=n位格雷码集合(顺序)加前缀0+n位格雷码集合(逆序)加前缀1