分治法与减治法

分治法

基本思想

(1) 将一个问题划分为同一类型的若干子问题,子问题最好规模相同。
(2) 对这些子问题求解(一般使用递归方法,但在问题规模足够小时,有时也会利用另一个算法)。
(3) 有必要的话,合并这些子问题的解,以得到原始问题的答案。

经典使用场景

1.归并排序

基本思想
归并排序,默认指二路归并排序。假设初始序列含有n个元素,则可看成n个有序的子序列,每个子序列的长度是1。然后将前后相邻的两个有序序列归并为一个有序序列。这与分治法**将一个问题划分为同一类型的若干子问题,对这些子问题求解,合并这些子问题的解的思路是一致的。

算法实现

// 归并排序
void merge(int arr[],int L,int M,int R){
	int LEFT_SIZE = M-L;
	int RIGHT_SIZE = R-M+1;
	int leftArr[LEFT_SIZE];
	int rightArr[RIGHT_SIZE]; 

	
	int i; int j; int k;
	
	//1.init new arr
	for(i=L;i<M;i++){
		leftArr[i-L] = arr[i];
	} 
	
	for(i=M;i<=R;i++){
		rightArr[i-M] = arr[i];
	}
	
	i=0;j=0;k=L;
	
//	2.first sort
	while(i<LEFT_SIZE && j<RIGHT_SIZE){
		if(leftArr[i] < rightArr[j]){
			arr[k] = leftArr[i];
			i++;
			k++;
		}
		else
		{
			arr[k] = rightArr[j];
			j++;
			k++;
		}
	}
	//3.end sort
	while(i < LEFT_SIZE){
		arr[k] = leftArr[i];
		i++;
		k++;
		num++;
	}
	
	while( j<RIGHT_SIZE ){
		arr[k] = rightArr[j];
		j++;
		k++;
	}	

}

void mergeSort(int arr[],int L,int R){

	if( L==R ){
		return;
	}
	else{
		int M=(L+R)/2;
		mergeSort(arr,L,M);
		mergeSort(arr,M+1,R);
		merge(arr,L,M+1,R);
	}
}

2.快速排序

基本思想
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据比另一部分的所有数据要小,再按这种方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,使整个数据变成有序序列。
算法实现

//归并排序
#include <iostream>
using namespace std;

int Partition(int r[ ], int first, int end);
void QuickSort(int r[ ], int first, int end);
 
int main( )
{
	int i, n = 8, r[8] = {8,3,2,6,7,1,5,4};
	QuickSort(r, 0, n-1);
	for (i = 0; i < n; i++)
		cout<<r[i]<<"\t";
	return 0;
}

int Partition(int r[ ], int first, int end)          
{	
	int temp, i = first, j = end; 
	while (i < j)	
	{  
		while (i < j && r[i] <= r[j]) j--;          //右侧扫描
		if (i < j) 
		{ 
  			temp = r[i]; r[i] = r[j]; r[j] = temp;      //将较小记录交换到前面
  			i++; 
		}
		while (i < j && r[i] <= r[j]) i++;         //左侧扫描
		if (i < j) 
		{
			temp = r[i]; r[i] = r[j]; r[j] = temp;      //将较大记录交换到后面
			j--; 
		}
	}
	return i;                                //返回轴值记录的位置
}

void QuickSort(int r[ ], int first, int end)        //快速排序
{	
	if (first < end) 
	{      
    	int pivot = Partition(r, first, end);         //划分,pivot是轴值的位置
    	QuickSort(r, first, pivot-1);              //对左侧子序列进行快速排序
    	QuickSort(r, pivot+1, end);              //对右侧子序列进行快速排序
    }
}

3.二叉树问题

因为二叉树可以划分为同样类型的两个更小的组成部分——左子树和右子树,所以许多关于二叉树的问题都可以应用分治法来解决。二叉树是由三个基本单元组成:根结点、左子树和右子树。因此,若能依次遍历这三部分,就能遍历整个二叉树。

减治法

基本思想

(1) 建立原问题实例的解和同样问题较小实 例的解的关系
(2) 并利用这种关系,从顶而下(递归地)或从底而上(非递归地)解决问题。
(3) 一般情况下,每次算法迭代,都消去一个常量和一个常数因子。

经典算法

1.插入排序

2.折半查找

(1)假币问题

// 减治法求解假币问题
int solve2(int low, int high) {
	num2++;
	if (low == high) return low; // 只有一个硬币 
	if (low == high - 1) { // 只有两个硬币 
		if (data[low] < data[high]) return low;
		else return high;
	}
	int mid = (low + high) / 2;
	int sum1=0, sum2=0;
	if ((high - low + 1) % 2 == 0) {   // 区间内硬币个数为偶数
		sum1 = sum(low, mid);
		sum2 = sum(mid + 1, high);
		printf("硬币%d-%d和硬币%d-%d称重一次:", low, mid, mid + 1, high);
	}
	else {                         // 区间内硬币个数为奇数
		sum1 = sum(low, mid - 1);
		sum2 = sum(mid + 1, high);
		printf("硬币%d-%d和硬币%d-%d称重一次:", low, mid - 1, mid + 1, high);
	}
	if (sum1 == sum2) {
		printf("两者重量相同。\n");
		return mid;
	}
	else if (sum1 < sum2) { // 假币在左区间 
		printf("前者重量轻。\n");
		if ((high - low + 1) % 2 == 0) return solve2(low, mid); // 区间内硬币个数为偶数 
		else return solve2(low, mid - 1); // 区间内硬币个数为奇数 
	}
	else { // 假币在右区间 
		printf("后者重量轻。\n");
		return solve2(mid + 1, high);
	}
}
int sum(int low, int high) { // 求data[low..high]的重量
	int sum = 0;
	for (int i = low; i <= high; i++) sum += data[i];
	return sum;
}

(2)金块问题
(3)俄式乘法
(4)约瑟夫斯问题

3.选择问题

/PS:此文归并排序和假币问题的代码实现均借鉴于本社区其他两位博主,整理下来仅供个人学习复习使用,尚未实现的算法部分留待之后学习到该算法时进行完善/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug滚远点~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值