【算法分析与设计】第五章-分治法

一、什么是分治法/什么时候用分治法

  1. 将一个复杂分解为若干规模相同、相互独立、但类型相同的子问题。
  2. 子问题足够小时可以直接求解。
  3. 存在将子问题的解组合为原问题的解的途径。
    这种解决问题的策略称为分治法。

二、为什么用分治法

由于子问题的类型和原问题的类型相同,可以编写递归程序简单的解决问题。例如:求最大最小值问题、折半查找、归并排序、快速排序、求第k小元等等。

三、分治法解题步骤

SolutionType  DandC(Q){
	if(问题规模足够小)
		直接求解;
	else{
			将问题分解为若干子问题q1,q2,...return Combine(DandC(q1),DandC(q2),...)}
}

四、典例

  1. 三分查找
#include 
using namespace std;
int TriSearch(int *a, int l, int r, int x){
	if(l <= r){
		int d1 = l + (r - l) / 3;		// 左侧三等分点
		int d2 = r - (r - l) / 3;		// 右侧三等分点
		if(x == a[d1]) return d1;
		if(x == a[d2]) return d2;
		if(x < a[d1])
			return TriSearch(a, l, d1 - 1, x);
		if(x > a[d2])
			return TriSearch(a, d2 + 1, r, x);
		// (d1, d2)
		return TriSearch(a, d1 + 1, d2 - 1, x);
	}
	return -1;
}
  1. 快速排序
int partition(int l, int r){
	int i = l, j;
	for(j = i + 1; j <= r; j ++){
		if(a[j] < a[l])
			swap(a[++i], a[j]);
	}
	swap(a[l], a[i]);
	return i;
}
int a[N];
void qsort(int l, int r){
	if(l < r){
		int j = rand() % (r - l + 1) + l;	// 随机数法选择主元
		swap(a[l], a[j]);
		qsort(l, j - 1);
		qsort(j + 1, r);
	}
}
  1. 归并排序
int a[N];
void Merge(int l, int m, int r){
	int b[N];
	int i = l, j = m + 1, k = 0;
	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, k = 0; i <= r; i ++, k ++)	// copy back
		a[i] = b[k];
}
void MergeSort(int l, int r){
	if(l < r){
		int m = l + r >> 1;
		MergeSort(l, m);
		MergeSort(m + 1, r);
		Merge(l, m, r);
	}
}
  1. 第 k 小元素问题
int a[N];
int select(int l,int r, int k){
	while(1){
		int j = partition(l, r);
		if(j + 1 == k) return a[j];
		else if(j + 1 > k) r = j - 1else l = j + 1;
	}
}

你可能感兴趣的:(算法分析与设计,算法,排序算法,数据结构)