分治法的设计思想与实例(二分,合并,快排)
分治法的基本思想是将一个规模为n的问题分割成k个规模较小的子问题,这些子问题相互独立切与原问题相同。递归的解这些子问题,然后将各子问题的解合并得到原问题的解。
它的一般算法设计模式如下:
divide(n) { if(fabs(n)<=n0)return solve(n); a1=divide(n1); a2=divide(n2); a3=divide(n3); ...... return condition(a1,a2,a3...); }
其中,n表示规模为n的问题,n0为一阈值,当n<=n0时问题直接解出,否则将问题分割成多个子问题,每个子问题若没到达阈值则继续分割。达到阈值的问题直接返回解,没有达到阈值的问题根据具体情况从所有子问题返回的解中找出解。
二分搜索技术
二分搜索是运用分治策略的典型例子。给定排好序的n个元素a[0~n],在这n个元素中找出一特定的元素x,二分搜索利用元素之间的次序关系,可在最坏情况下用O(logn)时间完成搜索任务,其基本思想是:每次搜索取最中间的元素,与x比较,若相等则结束,否则以最中间的元素为边界继续搜索含有x的那一边。(递归和非递归两个版本)
#include<iostream> using namespace std; int search(int[],int,int,int); int search(int[],int,int); int main() { int a[100000],n,i; while(cin>>n) { for(i=0;i<n;i++) cin>>a[i]; cin>>i; cout<<search(a,i,0,n-1)<<'\n'; cout<<search(a,n,i)<<'\n'; } return 0; } int search(int a[],int x,int l,int r) { int m=(l+r)>>1,i; if(a[m]==x)i=m; else if(l==r)i=-1; else if(a[m]<x)i=search(a,x,m+1,r); else i=search(a,x,l,m-1); return i; } int search(int a[],int n,int x) { int l=0,r=n-1,m; while(l<=r) { m=(l+r)>>1; if(a[m]==x)return m; else if(a[m]<x)l=m+1; else r=m-1; } if(a[m]==x)return m; else return -1; }
合并排序
基本思想:将待排序的元素分成大小大致相同的两个子集合,分别对两个子集合进行排序(分别分成两个子集合或者到达阈值直接返回),最终将排序好的子集合合并成排好序的集合。
#include<iostream> using namespace std; void apart(int[],int,int); void merge(int[],int,int); int main() { int a[100000],n,i; while(cin>>n) { for(i=0;i<n;i++) cin>>a[i]; apart(a,0,n-1); for(i=0;i<n;i++) cout<<a[i]<<" "; cout<<'\n'; } return 0; } void apart(int a[],int l,int r) { if(l==r)return; apart(a,l,(l+r)>>1); apart(a,((l+r)>>1)+1,r); merge(a,l,r); } void merge(int a[],int l,int r) { int b[100000],i=l,j=((l+r)>>1)+1,k=l,m=(l+r)>>1; while(i<=m&&j<=r) if(a[i]<=a[j])b[k++]=a[i++]; else b[k++]=a[j++]; while(i<=m)b[k++]=a[i++]; while(j<=r)b[k++]=a[j++]; for(i=l;i<=r;i++) a[i]=b[i]; }
快速排序
基本思想:
对于输入的子数组a[l~r],按以下三个步骤排序
(1)分解:将a[l~r]分成3段a[l~p-1]、a[p]、a[p+1~r],使a[l~p-1]中的所有元素小于等于a[p],a[p+1~r]中的所有元素大于等于a[p]
(2)递归求解:将数组a[l~r]分割成a[l~p-1],a[p+1~r],分别进行(1)分解
(3)合并:由于a[l~p-1]中的所有元素小于等于a[p],a[p+1~r]中的所有元素大于等于a[p],而a[l~p-1]和a[p+1~r]都已经排好序了,所以不需要执行任何计算,a[l~r]已经排好序
#include<iostream> using namespace std; void apart(int[],int,int); int sort(int[],int,int); int main() { int a[100000],n,i; while(cin>>n) { for(i=0;i<n;i++) cin>>a[i]; apart(a,0,n-1); for(i=0;i<n;i++) cout<<a[i]<<" "; cout<<'\n'; } return 0; } void apart(int a[],int l,int r) { int i=sort(a,l,r); if(i-1>l)apart(a,l,i-1); if(i+1<r)apart(a,i+1,r); } int sort(int a[],int l,int r) { int i,j=l; for(i=l+1;i<=r;i++) if(a[i]<=a[l])swap(a[i],a[++j]); swap(a[l],a[j]); return j; }
posted on 2019-10-16 21:46 我的昵称里必须得有mt 阅读(642) 评论(0) 收藏 举报
                    
                
                
            
        
浙公网安备 33010602011771号