分治算法定义
将一个问题分解成多个子问题,将问题缩小到一定规模后逐个求解,最后合并所有子问题
分治算法步骤
- 分解(将原问题分解成一个形式相同规模更小的子问题)
- 解决(递归求解子问题,直到问题的规模足够小,直接求解)
- 合并(合并子问题的解,得到原问题的解)
分治算法例题(实际应用)
插入排序
思路
一道十分普通的(O(n^2))时间复杂度题,使用类似打扑克牌时给牌排序的分治思想递归实现即可
即:
先给n-1张牌排序,再分成给n-2张牌排序,以此类推.......
直到只剩1张牌,则直接结束
(Code)
#include<bits/stdc++.h>
using namespace std;
int n,a[110];
void insert_sort(int a[],int n){
//1.基本情况
if(n==1)return;
//2.分解子问题
//3.解决子问题
insert_sort(a,n-1);
int tmp=a[n],i;
for(i=n-1;i>=1;i--){
if(a[i]>tmp){
a[i+1]=a[i];
}else{
break;
}
}
a[i+1]=tmp;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
insert_sort(a,n);
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
return 0;
}
归并排序
思路
这道题的数据范围加大,不能再用(O(n^2))算法解决,会导致TLE;故我们可以用归并排序解决
(Code)
#include<bits/stdc++.h>
using namespace std;
int n,a[110],b[110];
void merge(int a[],int l,int mid,int r,int t[]){
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r){
if(a[i]<=a[j])t[k++]=a[i++];
else t[k++]=a[j++];
}
while(i<=mid)t[k++]=a[i++];
while(j<=r)t[k++]=a[j++];
for(i=l;i<=r;i++)a[i]=t[i];
}
void merge_sort(int a[],int l,int r,int t[]){
//1.基本情况
if(l==r)return;
//2.分解子问题
int mid=(l+r)>>1;
//3.解决子问题
merge_sort(a,l,mid,t);
merge_sort(a,mid+1,r,t);
//4.合并子问题的解
merge(a,l,mid,r,t);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
merge_sort(a,1,n,b);
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
return 0;
}
快速排序
思路
使用(O(n log n))时间复杂度的快速排序,具体步骤看下图
(Code)
#include<bits/stdc++.h>
using namespace std;
int n,a[100010];
void quick_sort(int a[],int l,int r){
//1.基本情况
if(l==r)return;//可省略
//2.分解子问题
int i=l,j=r,mid=a[l+rand()%(r-l+1)];
while(i<=j){
while(a[i]<mid)i++;
while(a[j]>mid)j--;
if(i<=j){
swap(a[i],a[j]);
i++;
j--;
}
}
//3.解决子问题
if(l<j)quick_sort(a,l,j);
if(i<r)quick_sort(a,i,r);
//4.合并子问题的解
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
quick_sort(a,1,n);
for(int i=1;i<=n;i++){
printf("%d ",a[i]);
}
return 0;
}