分治算法

参考资料: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的一个排列,求它的逆序数

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值