参考资料:icpc暑期课
基本概念
把一个任务,分成形式和原任务相同,但规模更小的 几个部分任务(通常是两个部分),分别完成,或只 需要选一部完成。然后再处理完成后的这一个或几个 部分的结果,实现整个任务的完成。
典型应用——归并排序
基本思想:
数组排序任务可以如下完成:
1) 把前一半排序
2) 把后一半排序
3) 把两半归并到一个新的有序数组,然后再拷贝回 原数组,排序完成
核心代码:
void merge(int a[],int s,int m,int e,int tmp[])//归并操作
//其实原理就是把原本有序的a[s,m]与a[m+1,e]合并tmp[],使之有序,再填到a[s,e]上
{
int pb=0;//一个“指针”,指向tmp待填充的位置
int p1=s,p2=m+1;//也是“指针”,分别指向二分后数组的未排序最值
while(p1<=m&&p2<=e)
{
if(a[p1]<a[p2])
tmp[pb++]=a[p1++];
else
tmp[pb++]=a[p2++];
}
while(p1<=m)
{
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];
}
}
void mergesort(int a[],int s,int e,int tmp[])//排序操作
//时间复杂度O(nlogn)
{
if(s<e)//一个元素就没必要进行了,也是递归的终点 (想想二分)
{
int m=s+((e-s)>>1);//想想二分,注意这里不直接(s+e)>>1的操作
mergesort(a,s,m,tmp);
mergesort(a,m+1,e,tmp);
merge(a,s,m,e,tmp);
}
}
简单总结:
两个元素——排序简单。
三个元素——分成一个,两个,将两个的排好序,再合(归并)到一起。
四个元素——分成两个,两个,分别排序好,再合(归并)到一起。
假如有很多个元素,不断的一分为二去做,一直二分到两个元素去排序,然后不断的合并。
典型应用——快速排序
基本思想:
数组排序任务可以如下完成:
1)设k=a[0], 将k挪到适当位置,使得比k小的元素都 在k左边,比k大的元素都在k右边,和k相等的,不关心,在k左右出现均可 (O(n)时间完成)
2) 把k左边的部分快速排序
3) 把k右边的部分快速排序
核心代码:
#include <cstdio>
#include <iostream>
using namespace std;
void swap(int &a,int &b)
{
int tmp =a;
a=b;
b=tmp;
}
void quicksort(int a[],int s,int e)
//时间复杂度O(nlogn)
{
if(s>=e)//递归的出口
return;
int k=a[s];//让k等于起点的值,目标让k前的比k小,k后的比k大
int i=s,j=e;//指针,一个指着摆放的值,一个去遍历 (并不是固定的,但是总会有这样两个)
while(i!=j)
{
//遍历,和待摆放的元素的比较
//一开始倒着去扫,扫到小的换到前面去,再从前面往后扫,扫到大的再换到后面扫小的
//全部遍历一遍之后,前面的(无序)比k小,后面的(无序)比k大
while(j>i&&a[j]>=k)
j--;
swap(a[i],a[j]);
while(j>i&&a[i]<=k)
i++;
swap(a[i],a[j]);
}//结束后 a[i]==k
quicksort(a,s,i-1);
quicksort(a,i+1,e);
}
int a[]={93,27,30,2,8,12,2,8,30,89};
int main()
{
int size= sizeof(a)/sizeof(int);
quicksort(a,0,size-1);
for(int i=0;i<size;i++)
cout<<a[i]<<" ";
cout<<endl;
return 0;
}
简单总结:
选择:第一个元素(每次都是待排部分的第一个元素)
目标:前面的都比它小,后面的都比它大
方法:倒着扫,扫到小的换一下,再从换后的位置开始正着扫,扫到大的换一下,从换后的位置开始倒着扫小的,以此类推。其实就是这个元素换到哪都不动,然后另一个“指针”就往“中间”的方向去扫就可以。
分治思想体现:第一个元素放好了,可以看做,前面的,这个元素,后面的,三个东西在宏观上有序,我们对前面的 和 后面的,继续使用这种方法,直到,遇到一个元素的情况(已经有序)
即:分(分成前面的,元素,后面的三个),而据此,对前面的,后面的治之
练习例题
1. 给定一个数组包含n个元素,统计前m大的数并且把这m个数从大到小输出
2. 现给定1,2,…,n的一个排列,求它的逆序数