分治算法详解:分而治之

分治算法核心思想

分治算法用四个字概括就是分而治之

将原问题划分成多个小规模并且简单的子问题,这些子问题的结构与原问题相似,因此,递归地解决这些子问题,将子问题的解合并就可以得到原问题的解了。

分治算法的思路与递归很相似,但是分治算法是一种算法思想,是一种处理问题的思想,而递归是一种编程技巧。所以,分治算法通常适合使用递归来实现。

在使用递归实现分治算法时,有以下三步操作:

  1. 分解:将子问题分解成一系列小规模并且与原问题结构相似的子问题
  2. 解决:递归的解决每一个子问题
  3. 合并:将子问题的解合并得到原问题的解

那么,哪些问题适合使用分治算法来解决呢?

  1. 原问题可以分解成一系列与原问题结构相似的子问题,并且子问题很容易解决
  2. 原问题分解成的子问题可以独立求解,并且子问题与子问题之间没有关联性(区别于动态规划)
  3. 原问题在分解子问题的时候存在终止条件,即分解到一定程度后,子问题很容易解决。
  4. 最后求得子问题的解后,可以合并成原问题的解,并且这个合并操作复杂度不能太高。

分治算法实践:归并排序

两路归并排序的思路是,首先将数组分为两半,再递归的进行分割,直到每一份都只剩 1 个数据,再将每一份两两合并。如图所示:

  1. 分解
    分解
  2. 解决
    可以发现,在分解到只有单个数据时,从排序的角度看,实际上已经有序的,因此,直接再合并即可
  3. 合并
    合并
    C代码实现:
#include<stdio.h>
#include<stdlib.h>
//一遍归并
void merge(int a[], int temp[], int start, int mid, int end) {
	int i = start, j = mid + 1, k = start; //第一部分:start到mid,第二部分:mid+1到end
	while(i != mid + 1 && j != end + 1) {
		if(a[i] > a[j]) {                   //取较大者导入临时数组
			temp[k++] = a[i++];
		} else {
			temp[k++] = a[j++];
		}
	}
	while(i != mid + 1) {                   //两个部分若有多余的,直接导入temp数组
		temp[k++] = a[i++];
	}
	while(j != end + 1) {
		temp[k++] = a[j++];
	}
	for(i = start; i <= end; i ++) {        //从临时数组导出到原数组
		a[i] = temp[i];
	}
}
void merge_sort(int a[], int temp[], int start, int end) {
	int mid;
	if(start < end) {
		mid = (start + end) / 2;
		merge_sort(a,temp,start,mid);     //前半部分递归
		merge_sort(a,temp,mid+1,end);     //后半部分递归
		merge(a,temp,start,mid,end);      //排序
	}
}
void Sort(int a[], int N) {
	int* b;
	b = (int*)malloc(N*sizeof(int));
	if(b != NULL) {
		merge_sort(a,b,0,N);
		free(b);
	} else
		printf("空间不足");
}
int main() {
	int a[10] = {0,1,2,3,4,5,6,7,8,9,};
	Sort(a,9);
	for(int i = 0 ; i < 10 ; i ++) {
		printf("%d ",a[i]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值