实验项目1:蛮力法与分治法应用1、目的与要求:实验目的:了解蛮力法和分治法的基本思想,学会运用蛮力法和分治法解决实际系统设计应用中碰到的问题。
实验要求:用蛮力法实现选择、冒泡排序,或旅行商问题、背包问题等问题(任选其中之一)。
用分治法实现合并排序或快速排序。
要求写出算法的伪代码描述,并编写程序实现之,相关算法放在函数实现,主程序给出测试用例,要设计足够多的相关测试用例,验证程序的正确性。
注意观察程序执行结果和运行的时间。
实验报告要求给出问题定义及算法的伪代码描述,程序设计的代码,算法的测试用例及结果,并分析算法的时间效率,回答指导书中的思考题。
2、实验容:(2)用分治法实现快速排序、合并排序算法。
本实验主要是用分治法实现合并排序,快速排序程序等。
合并排序算法描述:MergeSort ( A[0...p-1] )// input 待排序数组A[0..n-1]// output 非降序排列的数组A[0..n-1]if ( n>1 ) {//至少有2个元素Copy A[0.. n/2-1 ] to B[0.. n/2-1 ];Copy A[n/2..n-1 ] to C[0.. n/2-1 ];MergeSort ( B[0.. n/2-1 ] );MergeSort (C[0.. n/2-1 ]t);Merge (B, C, A); //复制回数组a快速排序算法描述:QuickSort ( A[1.. r ] ){if (l<r) s=Partition( A[l,r] ); // s 是分裂位置QuickSort ( A[l..s-1] ); //对左半段排序QuickSort ( A[s+1,r); //对右半段排序}Partition ( A[l..r] ){p=A[[l] ;i = l; j = r + 1;repeatedrepeated i=i+1; until A[i]> p // 将>= x的元素交换到左边区域repeated i=i+1; until A[i]> p // <= x的元素交换到右边区域Swap( A[i], A[j] )Until i>jSwap( A[i] = a[j] );Swap( A[l], A[j] )return j;要求先给出算法的伪代码,然后用C++或其他程序设计语言编写程序实现之,并设计相关的测试用例,验证程序的正确性。
测试用例要求达到30个数据以上,或程序生成100个以上的数据,验证并说明程序的正确性。
上述实验项目是一般要求,的如学生水平较高,上述这些程序已经掌握,可以设计其他难度较高问题的算法和程序。
如:hanoi 塔问题。
最后要求结合实验体会,分析算法的时间效率。
实验思考题:1、蛮力法的优缺点是什么?适用什么情况?2、分治法的基本思想是什么?适用什么情况?说明分治法的优点和局限性。
实验代码:#include<iostream>using namespace std;inline void Swap(int &x,int &y) //交换x,y{int temp=x;x=y;y=temp;}int Partition(int a[],int p,int r) //通过一趟排序将要排序的数据分割成独立的两部分//Partition 以确定一个基准元素a[q] 对子数组a[p:r]进行划分{int i=p,j=r+1;int x=a[p];//一部分的所有数据都比另外一部分的所有数据都要小while(true){while(a[++i]<x&&i<r); //将<x的元素交换到左边区域while(a[--j]>x); //将>x得元素交换到右边区域if(i>=j) break;Swap(a[i],a[j]); //交换a[i],a[j]}a[p]=a[j];a[j]=x;return j; //返回划分点}void QuickSort(int a[],int p,int r) //利用递归进行快速排序{if(p<r){int q=Partition(a,p,r); //Partition返回划分点j,此处使q=j q 为分裂点QuickSort(a,p,q-1); //对左半段排序QuickSort(a,q+1,r); //对右半段排序}}int main(){int len;cout<<"请输入数组长度: ";cin>>len;int *a=new int[len]; //动态生成一个长度为len的数组cout<<"请输入一个数组: ";for(int i=0;i<len;i++) //输入数组cin>>a[i];QuickSort(a,0,len-1); //对数组进行快排cout<<"排序后的数组是:";for(int j=0;j<len;j++)cout<<a[j]<<" "; //输出数组cout<<endl;delete[] a;return 0;}测试结果图:图1:图2:30组数据测试图:代码://递归实现合并排序#include "stdafx.h"#include <iostream>using namespace std;int a[] = {10,5,9,4,3,7,8};int b[7];template <class Type>void Merge(Type c[],Type d[],int l,int m,int r);template <class Type>void MergeSort(Type a[],int left,int right);int main(){for(int i=0; i<7; i++){cout<<a[i]<<" ";}cout<<endl;MergeSort(a,0,6);for(int i=0; i<7; i++){cout<<a[i]<<" ";}cout<<endl;}template <class Type>void Merge(Type c[],Type d[],int l,int m,int r) {int i = l,j = m + 1,k = l;while((i<=m)&&(j<=r)){if(c[i]<=c[j]){d[k++] = c[i++];}else{d[k++] = c[j++];}}if(i>m){for(int q=j; q<=r; q++){d[k++] = c[q];}}else{for(int q=i; q<=m; q++){d[k++] = c[q];}}}template <class Type>void MergeSort(Type a[],int left,int right){if(left<right){int i = (left + right)/2;MergeSort(a,left,i);MergeSort(a,i+1,right);Merge(a,b,left,i,right);//合并到数组b//复制回数组afor(int g=left; g<=right; g++){a[g] = b[g];}}}测试结果图:图1:图2:图3:30组数据测试图:分治法的基本思想:任何一个可以用计算机求解的问题所需的计算时间都与其规模N有关。
问题的规模越小,越容易直接求解,解题所需的计算时间也越少。
例如,对于n 个元素的问题,当n=1时,不需任何计算;当n=2时,只要作一次比较即可排序好;当n=3时只要做3次比较即可,…。
而当n较大时,问题就不那么容易处理了。
要想直接解决一个规模较大的问题,有时是相当困难的。
适用什么情况?分治法所能解决的问题一般具有以下几个特征:1) 该问题的规模缩小到一定的程度就可以容易地解决2) 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质。
3) 利用该问题分解出的子问题的解可以合并为该问题的解;4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
上述的第一条特征是绝大多数问题都可以满足的,因为问题的计算复杂性一般是随着问题规模的增加而增加;第二条特征是应用分治法的前提它也是大多数问题可以满足的,此特征反映了递归思想的应用;第三条特征是关键,能否利用分治法完全取决于问题是否具有第三条特征,如果具备了第一条和第二条特征,而不具备第三条特征,则可以考虑用贪心法或动态规划法。
第四条特征涉及到分治法的效率,如果各子问题是不独立的则分治法要做许多不必要的工作,重复地解公共的子问题,此时虽然可用分治法,但一般用动态规划法较好。
说明分治法的优点和局限性。
优点:将待求解的问题分解成若干子问题,先求解子问题,然后再从这些子问题的解得到原问题的解;分治法中子问题相互独立。
局限性:分治法中对于每次出现的子问题均求解,导致同样的子问题被反复求解,故产生指数增长的时间复杂度,效率较低。