算法分析与设计实验
一、实验目的
1、熟悉 python 编程环境,包括程序安装
2、熟悉 python 基本语法
3、递归算法程序分析与调试
二、实验工具
Win10 操作系统、python3.7 编译环境、IDLE 编译器
三、实验内容
本次实验是利用递归算法,用 python 中的绘图库 turtle,实现画出科赫雪花。雪
花曲线的构造从一个正三角形开始,把每条边分成三等份,然后以各边的中间长
度为底边,分别向外作正三角形,再把“底边”线段抹掉,这样就得到一个六角
形,它共有 12 条边,再把每条边分成三等份,以各中间部分的长度为底边,向
外作正三角形后,抹掉底边线段,反复进行这一过程,就会得到有个“雪花”样
子的科赫曲线。
四、实验过程
本实验采用递归算法完成曲线绘制:如果 n=0,直接画出长度为 L 的直线。如果
n=1(第一次迭代),画出长度为 L/3 的线段;画笔向左转 60 度再画长度为 L/3
长的线段;画笔向右转 120 度画长度为 L/3 长的线段;画笔再向左转 60 度画出
长度为 L/3 的线段。如果 n>1,第 n 次迭代相当于:第 n-1 次迭代;画笔左转 60
度;n-1 次迭代;画笔右转 120 度;第 n-1 次迭代;画笔左转 60 度;第 n-1 次迭
代。本次实验设 n=3,用 for 遍历循环角度,在最外层的循环执行后,再调用下
一阶及相应的长度。程序代码如下:
import turtle as t
def koch(size, order):
def main():
t.setup(800, 800)
t.penup()
t.goto(-120, 100)
t.pendown()
t.pensize(2)
if order == 0:
t.forward(size)
else:
for angle in [0, 60, -120, 60]:
t.left(angle)
koch(size/3, order-1)
t.pencolor('green')
koch(300, 3)
t.right(120)
koch(300, 3)
t.right(120)
koch(300, 3)
t.done()
t.hideturtle()
main()
五、实验结果与分析
实验二、快速排序算法
一、实验目的
1、熟悉 python 编程环境,独立编写程序实验代码
2、熟悉 python 基本语法
3、快速排序算法程序分析与调试
二、实验工具
Win10 操作系统、python3.7 编译环境、IDLE 编译器
三、实验要求
1、数据可以预充设定,也可以由程序产生随机数,数据个数不限
2、要求给出算法思想或原理
3、要求分析算法复杂度,并与选择排序、插入排序、或合并排序的复杂度作对
比对照
四、实验内容
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据
都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快
速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。如序列
[6,8,1,4,3,9],选择 6 作为基准数。从右向左扫描,寻找比基准数小的数
字为 3,交换 6 和 3 的位置,[3,8,1,4,6,9],接着从左向右扫描,寻找比
基准数大的数字为 8,交换 6 和 8 的位置,[3,6,1,4,8,9]。重复上述过程,
直到基准数左边的数字都比其小,右边的数字都比其大。然后分别对基准数左边
和右边的序列递归进行上述方法。
五、实验步骤
1、设置两个变量 i、j,排序开始的时候:i=0,j=N-1;
2、以第一个数组元素作为关键数据,赋值给 key,即 key=A[0];
3、从 j 开始向前搜索,即由后开始向前搜索(j--),找到第一个小于 key 的值
A[j],将 A[j]和 A[i]互换;
4、从 i 开始向后搜索,即由前开始向后搜索(i++),找到第一个大于 key 的 A[i],
将 A[i]和 A[j]互换;
5、重复第 3、4 步,直到 i=j; (3,4 步中,没找到符合条件的值,即 3 中 A[j]
不小于 key,4 中 A[i]不大于 key 的时候改变 j、i 的值,使得 j=j-1,i=i+1,直
至找到为止。找到符合条件的值,进行交换的时候 i, j 指针位置不变。另外,
i==j 这一过程一定正好是 i+或 j-完成的时候,此时令循环结束)。
六、实验心得
通过本次实验,我更深一步熟悉了 python 的编程环境,python 的基本语法,
了解了快速排序算法的基本思想,即选取数组中一个数为基准数,一次排序过程
中,将比基准数小的都放在它左边,比基准数大的不动。然后经过一次排序,左
边部分都比基准数小,右边都比基准数大,然后对左右两边分别进行同样的排序。
并对快速排序算法程序进行了分析和调试。
七、实验结果截图
八、实验源码
def QuickSort(myList, start, end):
if start < end:
i, j = start, end
base = myList[i]
while i < j:
while (i < j) and (myList[j] >= base):
j = j - 1
myList[i] = myList[j]
while (i < j) and (myList[i] <= base):
i = i + 1
myList[j] = myList[i]
myList[i] = base
QuickSort(myList, start, i - 1)
QuickSort(myList, j + 1, end)
return myList
myList = [6, 1, 2, 7, 9, 3, 4, 5, 10, 8]
print("快速算法排序结果:")
QuickSort(myList, 0, len(myList)-1)
print(myList)
实验三、分治算法
一、实验目的
1、熟悉 python 编程环境,独立编写程序实验代码
2、熟悉 python 基本语法
3、分治算法程序分析与调试
二、实验工具
Win10 操作系统、python3.7 编译环境、IDLE 编译器
三、实验内容
给定平面上 n 个点,找其中的一对点,使得在 n 个点的所有点对中,该点对
的距离最小。主要思想就是分治,先把 n 个点按 x 坐标排序,然后求左边 n/2
个和右边 n/2 个的最近距离,最后合并。 首先,假设点是 n 个,编号为 1 到 n。
我们要分治求,则找一个中间的编号 mid,先求出 1 到 mid 点的最近距离设为 d1,
还有 mid+1 到 n 的最近距离设为 d2。这里的点需要按 x 坐标的顺序排好,并且
假设这些点中,没有 2 点在同一个位置。(若有,则直接最小距离为 0 了)。
然后,令 d 为 d1, d2 中较小的那个点。如果说最近点对中的两点都在 1-mid
集合中,或者 mid+1 到 n 集合中,则 d 就是最小距离了。但是还有可能的是最近
点对中的两点分属这两个集合,所以我们必须先检测一下这种情况是否会存在,
若存在,则把这个最近点对的距离记录下来,去更新 d。这样我们就可以得道最
小的距离 d 了。
关键是要去检测最近点对,理论上每个点都要和对面集合的点匹配一次,那
效率还是不能满足我们的要求。所以需要优化。假如以我们所选的分割点 mid
为界,如果某一点的横坐标到点 mid 的横坐标的绝对值超过 d1 并且超过 d2,那
么这个点到 mid 点的距离必然超过 d1 和 d2 中的小者,所以这个点到对方集合的
任意点的距离必然不是所有点中最小的。所以我们先把在 mid 为界左右一个范围
内的点全部筛选出来,放到一个集合里。筛选好以后,当然可以把这些点两两求
距离去更新 d 了,不过这样效率很低,可能满足条件的点很多。继续优化。
首先把这些点按 y 坐标排序。假设排序好以后有 cnt 个点,编号为 0 到 cnt-1。
那么我们用 0 号去和 1 到 cnt-1 号的点求一下距离,然后 1 号和 2 到 cnt-1 号的
点求一下距离。如果某两个点 y 轴距离已经超过了 d,这次循环就可以直接 break
了,开始从下一个点查找。
四、实验步骤
1、用一条竖直的线 L 将所有的点分成两等份
2、递归算出左半部分的最近两点距离 d1,右半部分的最近两点距离 d2,取
d=min(d1,d2)
3、算出“一个在左半部分,另一个在右半部分”这样的点对的最短距离 d3。
3.1 删除所有到 L 的距离大于 d 的点。 O(n)
3.2 把右半平面的点按照纵坐标 y 排序。 O(nlogn)
3.3 对于左半平面内的每个点 P1,找出右半平面内纵坐标与 P1 的纵坐标的
差在 d 以内的点 P2,计算距离取最小值,算出 d3。
4、结果=min(d1,d2,d3)
五、实验结果
六、实验代码
from math import sqrt
def solve(points):
n = len(points)
min_d = float("inf")
min_ps = None
for i in range(n - 1):
# 最近点对
# 最小距离:无穷大
for j in range(i + 1, n):
d = sqrt((points[i][0] - points[j][0]) ** 2 + (points[i][1]
- points[j][1]) ** 2)
# 两点距离
if d < min_d:
min_d = d
min_ps = [points[i], points[j]]
# 修改最小距离
# 保存最近点对
return min_ps
def nearest_dot(seq):
# 注意:seq 事先已对 x 坐标排序
n = len(seq)
if n <= 2:
return seq
# 若问题规模等于 2,直接解
left, right = seq[0:n // 2], seq[n // 2:]
print(left, right)
mid_x = (left[-1][0] + right[0][0]) / 2.0
lmin = (left, nearest_dot(left))[len(left) > 2]
rmin = (right, nearest_dot(right))[len(right) > 2]
# 左侧最近点对
# 右侧最近点对
dis_l = (float("inf"), get_distance(lmin))[len(lmin) > 1]
dis_r = (float("inf"), get_distance(rmin))[len(rmin) > 1]
d = min(dis_l, dis_r)
left = list(filter(lambda p: mid_x - p[0] <= d, left))
# 最近点对距离
# 中间线左
侧的距离<=d 的点
right = list(filter(lambda p: p[0] - mid_x <= d, right))
# 中间线
右侧的距离<=d 的点
mid_min = []
for p in left:
for q in right:
if abs(p[0] - q[0]) <= d and abs(p[1] - q[1]) <= d:
# 如
果右侧部分点在 p 点的(d,2d)之间
td = get_distance((p, q))
if td <= d:
mid_min = [p, q]
d = td
# 修改最小距离
# 记录 p,q 点对
if mid_min:
return mid_min
elif dis_l > dis_r:
return rmin
else:
return lmin
def get_distance(min):
return sqrt((min[0][0] - min[1][0]) ** 2 + (min[0][1] - min[1][1])
** 2)
def divide_conquer(seq):
seq.sort(key=lambda x: x[0])
res = nearest_dot(seq)
return res
# 测试
seq = [(0, 1), (3, 2), (4, 3), (5, 1), (1, 2), (2, 1), (6, 2), (7, 2),
(8, 3), (4, 5), (9, 0), (6, 4)]
print("空间最近距离的点对为")
print(solve(seq))
实验四:宽度优先查找最短路径
一、实验目的
1、熟悉图的两种常见表示方法,熟练掌握如何在计算机中存储图。了解图
在计算机应用领域常见的应用场景。
2、熟练掌握图上宽度优先搜索算法及其算法复杂度分析,了解利用宽度优
先搜索解决计算问题的建模过程。
3、熟练掌握图上深度优先搜索算法及其算法复杂度分析,了解深度优先算
法的建模过程。
二、实验工具
Win10 操作系统、python3.7 编译环境、IDLE 编译器
三、实验内容
给定无向图 G=(V,E),求从源点 s 到图中各个结点 v∈V 的最近距离。如图 1
所示,从源点 s 到结点 d,c 和 z 的最短距离均为 2,而到结点 f 和 v 的最短距离
则为 3。
四、实验过程
图的存储依然采用邻接列表的方式存储,通过设计一个 Graph 类来表示图。
Graph 类中的成员变量为字典类型变量 adj,用于存储图中每一个结点的邻边,
成员函数 add_edge(u,v)将两个结点 u 和 v 建立连接。设计一个 BFSResult 类来
存储 BFS 的输出结果,一个字典类型的变量 level 来存储各层结点。level 的 key
对应层的结点,level 的 value 则是层的标号。使用一个字典变量 parent 来记
录结点的父结点。