算法设计方法之一——分而治之,模仿了法国皇帝拿破仑在1852年12月2日奥斯特里茨战役中采用的接触策略。
分而治之(divide-and-conquer)将问题的一个实例划分为两个或更多个较小的实例,一直持续划分实例指导规模小到可以轻松获得答案为止。是一种自顶向下的方法。
1. 二分查找
/**
* 二分查找
* 基于非递减的有序数组
* @param s 非递减数组,查找区域
* @param x 查找值
* @return 返回查找值所在位置,如查找不到返回-1
*/
public int binsearch(int[] s,int x){
int location =-1;
int start = 0;
int end = s.length-1;
int mid;
while(location==-1 && start<=end){
mid = (start+end)/2;
if(s[mid]==x){
location =mid;
}else if(s[mid]< x){
start = mid+1;
}else{
end = mid-1;
}
}
return location;
}
2. 合并排序
两路合并(two-way merging),表示将两个有序数组合并为一个有序数组。合并排序即重复应用两路合并完成对数组的排序。
**此代码有错,还未调试成功,希望有大神可以提供意见**
/**
* 合并排序
* 将n个建排列为非递减序列
* @param S 排序后的有序数组cun'fan'f
*/
static int S[] = {};
/**
* 两路合并
* 将两个有序数组合并为一个有序数组
**/
public void merge(int[] arr1,int[] arr2 ){
int i=0,j=0,k=S.length;
Arrays.copyOf(S,k+arr1.length+arr2.length);
while(i<arr1.length && j<arr2.length){
if(arr1[i]<arr2[j]){
S[k]=arr1[i];
i++;
}else{
S[k]=arr2[j];
j++;
}
k++;
}
if(i<arr1.length){
System.arraycopy(S,k,arr1,arr1[i],arr1.length-i);
}
if(j<arr1.length){
System.arraycopy(S,k,arr2,arr2[j],arr2.length-j);
}
}
/**
* 分而治之方法,拆分要排序的数组
* 调用merge()方法,两辆排序
* @param args 要排序的数组
*/
public void mergesort(int[] arr){
int len = arr.length;
int [] left;
int [] right;
int devide;
if(len>1){
devide = len/2;
left = new int[devide];
System.arraycopy(arr,0,left,0,devide);
right = new int[len-devide];
System.arraycopy(arr,devide,right,0,right.length);
mergesort(left);
mergesort(right);
merge(left,right);
}
}
3. 快速排序
/**
* 快速排序
* @param arr 要排序的数组
* @param start 数组起始下标
* @param end 数组结束下标
*/
public void quicksort(int[] arr,int start,int end){
/**
* 首先判断该数组长度是否大于1
*/
if(start<end){
int i=start;
int j=end;
/**
* 以起始值为基准,并且该位置即为一个坑
*/
int x=arr[start];
while(i<j){
/**
* 从倒序分别与基准值x比对,大于基准值则比对下一项
*/
while(i<j && arr[j]>=x){
j--;
}
/**
* 直至该项值小于基准值,将该值放入正序的第一个坑,并且此位置空出来成为了一个坑
*/
if(i<j){
arr[i++]=arr[j];
}
/**
* 从正序开始分别与基准值比对,小于基准值则比对下一项
*/
while(i<j && arr[i]<=x){
i++;
}
/**
* 直至该项值大于基准值,将该值放入刚刚腾出来的坑,并且此位置空处理啊成为了一个坑
*/
if(i<j){
arr[j--]=arr[i];
}
}
/**
* 将基准值x放入最后空出来的一个坑
* 经过上面排序之后,该基准值x左边都是小于该值的项,右边都是大于该值的项
*/
arr[i]=x;
quicksort(arr,start,i-1);
quicksort(arr,i+1,end);
for(int l=0;l<arr.length;l++){
System.out.print(arr[l]+" ");
}
System.out.println();
}
}
4. Strassen矩阵乘法算法
1969年,Strassen发表了一种算法,对于矩阵的计算,无论是乘法或者加减法,其时间复杂度都优于根据矩阵的定义去计算。
5. 大整数的算数运算
大整数,是指超出计算机硬件所能表示的整数范围。如果需要表示这样的大整数,就只能通过软件来表示和处理这些整数。
- 大整数的加减法及其他线性时间运算
可以使用一个整数数组来表示大整数,每个位置存储一个数位。例如:534127的存储,存储到数组S中
S[6]
S[5] |S[4]| S[3]| S[2]| S[1]| S[0]
—-|—–|——|—–|—–|—–
5 |3 |4 |1 |2 |7
线性运算:
u∗10m乘法
u/10m除法
umod10m求余
例如: 534127=534∗103+127 - 大整数的乘法
567832=567∗103+832
9423723=9423∗103+723
按照分而治之的思想,一个n位的大整数u,可以表示为:
u=x∗10(n/2)+y
y(n/2位)
x(n−n/2位)
两个整数相乘:
u=x∗10m+y
z=w∗10m+z
u∗z=(x∗10m+y)(w∗10m+z)=xw∗102m+(xz+yw)∗10m+yz
该代码还待修正
/**
* 大整数乘法
* @param u 整数1
* @param v 整数2
*/
public int prod(int u,int v){
int x,y,w,z;
int n = 6,m;
if(u==0||v==0){
return 0;
}
else{
m =n/2;
int pow = (int)Math.pow(10,m);
x=u/pow;
y=u%pow;
w=v/pow;
z=v%pow;
return x*w*(int)Math.pow(10,2*m)+(x*z+y*w)*pow+y*z;
}
}
6. 确定阈(yu)值
最优阈值:n
递归需要消耗大量的计算机内存,例如Strassen矩阵算法中,当矩阵为一阶矩阵时,直接按矩阵定义计算乘积反而比调用分而治之发效率高,类似于这样,求最优阈值n,当n大于该阈值时调用某个方法,当n小于阈值时调用另一效率更高的方法,这样可以使运算效率更快。