1、分治法算法分析作业 吴迪2011-3-29本次是第一次算法作业,该部分内容包含3个题目的程序代码,分析文档,说明图片等内容目录引言31算法性能比较31.1问题分析31.2源程序代码31.3运行示例81.4数据分析8(单次录入数据具有较大随机误差,只看增长趋势)82循环赛问题92.1问题描述92.2问题分析92.3 源程序102.4运行示例113最大最小值问题123.1问题描述与分析123.2源程序133.3运行示例14引言任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。分治法是计算机科学中经常使用的一种算法。设计思想是,将一
2、个难以直接解决的大问题,分割成一些规模较小的相同问题,以便各个击破,分而治之。但是不是所有问题都适合用分治法解决。当求解一个输入规模为n且取值又相当大的问题时,使用蛮力策略效率一般得不到保证。因此分治策略将问题划分成k个子问题分别求解合并能有效提高计算效率。1算法性能比较1.1问题分析比较插入排序,合并排序和快速排序性能。算法性能比较通常是从时间复杂度的角度进行的。排序算法的复杂度主要和算法中的比较次数和元素交换或移动次数有关。因而在不同大小规模的问题中通过统计这两者之和来评判算法的优劣。同时也可以证明各种算法的时间复杂度与问题规模n之间的关系。特别说明:本程序中考虑到不同规模的乱序数据输入过
3、程比较复杂,编写了一个规模n的整型数据随机排列函数,能够直接生成指定大小的1-n无序整数列。1.2源程序代码/2011年3月19日0:20:02 /main test.cpp for test#include#includeusing namespace std; /全局标记比较次数和移动次数 int count_compare=0;int count_move = 0;int count_all() return count_compare+count_move; void clear_count() count_compare=0; count_move = 0; /insert sort
4、 void insert_element(int a,int size,int element) /size before insertion int i=0; for(i=size-1;i=0;i-) count_compare+; if(elementai) ai+1=ai;count_move+; else break; ai+1=element; count_move+;void InsertSort(int a,int size) for(int i=1;isize;i+) insert_element(a,i,ai); /merge sortvoid Merge(int c,int
5、 d, int l, int m, int r) int i = l, j = m+1, k = l; while(i = m & j = r) count_compare+; if(ci m) for(int q = j; q = r; q +) dk+ = cq; count_move+; else for(int q = i; q = m; q +) dk+ = cq; count_move+; void Copy(int a,int b,int l,int r)for(int i=l;i=r;i+) ai=bi; count_move+; void MergeSort(int a,in
6、t left,int right,int size) if(left right) count_compare+; int i = (right + left)/2; int p=size; /this is important,mind the value! int *b=new intp; MergeSort(a, left, i,size); MergeSort(a, i+1, right,size); Merge(a, b, left, i, right); Copy(a,b,left,right); /quick sortvoid swap(int a,int i,int j) in
7、t temp=ai; ai=aj; aj=temp; count_move+=3;int partition(int a,int p,int r) int i=p,j=r+1; int x=ap; while(true) while(a+ix&ix) count_compare+; count_compare+; if(i=j) break; swap(a,i,j); ap =aj; aj = x; count_move+; return j;void QuickSort(int a,int p ,int r) if (p r) int q= partition(a, p , r); Quic
8、kSort(a,p,q-1); QuickSort(a,q+1,r); count_compare+; /showvoid show_array(int a,int size) /显示一个数组的所有元素 for(int i=0;isize;i+) cout ai ; cout endl;/random arrayvoid RandomArray(int a,int size) /随机生成数组含n个元素,其元素各不相同 srand(time(NULL); for(int i=0;isize;i+) ai=0; for(int i=1;i=size;i+) int p=rand()%size; w
9、hile(ap!=0) p=(+p)%size; ap=i; show_array(a,size); /copy arrayvoid CopyArray(int a,int b,int size) for(int i=0;isize; a=new int size; temp_a = new int size; RandomArray(temp_a,size); CopyArray(temp_a,a,size); show_array(a,size); InsertSort(a,size); show_array(a,size); cout 插入排序比较次数为 count_compare en
10、dl; cout 插入排序移动次数为 count_move endl; cout 总规模为 count_all() endl; clear_count(); CopyArray(temp_a,a,size); show_array(a,size); MergeSort(a,0,size-1,size); show_array(a,size); cout 合并排序比较次数为 count_compare endl; cout 合并排序移动次数为 count_move endl; cout 总规模为 count_all() endl; clear_count(); CopyArray(temp_a,
11、a,size); show_array(a,size); QuickSort(a,0,size-1); show_array(a,size); cout 快速排序比较次数为 count_compare endl; cout 快速排序移动次数为 count_move endl; cout 总规模为 count_all() endl; show_array(a,size); system(pause); return 0; 1.3运行示例1.4数据分析(单次录入数据具有较大随机误差,只看增长趋势)问题规模(n)排序总复杂度规模(T(n)插入排序合并排序快速排序1057105502022128012
12、2303674612384094666037150139487943280326115708561004694206410642002291247182447500130133136687368100050425430309170031000043898103401968225489根据列表分析,插入算法平均复杂度为(n2), 合并算法平均复杂度为(nlogn), 快速排序算法平均复杂度为(nlogn),但是排序算法最坏情况下复杂度仍为(n2),为了验证这一点,取n=1000的已排好数组,快排总规模变为503497,取n=10000的已排好数组,快排总规模变为50034997。说明快排算法对已
13、经基本排好的数组反而耗时间更多。2循环赛问题2.1问题描述设有n个运动员要进行网球循环赛。设计一个满足下列条件的比赛日程表:每个选手必须与其他n-1个选手各赛一次;每个选手一天只能赛一次;当n是偶数时,循环赛进行n-1天。当n是奇数时,循环赛进行n天。2.2问题分析当n= (k=1、2、3、4,,n=2、4、8、16,)时,此时问题比较简单。按照分治的策略,可将所有参赛的选手分为两部分,n个选手的比赛日程表就可以通过为n/2个选手设计的比赛日程表来决定。递归地执行这种分割,直到只剩下2个选手时,比赛日程表的制定就变得很简单:只要让这2个选手进行比赛就可以了。再逐步合并子问题的解即可得到原问题的
14、解。推广当n为任意整数时:当n小于或等于1时,没有比赛。当n是偶数时,至少举行n-1轮比赛.当n是奇数时,至少举行n轮比赛,这时每轮将会有一支球队轮空。因此应对策略如下:(1)当n/2为偶数时,与n= 情形类似,可用分治法求解。(2)当n/2为奇数时,递归返回的轮空的比赛要作进一步处理。可以在前n/2轮比赛中让轮空选手与下一个未参赛选手进行比赛。2.3 源程序#includeusing namespace std;int a100100;int b100;bool odd(int n) /判断n奇偶性 return n&1; /n为奇数,返回1,n为偶数,返回0void copyodd(int
15、 n) / n/2为奇数时的合并算法 int m=n/2; for(int i=0;im;i+) bi=m+i; bm+i=bi; for(int i=0;im;i+) /由左上角小块的值算出相应的左下角小块的值 for(int j=0;j=m) aij=bi; am+ij=(bi+m)%n; else am+ij=aij+m; /由左上角小块的值算出相应的右上角和右下角小块的值 for(int j=1;jm;j+) aim+j=bi+j; abi+jm+j=i; void copy(int n) int m=n/2; for(int i=0;im;i+) for(int j=0;j1&odd
16、(n/2) copyodd(n); /n/2为奇数时 else copy(n);void tourna(int n) /改进的分治赛算法 if(n=1)a00=0;return; if(odd(n)tourna(n+1);return; /n为奇数,分治 tourna(n/2); /n为偶数,分治 makecopy(n); /合并int main() int n; cout 请输入参数队数:n; tourna(n); cout 参数日程表为:endl; for(int i=0;in;i+) for(int j=0;jn;j+) cout aij ; cout endl; system(paus
17、e); return 0; 2.4运行示例3最大最小值问题3.1问题描述与分析在含有n个不同元素的集合中同时找出它的最大和最小元素算法思想:先相邻两个两个比较,较大的放入数组max,较小的放入数组min,然后从max数组求出最大,min数组求出最小即可。从算法描述中可以看出,占据算法的主要执行次数的是比较过程,因此算法的复杂性主要跟比较次数相关Tn=01Tn/2+Tn/2+2 当n是2的幂时,即对于某个正整数k,n=2k,有T(n)=2T(n/2)+2=2(2T(n/4)+2)+2=2*2T(n/4)+2*2+2.=2k-1+2k-2=3n/2-2这是最优情况,平均则比直接比较少25%3.2源
18、程序/find max and min#include using namespace std; void Max_Min(int a,int n) int m = (n+1)/2; int maxm; int minm; int k = 0, j = 0; if(n/2 != 0) maxm-1 = minm-1 = an-1; for (int i=0; i = ai+1) maxj+ = ai; mink+ = ai+1; else maxj+ = ai+1; mink+ = ai; for( int i=0; i m; i+) cout max i = maxi t; cout min i = mini endl; int MAX = max0; int MIN = min0; for ( j = 1; j MAX) MAX = maxj; if (minj MIN) MIN = minj; cout MAX = MAX , MIN = MIN endl; int main(void) int a = 6,16,3,13,6,5,7,8,9,10,2,8,6; int n = sizeof(a)/sizeof(a0); Max_Min(a,n); system(pause); return 0;3.3运行示例