分治的基本概念:把一个任务,分成形式和原任务相同,但规模更小的几个部分任务(通常是两个部分),分别完成,或只需要选一部分完成。然后再处理完成后的这一个或几个部分的结果,实现整个任务的完成。
例题:归并排序
数组的排序可以先把前一半排序,在把后一半排序,然后把两半归并到一个新的有序数组,然后再拷贝到原数组,排序完成。
思考:将前一半排序时又要将这一半分成前一半和后一半进行排序,即利用递归的思想进行排序,假设数组的前一半和后一半在原数组内已经排号序了,将两个排号序的数组序列合并一起即可(要求合并后的数组仍是排好序的),这时需要另一个数组当中介。
public void mergesort(int a[],int s,int e,int tmp[]) { if(s==e) { return; } if(s<e) { int mid=s+(e-s)/2; mergesort(a,s,mid,tmp); mergesort(a,mid+1,e,tmp); merge(a,s,mid,e,tmp); } } public void merge(int a[],int s,int mid,int e,int tmp[]) { int pb=0; int p1=s; int p2=mid+1; while(p1<=mid&&p2<=e) { if(a[p1]<a[p2]) { tmp[pb++]=a[p1++]; } else tmp[pb++]=a[p2++]; } while(p1<=mid) { tmp[pb++]=a[p1++]; } while(p2<=e) { tmp[pb++]=a[p2++]; } for(int i=0;i<e-s+1;i++) { a[s+i]=tmp[i]; } }收获:书写程序时 tmp[pb++]=a[p1++]; 这样书写更简明扼要,我们利用递归时一定要考虑好回归条件,即使什么都不用返回,也要考虑回归条件,在进行数组的一系列操作时我们应该充分学会利用指针,通过指针实现数组内数的传递
快速排序:
定义:(1)设k=a[0],将k放到适当位置,使的比k小的都在k左边,比k大的都在k右边,和k相等的,在k左右都可
(2)把k右边快速排序,把k左边快速排序
public void mergesort(int a[],int s,int e) { if(s>=e) { return; } int k=a[s]; int i=s; int j=e; //一开始是比较看k右边的是不是比k大,不满足的话a【i】和a【j】交换位置,交换后a【j】变成了k,就看 //k左边的是不是比k小,不是的话交换位置,循环停止的条件是i==j这时所有的元素已经判断完毕 while(i!=j) { while(j>i&&a[j]>=k) { --j; } int m=a[j]; a[j]=a[i]; a[i]=m; while(i<j&&a[i]<=k) { ++i; } int p=a[j]; a[j]=a[i]; a[i]=p; } mergesort(a,s,i-1); //进行完上面的操作后a[i]=k;在将i右面的和i左边的进行快速排序即可,所有的元素的左边都比自己大,右边比自己小 //就实现了排序 mergesort(a,i+1,e); }这跟课程中的程序有些不同,因为c语言中,可以通过调用方法实现数组中两个数的交换,但是java语言不行。
收获:又提供了一种将数组排序的方法