分治法的基本思想是将一个规模为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[lr]分成3段a[lp-1]、a[p]、a[p+1r],使a[lp-1]中的所有元素小于等于a[p],a[p+1~r]中的所有元素大于等于a[p]
(2)递归求解:将数组a[lr]分割成a[lp-1],a[p+1~r],分别进行(1)分解
(3)合并:由于a[lp-1]中的所有元素小于等于a[p],a[p+1r]中的所有元素大于等于a[p],而a[lp-1]和a[p+1r]都已经排好序了,所以不需要执行任何计算,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;
}
分治法详解:二分搜索、合并排序与快速排序
本文介绍了分治法的基本思想,包括何时直接解出问题和如何递归解决子问题。重点讲解了三种使用分治策略的算法:二分搜索,能在最坏情况下以O(logn)时间完成排序任务;合并排序,通过不断分割和合并子集实现高效排序;以及快速排序,通过分解、递归和合并三步实现数组排序。
2496

被折叠的 条评论
为什么被折叠?



