某天得知寒假还有编程作业,便很无奈地写着第一套题,发现分治算法,这种基础算法,初一初二学的,现在完全不记得了23333
于是嘛,就又重新学了一下分治以及归并排序。

一、啥是分治

分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。

(以上来自百度百科quq)

二、适用条件

采用分治法解决的问题一般具有的特征如下:

  1. 问题的规模缩小到一定的规模就可以较容易地解决;
  2. 问题可以分解为若干个规模较小的模式相同的子问题,即该问题具有最优子结构性质;
  3. 合并问题分解出的子问题的解可以得到问题的解;
  4. 问题所分解出的各个子问题之间是独立的,即子问题之间不存在公共的子问题。

(还是来自百度百科,因为觉得说的很有道理就直接复制了)

三、从归并排序入手

假设我们要排序这样一个序列:
14,13,52,26,12,2,44,42

首先是要利用分治将这列数的排序变成小数字的排序(从上往下):

基于分治的归并排序
PS:主要是二分法,这个最常用。

然后是把每个小问题排序,合并成最终答案(从下往上):

基于分治的归并排序

(是不是很像一颗树?!)

当把子问题合并时,我们只需要用一个tmp数组存顺序,最后复制回原数组即可(以最后一步为例):

基于分治的归并排序
我们通过俩指针i和j比较从front到mid和mid+1到end的大小,依次放进tmp中,再复制回原数组即可(如下)。
基于分治的归并排序
具体见程序咯!

时间复杂度:O(nlogn)

C++ Code:

#include <bits/stdc++.h>
using namespace std;
int a[100];

void MergeSort(int* a,int f,int mid,int e){
	int* tmp = new int[e-f+2];//利用tmp询问一个新的内存空间用来定义tmp数组
	int i = f,j = mid+1,k = 1;//定义指针和tmp数组初始位置
	/*比较并存入tmp过程*/
	while (i <= mid && j <= e){
		if (a[i] < a[j]) tmp[k++] = a[i++];
		else tmp[k++] = a[j++];
	}
	
	while (i <= mid) tmp[k++] = a[i++];
	while (j <= e) tmp[k++] = a[j++];
	/*复制过程*/
	k = 1;
	for (int i = f;i <= e;i++) a[i] = tmp[k++];
	delete [] tmp;//养成好习惯,有new必有delete!
}

void Merge(int* a,int f,int e){
	int mid = (f+e)/2;
	if (f < e){
		Merge(a,f,mid);
		Merge(a,mid+1,e);
		MergeSort(a,f,mid,e);
	}
}

int main(){
	int n;
	cin >> n;
	for (int i = 1;i <= n;i++)
		cin >> a[i];
	Merge(a,1,n);
	for (int i = 1;i <= n;i++) cout << a[i] << " ";
	cout << endl;
}

四、写在后面

分治貌似就是和二分差不多,写了分治求最近点对和分治求逆序数,大概懂了些皮毛了。。。

也祝大家新年快乐!!!!!!!!

相关文章: