算法分析与设计实验报告 (2)

合集下载

算法分析与设计实验报告--回溯法

算法分析与设计实验报告--回溯法

算法分析与设计实验报告--回溯法实验目的:通过本次实验,掌握回溯法的基本原理和应用,能够设计出回溯法算法解决实际问题。

实验内容:1.回溯法概述回溯法全称“试探回溯法”,又称“逐步退化法”。

它是一种通过不断试图寻找问题的解,直到找到解或者穷尽所有可能的解空间技术。

回溯法的基本思路是从问题的某一个初始状态开始,搜索可行解步骤,一旦发现不满足求解条件的解就回溯到上一步,重新进行搜索,直到找到解或者所有可能的解空间已经搜索完毕。

2.回溯法的基本应用回溯法可用于求解许多 NP 问题,如 0/1 背包问题、八皇后问题、旅行商问题等。

它通常分为两种类型:一种是通过枚举所有可能的解空间来寻找解;另一种则是通过剪枝操作将搜索空间减少到若干种情况,大大减少了搜索时间。

3.回溯法的解题思路(1)问题分析:首先需要对问题进行分析,确定可行解空间和搜索策略;(2)状态表示:将问题的每一种状况表示成一个状态;(3)搜索策略:确定解空间的搜索顺序;(4)搜索过程:通过逐步试探,不断扩大搜索范围,更新当前状态;(5)终止条件:在搜索过程中,如果找到了满足要求的解,或者所有的可行解空间都已搜索完毕,就结束搜索。

4.八皇后问题八皇后问题是指在一个 8x8 的棋盘上放置八个皇后,使得任意两个皇后都不在同一行、同一列或同一对角线上。

通过回溯法可以求解出所有的可能解。

实验过程:回溯法的实现关键在于搜索空间的剪枝,避免搜索无用的解;因此,对于八皇后问题,需要建立一个二维数组来存放棋盘状态,以及一个一维数组来存放每行放置的皇后位置。

从第一行开始搜索,按照列的顺序依次判断当前的空位是否可以放置皇后,如果可以,则在相应的位置标记皇后,并递归到下一行;如果不能,则回溯到上一行,重新搜索。

当搜索到第八行时,获取一组解并返回。

