所谓分治:分而治之,中华民族智慧的结晶。对其联盟,使其分裂而利于各个击破;对其国使用,使其国分裂而利于控制;对其公司使用,使其公司分裂而利于控制;对其团队使用,使其团队分裂而利于控制。可见,分治法被运用于当今社会的方方面面。
既然分治法拥有那么大能量,有必要学习学习它。当然了,这里学习分治是用来如何解决问题的。
面对一个大问题,如果直接去解决,可能很复杂,不好解决。所以要把大的问题分解成小问题,先解决小问题,等小问题都解决了,再一梳理,可能就把大问题也解决了。
所以分治法的基本步骤就是:
1. 认清问题,问题是否能够使用分治法
2.分解问题,把问题分解成小规模的一系列子问题
3.求解问题,把小规模问题一一求解
4.合并
分治法的典型使用: 二分查找、归并排序
各种情况下时间复杂度都能达到O(nlgn),理论上O(nlgn)已经是最优性能了。
递归算法公式或者说主方法:
T(n)=aT(n/b)+f(n);
a 代表问题规模
b 代表每个问题是原来的1/b;
归并排序公式:
T(n)=2T(n/2)+f(n);
问题规模是2个,每次都是分半
那么根据算法主定理可以得到其时间复杂度是O(nlgn)
主定理请看:http://blog.chinaunix.net/uid-25267728-id-3802135.html
归并排序空间复杂度:
需要O(n)临时保存数据。
归并排序C 语言代码示例:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <error.h>
#include <errno.h>
#include <sys/socket.h>
#include <stdlib.h>
void merge(int data[],int start,int middle, int end);
void mergeSort(int data[],int start, int end){
if(data == NULL){
printf("data == NULL");
return;
}
if(start < end){
int middle = 0;
middle = (end + start)/2;
mergeSort(data,start, middle);
mergeSort(data,middle+1, end);
merge(data,start,middle,end);
}
}
void merge(int data[],int start,int middle, int end){
int i = 0;
int j = 0;
int k = 0;
int part1Size = middle -start+1;
int part2Size = end - middle;
int* data1 = (int*)malloc(sizeof(int)*part1Size);
int* data2 = (int*)malloc(sizeof(int)*part2Size);
if(data1 == NULL || data2 == NULL){
printf("data1 or data2 is null\n ");
return;
}
printf("\n");
printf("merge start \n ");
printf("merge data1 \n ");
for(i=0; i < part1Size; i++){
data1[i]= data[start+i];
printf(" %d",data1[i]);
}
printf("\n ");
printf("merge data2 \n ");
for(j=0; j < part2Size; j++){
data2[j]= data[middle+1+j];
printf(" %d",data2[j]);
}
printf("\n ");
i = 0;
j = 0;
for( k = start; k <= end && i< part1Size && j<part2Size; k++){
if(data1[i] < data2[j]){
data[k]=data1[i];
i++;
}else{
data[k]=data2[j];
j++;
}
}
//再拷贝余下的
for(i; i< part1Size; i++){
data[k++]=data1[i];
}
for(j; j< part2Size; j++){
data[k++]=data2[j];
}
//end
free(data1);
free(data2);
printf("merge end \n ");
}
int main(){
int i;
int data[]={3,4,1,2,9,8,6,32,15,16,11,7};
int len = sizeof(data)/sizeof(int);
mergeSort(data,0,len -1);
printf("\n");
printf(" get sort result\n");
for(i =0; i < len;i++){
printf(" %d",data[i]);
}
printf("\n");
return 0;
}
从以下执行过程 log可以看出,最终分解为两两比较,然后合并,之后比较个数逐步体增再合并。
merge start
merge data1
3
merge data2
4
merge end
merge start
merge data1
3 4
merge data2
1
merge end
merge start
merge data1
2
merge data2
9
merge end
merge start
merge data1
2 9
merge data2
8
merge end
merge start
merge data1
1 3 4
merge data2
2 8 9
merge end
merge start
merge data1
6
merge data2
32
merge end
merge start
merge data1
6 32
merge data2
15
merge end
merge start
merge data1
16
merge data2
11
merge end
merge start
merge data1
11 16
merge data2
7
merge end
merge start
merge data1
6 15 32
merge data2
7 11 16
merge end
merge start
merge data1
1 2 3 4 8 9
merge data2
6 7 11 15 16 32
merge end
get sort result
1 2 3 4 6 7 8 9 11 15 16 32