代码实现:```pythondef is_valid(board, row, col):for i in range(row):if board[i] == col or abs(board[i] - col) == abs(i - row):return Falsereturn True实验结果:当 n=4 时,求得的所有可行解如下:```[[1, 3, 0, 2],[2, 0, 3, 1]]```本次实验通过实现回溯法求解八皇后问题,掌握了回溯法的基本原理和应用,并对回溯法的核心思想进行了深入理解。

算法课设实验报告(3篇)

算法课设实验报告(3篇)

第1篇一、实验背景与目的随着计算机技术的飞速发展,算法在计算机科学中扮演着至关重要的角色。

为了加深对算法设计与分析的理解,提高实际应用能力,本实验课程设计旨在通过实际操作,让学生掌握算法设计与分析的基本方法,学会运用所学知识解决实际问题。

二、实验内容与步骤本次实验共分为三个部分,分别为排序算法、贪心算法和动态规划算法的设计与实现。

1. 排序算法(1)实验目的:熟悉常见的排序算法,理解其原理,比较其优缺点,并实现至少三种排序算法。

(2)实验内容:- 实现冒泡排序、快速排序和归并排序三种算法。

- 对每种算法进行时间复杂度和空间复杂度的分析。

- 编写测试程序,对算法进行性能测试,比较不同算法的优劣。

(3)实验步骤:- 分析冒泡排序、快速排序和归并排序的原理。

- 编写三种排序算法的代码。

- 分析代码的时间复杂度和空间复杂度。

- 编写测试程序,生成随机测试数据,测试三种算法的性能。

- 比较三种算法的运行时间和内存占用。

2. 贪心算法(1)实验目的:理解贪心算法的基本思想,掌握贪心算法的解题步骤,并实现一个贪心算法问题。

(2)实验内容:- 实现一个贪心算法问题,如活动选择问题。

- 分析贪心算法的正确性,并证明其最优性。

(3)实验步骤:- 分析活动选择问题的贪心策略。

- 编写贪心算法的代码。

- 分析贪心算法的正确性,并证明其最优性。

- 编写测试程序,验证贪心算法的正确性。

3. 动态规划算法(1)实验目的:理解动态规划算法的基本思想,掌握动态规划算法的解题步骤,并实现一个动态规划算法问题。

(2)实验内容:- 实现一个动态规划算法问题,如背包问题。

- 分析动态规划算法的正确性,并证明其最优性。

(3)实验步骤:- 分析背包问题的动态规划策略。

- 编写动态规划算法的代码。

- 分析动态规划算法的正确性,并证明其最优性。

- 编写测试程序,验证动态规划算法的正确性。

三、实验结果与分析1. 排序算法实验结果:- 冒泡排序:时间复杂度O(n^2),空间复杂度O(1)。

算法分析与设计实验报告合并排序快速排序

算法分析与设计实验报告合并排序快速排序

算法分析与设计实验报告:合并排序与快速排序一、引言算法是计算机科学中非常重要的一部分,它涉及到解决问题的方法和步骤。

合并排序和快速排序是两种经典而常用的排序算法。

本文将对这两种排序算法进行分析和设计实验,通过对比它们的性能和效率,以期得出最优算法。

二、合并排序合并排序是一种分治算法,它将原始数组不断分解为更小的数组,直到最后细分为单个元素。

然后,再将这些单个元素两两合并,形成一个有序数组。

合并排序的核心操作是合并两个有序的数组。

1. 算法步骤(1)将原始数组分解为更小的子数组,直到每个子数组只有一个元素;(2)两两合并相邻的子数组,同时进行排序,生成新的有序数组;(3)重复步骤(2),直到生成最终的有序数组。

2. 算法性能合并排序的最优时间复杂度为O(nlogn),其中n为待排序数组的长度。

无论最好情况还是最坏情况,合并排序的复杂度都相同。

合并排序需要额外的存储空间来存储临时数组,所以空间复杂度为O(n)。

三、快速排序快速排序也是一种分治算法,它将原始数组根据一个主元(pivot)分成两个子数组,一个子数组的元素都小于主元,另一个子数组的元素都大于主元。

然后,递归地对这两个子数组进行排序,最后得到有序数组。

快速排序的核心操作是划分。

1. 算法步骤(1)选择一个主元(pivot),可以是随机选择或者固定选择第一个元素;(2)将原始数组根据主元划分为两个子数组,一个子数组的元素都小于主元,另一个子数组的元素都大于主元;(3)递归地对这两个子数组进行快速排序;(4)重复步骤(2)和(3),直到每个子数组只有一个元素,即得到最终的有序数组。

2. 算法性能快速排序的平均时间复杂度为O(nlogn),其中n为待排序数组的长度。

最坏情况下,当每次选择的主元都是最小或最大元素时,时间复杂度为O(n^2)。

快速排序是原地排序,不需要额外的存储空间,所以空间复杂度为O(1)。

四、实验设计为了验证合并排序和快速排序的性能和效率,我们设计以下实验:1. 实验目的:比较合并排序和快速排序的时间复杂度和空间复杂度。

算法分析与设计实验报告

算法分析与设计实验报告

算法分析与设计实验报告算法分析与设计实验报告一、引言算法是计算机科学的核心,它们是解决问题的有效工具。

算法分析与设计是计算机科学中的重要课题,通过对算法的分析与设计,我们可以优化计算机程序的效率,提高计算机系统的性能。

本实验报告旨在介绍算法分析与设计的基本概念和方法,并通过实验验证这些方法的有效性。

二、算法分析算法分析是评估算法性能的过程。

在实际应用中,我们常常需要比较不同算法的效率和资源消耗,以选择最适合的算法。

常用的算法分析方法包括时间复杂度和空间复杂度。

1. 时间复杂度时间复杂度衡量了算法执行所需的时间。

通常用大O表示法表示时间复杂度,表示算法的最坏情况下的运行时间。

常见的时间复杂度有O(1)、O(log n)、O(n)、O(n log n)和O(n^2)等。

其中,O(1)表示常数时间复杂度,O(log n)表示对数时间复杂度,O(n)表示线性时间复杂度,O(n log n)表示线性对数时间复杂度,O(n^2)表示平方时间复杂度。

2. 空间复杂度空间复杂度衡量了算法执行所需的存储空间。

通常用大O表示法表示空间复杂度,表示算法所需的额外存储空间。

常见的空间复杂度有O(1)、O(n)和O(n^2)等。

其中,O(1)表示常数空间复杂度,O(n)表示线性空间复杂度,O(n^2)表示平方空间复杂度。

三、算法设计算法设计是构思和实现算法的过程。

好的算法设计能够提高算法的效率和可靠性。

常用的算法设计方法包括贪心算法、动态规划、分治法和回溯法等。

1. 贪心算法贪心算法是一种简单而高效的算法设计方法。

它通过每一步选择局部最优解,最终得到全局最优解。

贪心算法的时间复杂度通常较低,但不能保证得到最优解。

2. 动态规划动态规划是一种将问题分解为子问题并以自底向上的方式求解的算法设计方法。

它通过保存子问题的解,避免重复计算,提高算法的效率。

动态规划适用于具有重叠子问题和最优子结构的问题。

3. 分治法分治法是一种将问题分解为更小规模的子问题并以递归的方式求解的算法设计方法。

算法与分析实验报告

算法与分析实验报告

算法与分析实验报告一、引言算法是现代计算机科学中的核心概念,通过合理设计的算法可以解决复杂的问题,并提高计算机程序的执行效率。

本次实验旨在通过实际操作和数据统计,对比分析不同算法的执行效率,探究不同算法对于解决特定问题的适用性和优劣之处。

二、实验内容本次实验涉及两个经典的算法问题:排序和搜索。

具体实验内容如下:1. 排序算法- 冒泡排序- 插入排序- 快速排序2. 搜索算法- 顺序搜索- 二分搜索为了对比不同算法的执行效率,我们需要设计合适的测试用例并记录程序执行时间进行比较。

实验中,我们将使用随机生成的整数数组作为排序和搜索的测试数据,并统计执行时间。

三、实验步骤1. 算法实现与优化- 实现冒泡排序、插入排序和快速排序算法,并对算法进行优化,提高执行效率。

- 实现顺序搜索和二分搜索算法。

2. 数据生成- 设计随机整数数组生成函数,生成不同大小的测试数据。

3. 实验设计- 设计实验方案,包括测试数据的规模、重复次数等。

4. 实验执行与数据收集- 使用不同算法对随机整数数组进行排序和搜索操作,记录执行时间。

- 多次重复同样的操作,取平均值以减小误差。

5. 数据分析与结果展示- 将实验收集到的数据进行分析,并展示在数据表格或图表中。

四、实验结果根据实验数据的收集与分析,我们得到以下结果:1. 排序算法的比较- 冒泡排序:平均执行时间较长,不适用于大规模数据排序。

- 插入排序:执行效率一般,在中等规模数据排序中表现良好。

- 快速排序:执行效率最高,适用于大规模数据排序。

2. 搜索算法的比较- 顺序搜索:执行时间与数据规模成线性关系,适用于小规模数据搜索。

- 二分搜索:执行时间与数据规模呈对数关系,适用于大规模有序数据搜索。

实验结果表明,不同算法适用于不同规模和类型的问题。

正确选择和使用算法可以显著提高程序的执行效率和性能。

五、实验总结通过本次实验,我们深入了解了不同算法的原理和特点,并通过实际操作和数据分析对算法进行了比较和评估。

算法设计与分析实验报告(中南民族大学)

算法设计与分析实验报告(中南民族大学)

院系:计算机科学学院专业:年级:课程名称:算法设计与分析基础班号:组号:指导教师:年月日实验结果及分析1.求最大数2.递归法与迭代法性能比较递归迭代3.改进算法1.利用公式法对第n项Fibonacci数求解时可能会得出错误结果。

主要原因是由于double类型的精度还不够,所以程序算出来的结果会有误差,要把公式展开计算。

2.由于递归调用栈是一个费时的过程,通过递归法和迭代法的比较表明,虽然递归算法的代码更精简更有可读性,但是执行速度无法满足大数问题的求解。

3.在当前计算机的空间较大的情况下,在一些速度较慢的问题中,空间换时间是一个比较周全的策略。

实验原理(算法基本思想)定义:若A=(a ij), B=(b ij)是n×n的方阵,则对i,j=1,2,…n,定义乘积C=A⋅B 中的元素c ij为:1.分块解法通常的做法是将矩阵进行分块相乘,如下图所示:二.Strassen解法分治法思想将问题实例划分为同一问题的几个较小的实例。

对这些较小实例求解,通常使用递归方法,但在问题规模足够小时,也会使用另一种算法。

如果有必要,合并这些问题的解,以得到原始问题的解。

求解矩阵相乘的DAC算法,使用了strassen算法。

DAC(A[],B[],n){If n=2 使用7次乘法的方法求得解ElseDivide(A)//把A分成4块Divide(B)//把B分成4块调用7次strassen算法求得解的4块合并这4块得到解并返回}伪代码Serial_StrassenMultiply(A, B, C) {T1 = A0 + A3;T2 = B0 + B3;StrassenMultiply(T1, T2, M1);T1 = A2 + A3;StrassenMultiply(T1, B0, M2);T1 = (B1 - B3);StrassenMultiply (A0, T1, M3);T1 = B2 - B0;StrassenMultiply(A3, T1, M4);T1 = A0 + A1;StrassenMultiply(T1, B3, M5);T1 = A2 – A0;T2 = B0 + B1;StrassenMultiply(T1, T2, M6);T1 = A1 – A3;T2 = B2 + B3;StrassenMultiply(T1, T2, M7);C0 = M1 + M4 - M5 + M7C1 = M3 + M5C2 = M2 + M4C3 = M1 - M2 + M3 + M6}实验结果及分析时间复杂度1.分块相乘总共用了8次乘法,因而需要Θ(n log28)即Θ(n3)的时间复杂度。

算法设计与分析实验报告

算法设计与分析实验报告

算法设计与分析实验报告实验一全排列、快速排序【实验目的】1. 掌握全排列的递归算法。

2. 了解快速排序的分治算法思想。

【实验原理】一、全排列全排列的生成算法就是对于给定的字符集,用有效的方法将所有可能的全排列无重复无遗漏地枚举出来。

任何n个字符集的排列都可以与1~n的n个数字的排列一一对应,因此在此就以n 个数字的排列为例说明排列的生成法。

n个字符的全体排列之间存在一个确定的线性顺序关系。

所有的排列中除最后一个排列外,都有一个后继;除第一个排列外,都有一个前驱。

每个排列的后继都可以从它的前驱经过最少的变化而得到,全排列的生成算法就是从第一个排列开始逐个生成所有的排列的方法。

二、快速排序快速排序(Quicksort)是对冒泡排序的一种改进。

它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

【实验内容】1.全排列递归算法的实现。

2.快速排序分治算法的实现。

【实验结果】1. 全排列:2. 快速排序:实验二最长公共子序列、活动安排问题【实验目的】1. 了解动态规划算法设计思想,运用动态规划算法实现最长公共子序列问题。

2. 了解贪心算法思想,运用贪心算法设计思想实现活动安排问题。

【实验原理】一、动态规划法解最长公共子序列设序列X=和Y=的一个最长公共子序列Z=,则:i. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;ii. 若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;iii. 若xm≠yn且z k≠yn ,则Z是X和Yn-1的最长公共子序列。

其中Xm-1=,Yn-1=,Zk-1=。

最长公共子序列问题具有最优子结构性质。

由最长公共子序列问题的最优子结构性质可知,要找出X=和Y=的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。

《算法设计与分析》课程实验报告 (回溯法(二))

《算法设计与分析》课程实验报告 (回溯法(二))

《算法设计与分析》课程实验报告实验序号:10实验项目名称:实验十一回溯法(二)一、实验题目1.图的着色问题问题描述:给定无向连通图G和m种不同的颜色。

用这些颜色为图G的各顶点着色,每个顶点着一种颜色。

如果有一种着色法使G中每条边的2个顶点着不同颜色,则称这个图是m可着色的。

图的m着色问题是对于给定图G和m种颜色,找出所有不同的着色法。

2.旅行商问题问题描述:给出一个n个顶点的带权无向图,请寻找一条从顶点1出发,遍历其余顶点一次且仅一次、最后回到顶点1的最小成本的回路——即最短Hamilton回路。

3.拔河比赛问题描述:某公司的野餐会上将举行一次拔河比赛。

他们想把参与者们尽可能分为实力相当的两支队伍。

每个人都必须在其中一只队伍里,两队的人数差距不能超过一人,且两队的队员总体重应该尽量接近。

4.批处理作业调度问题描述:给定n个作业的集合J=(J1,J2, .. Jn)。

每个作业J都有两项任务分别在两台机器上完成。

每个作业必须先由机器1处理,再由机器2处理。

作业i需要机器j的处理时间为tji(i=1,2, ..n; j=1,2)。

对于一个确定的作业调度,设Fji是作业i在机器j上完成处理的时间,则所有作业在机器2上完成处理的时间和,称为该作业调度的完成时间和。

批处理作业调度问题要求,对于给定的n个作业,制定最佳作业调度方案,使其完成时间和达到最小。

二、实验目的(1)通过练习,理解回溯法求解问题的解状态空间树与程序表达的对应关系,熟练掌握排列树、子集树的代码实现。

(2)通过练习,体会减少搜索解空间中节点的方法,体会解的状态空间树的组织及上界函数的选取对搜索的影响。

(3)通过练习,深入理解具体问题中提高回溯算法效率的方法。

(4)(选做题):在掌握回溯法的基本框架后,重点体会具体问题中解的状态空间搜索时的剪枝问题。

三、实验要求(1)每题都必须实现算法、设计测试数据、记录实验结果,并给出时间复杂度分析。

四、实验过程(算法设计思想、源码)1.图的着色问题(1)算法设计思想用邻接矩阵a[i][j]存储无向图,对于每一个顶点有m种颜色可以涂。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

算法分析与设计上机实验报告课程名称:算法分析与设计班级:实验日期:姓名:学号:指导教师:许晓华实验名称:最优二叉搜索树实验地点:主楼1114实验成绩:一、实验目的及要求1.进一步掌握最优二叉树的含义。

2.掌握最优二叉树的结构特征。

3.认真阅读和掌握动态规划法秋最有搜索二叉树实验的程序。

4.上机运行本程序。

5.保存和打印出程序的运行结果,并结合程序进行分析。

6.按照你二叉树的操作需要,可重新改写主程序并运行,请上交文件清单和运行结果二、实验环境及设备微机一台:Intel 酷睿2双核操作系统:Microsoft Windows XP Professional工具软件:Microsoft Visual C++ 6.0三、实验内容及实验步骤动态规划——最优二叉查找树1,问题描述:给定一个有序序列K={k1<k2<k3<,……,<kn}和他们被查询的概率P={p1,p2,p3,……,pn},要求构造一棵二叉查找树T,使得查询所有元素的总的代价最小。

对于一个搜索树,当搜索的元素在树内时,表示搜索成功。

当不在树内时,表示搜索失败,用一个“虚叶子节点”来标示搜索失败的情况,因此需要n+1个虚叶子节点{d0<d1<……<dn}。

其中d0表示搜索元素小于k1的失败结果,dn表示搜索元素大于kn的失败情况。

di(0<i<n)表示搜索节点在ki和k(i+1)之间时的失败情况。

对于应di的概率序列是Q={q0,q1,……,qn}。

2,问题分析:在二叉树中T内搜索一次的期望代价为:E[T]=(depth(ki)+1)*pi //对每个i=1~n,搜索成功情况+(depth(di)+1)*qi //对每个i=0~n,搜索失败情况3,问题求解:动态规划步骤一:寻找最优子结构。

一个最优二叉树的子树必定包含连续范围的关键字ki~kj,1<=i<=j<=n,同时也必须含有连续的虚叶子节点di-1~dj。

如果一棵最优二叉查找树T有一棵含有关键字ki~kj的子树T',那么,T'也是一棵最优查找树,这通过剪贴思想可以证明。

现在开始构造最优子结构:在ki~kj中,选定一个r,i<=r<=j,使以kr为根,ki~k(r-1)和k(r+1)~kj为左右孩子的最优二叉树。

注意r=i或者r=j的情况,表示左子树或右子树只有虚叶子节点。

步骤二:一个递归解。

定义e[i,j]为一棵包含关键字ki~kj的最优二叉树的期望代价。

当j=i-1时没有真实的关键在,只有虚叶子节点d(i-1)。

于是:当j=i-1时,e[i,i-1]=q(i-1)。

当j>=i时,需要选择合适的kr作为根节点,然后其余节点ki~K(r-1)和k(r+1)~kj构造左右孩子。

这时要考虑左右孩子这些节点成为一个节点的子树后,它的搜索代价的变化:根据E[T]的计算,得知它们的期望代价增加了“子树中所有概率的总和”w。

w[i,j]=pl // 对每个l=i~j+ql //对每个l=i-1~j于是当j>=i时,e[i,j]=pr + (e[i,r-1]+w[i,r-1])+(e[r+1,j]+w[r+1,j]) = e[i,r-1] + e[r+1,j]+w[i,j];步骤三:计算最优二叉树的期望代价e[i,j]=q(i-1) //如果j=i-1min(e[i,r-1] + e[r+1,j]+w[i,j]),如果i<=j,其中i<=r<=jw[i,j] =q(i-1) 如果j=i-1w[i,j]=w[i,j-1]+pj+qj 如果i<=j实现代码如下:view plaincopy to clipboardprint?1 #include <iostream>2 using namespace std;34 #define MAXNUM 1005 #define MAX 655366 //p中为有序关键字k1到k5的搜索概率,k1<k2<k3<k4<k57 double p[MAXNUM] = {0.00,0.15,0.10,0.05,0.10,0.20};8 double q[MAXNUM] = {0.05,0.10,0.05,0.05,0.05,0.10};9 void optimal_bst(double e[][MAXNUM],int root[][MAXNUM],double w[][MAXNUM],int n)10 {11 int i =0,j=0;12 //针对左或右孩子为空树情况初始化13 for(i = 1;i<=n+1;i++)14 {15 e[i][i-1] = q[i-1];16 w[i][i-1] = q[i-1];17 }18 int l = 0;19 //计算顺序如下:根据计算式:e[i,j] = e[i,r-1]+e[r+1,j首先计算节点个数为1的最优二叉树的代价e[1,1],e[2,2]……接着计算节点个数为1的最优二叉树的代价e[1,2],e[2,3]…………最后计算结点个数为n的最优二叉树的代价e[1,n],利用之前保存的较少结点最优二叉树的结果。

20 for(l = 1;l<=n;l++)21 {22 for(i = 1;i<=n-l+1;i++)23 {24 j = i+l-1;25 e[i][j] = MAX;26 w[i][j] = w[i][j-1] + p[j]+q[j];27 for(int r = i;r<=j;r++)28 {29 do uble t = 0;30 t = e[i][r-1]+e[r+1][j] + w[i][j];31 if (t<e[i][j])32 {33e[i][j]= t;34root[i][j] = t;35 }36 }3738 }39 }4041 }42 int main()43 {44 double e[MAXNUM][MAXNUM];45 int root[MAXNUM][MAXNUM];46 double w[MAXNUM][MAXNUM];4748 optimal_bst(e,root,w,5);4950 for(int i =1;i<=6;i++)51 {52 for(int j = 0;j<=5;j++)53 {54 cout << e[i][j] << " ";55 }56 cout << endl;57 } 这是一个经典的动态规划问题(但厉害的是其中带有一个很神奇的定理),问题是这样的:已知二叉搜索树中每个节点的访问概率,问这棵树整体的搜索时间最短是多少(此时称为最优二叉搜索树)。

众所周知,在二叉搜树中,一次搜索的时间等于待访问节点的深度。

所以整体的搜索时间为:节点i的访问概率 * 节点i的深度所以如果要整体搜索时间最短,则访问概率高的节点应该比较靠近根节点。

乍一听,好像是哈夫曼编码。

但是不同的是,这是二叉搜索树,所有节点的左右顺序(这里指中序遍历的顺序)不能变化。

所以无法像哈夫曼编码那样一味地把概率高的节点往上移(那是一个贪心算法)。

那该怎么办呢?其实我们只要想到这样一个递推关系:一棵树如果是最优二叉搜索树,那么要么它是空树,要么它的左、右子树也是最优二叉搜索树。

这样就得到了动态规划的解法:For size = 1到nFor 所有包含size个元素的子树For 该子树的所有节点i找出其中一个i,使当它为根节点时,左、右子树的最短搜索时间之和最小。

那么该子树的访问时间就是:左、右子树的最短搜索时间之和 + 所有节点的访问概率之和(因为所有节点都下降了一层)。

可见,这个算法的时间复杂度是O(n^3)。

但是有一个神奇的定理,可以把算法的时间效复杂度降到O(n^2),如下:设一个子树的节点为i ~ j(当然,这里说的i ~ j都是从小到大排好序的),则当它是最优二叉搜索树时的根节点root(i, j)满足:root(i, j - 1) <= root(i, j) <= root(i + 1, j)。

这样一来,上面那个算法的第3个For就可以不用循环子树中的所有节点了,只要循环另两个子树的根节点之间的范围就可以了。

而这个范围根据实践表明是很小的。

所以整体的时间复杂度就相当于两层For循环而已。

===========================================//最优二叉搜索树的动态规划算法代码如下:#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <string.h>typedef struct matrix{int row;int col;} matrix;typedef struct minCost{int cost;int mid;} minCost;minCost** func(matrix* mt, ssize_t count){int i, j, step, min, temp, mid;minCost **rows;rows = (minCost **)malloc(count*(sizeof(minCost*)));for(i=0;i<count;i++)rows[i] = (minCost *)malloc((count-i)*sizeof(minCost));for(i=0;i<count;i++){rows[i][0].cost=0;rows[i][0].mid=-1;}for(step=1;step<count;step++)for(j=0;j<count-step;j++){min=mt[j].row*mt[j].col*mt[j+step].col+rows[j][0].cost+rows[j+1][step-1].cost;mid=j;for(i=1;i<step;i++){temp=rows[j][i].cost+rows[j+i+1][step-i-1].cost+mt[j].row*mt[j+i].col*mt[j+step].col;if(min>temp){min=temp;mid=j+i;}}rows[j][step].cost=min;rows[j][step].mid=mid;}printf("%d, %d\n", rows[0][count-1].cost, rows[0][count-1].mid); return rows;}void rel(minCost **mc, ssize_t count){int i;for(i=0;i<count;i++)free(mc[i]);free(mc);}int main(int argc, char *argv[]){minCost **temp;matrix ma[]={{30,35},{35,15},{15,5},{5,10},{10,20},{20,25}};temp=func(ma, sizeof(ma)/sizeof(ma[0]));rel(temp, sizeof(ma)/sizeof(ma[0]));return 0;}四、调试过程及实验结果上程序调试运行的结果为:15125 , 2虽然使用动态规划法可以构造出最优二叉搜索树,但on3的时间复杂性仍然显得太高。

相关文档
最新文档