分治法:
有很多算法在结构上是递归的,为了解决这一给定的问题,算法要一次或者多次的递归调用其自身来解决问题,通常这样的算法会用到分治法,那么什么是分治法呢?分治法就是将一个规模很大的问题,分解为很多的可以很用以就得到解决的子问题,而且这些子问题与原问题有着相似的结构,然后,分别求解这些子问题的解,最后,合成这些子问题的解,从而得到原问题的解的方法。
分治策略:(三步走)
分解(Divide):将原问题分解为与原问题相似的一系列子问题的过程;
解决(Conquer):递归的解决各个子问题,若是子问题足够小,则就可直接求解;
合并(Combine):将子问题的解合并成为原问题的解。
注意:关于如何将原问题分解为子问题的情况,我们应该具体情况,具体分析,因为分成不同的等分时,可能会影响到时间复杂度。所以,分子问题应该是分治法的难点。
????看到上面的描述,没接触过算法的朋友,可能还是不清楚,那么我们举个生活中的例子,就很用以理解了。
举例(扑克牌排序):
假设我们的桌子上有两堆牌A,B,每一堆都是排好序的,最小的牌在最上面一张。现在,我们希望将这两堆牌何在一起,并进行排序,面朝下的放在桌子上。那么,我们可以这样做,同时拿起两堆牌A,B中的第一张,进行比较,选取小的一张,放在新的地方,然后,(假设是A堆中的第一张牌小)我们再从选择的那A堆,抽出第二张牌,与手中的B堆的第一张牌进行比较,同样小的拿出。(如果此时是B得小,我们就得再从B堆中抽一张牌与A堆的第二张比较,同样拿出小的牌),一直进行下去,直到手上剩下最后一张牌。就是最大的牌了。
分治法其实就是先将大规模数据,进行分组,并将很容易排序的组别时进行排序,之后,就跟那排好序的那堆牌一样的做法进行合并排序。
如果大家还不明白,请看下图。
图形说明:
伪代码实现:
Merge-Sort(A,p,r)
if p < r
then q<---(向下取整)(p+q)/2
Menge-Sort(A,p,q);
Menge-Sort(A,q+1,r);
Menge(A,p,q,r);
Merge(A,p,q,r)
n1<-----q-p+1
n2<------r-q
creat arrays left[0......,n1-1] and right [0,......n2-1]
for i<---- 0 to n1-1
do left[i] <----A[p+i]
for j<---- 0 to n2-1
do right[j] <---A[q+j+1]
i<---- 0
j<---- 0
for k<----p to r (i<n1 and j<n2)
do if left[i]<=right[j]
then A[k] <----left[i] i++
else
then A[k] <----right[j] j++
if i==n1
while j != n2
array[k] = right[j];
++k;
++j;
if j==n2
while i != n1
array[k] = left[i];
++k;
++i;
Java代码实现:
方法1:
public class MergeSort
{
/**
* 主方法
*/
public static void main(String []args)
{
int []array={5,8,4,6,2,3,1,9};
int alen=array.length;
System.out.println("未排序前的顺序:");
for(int i=0;i<alen;i++)
{
System.out.print(" "+array[i]+" ");
}
MergeSortWay(array,0,alen-1);
System.out.println("\n排序后的顺序:");
for (int i = 0; i < alen; i++)
{
System.out.print(" "+array[i]+" ");
}
}
/**
* 分治法
*/
public static void MergeSortWay(int array[],int p,int r)
{
if(p<r)
{
int q=(p+r)/2;
MergeSortWay(array,p,q);
MergeSortWay(array,q+1,r);
MergeWay(array,p,q,r);
}
}
/**
* 合并的方法
*/
public static void MergeWay(int array[],int p,int q,int r)
{
int n1=q-p+1;
int n2=r-q;
int left[]=new int [n1];
int right[]=new int [n2];
for(int i=0;i<n1;i++)
left[i]=array[p+i];
for(int j=0;j<n2;j++)
right[j]=array[q+j+1];
int i,j,k;
for( i=0,j=0,k=p;k<array.length&&i<n1&&j<n2;k++)
{
if(left[i]<=right[j])
{
array[k]=left[i];
i++;
}
else if(right[j]<=left[i])
{
array[k]=right[j];
j++;
}
}
if (i == n1)
while (j != n2)
{
array[k] = right[j];
++k;
++j;
}
if (j == n2)
while (i != n1)
{
array[k] = left[i];
++k;
++i;
}
}
}
方法2:
public class MergeSort
{
public static void main(String args[])
{
int[] num = {5, 8, 4 , 6, 2, 3, 1, 9};
System.out.println("未排序前:");
for (int i=0;i<num.length;i++)
System.out.print(num[i] + " ");
System.out.println();
mergesort(num, 0, num.length-1);
System.out.println("经排序后:");
for (int i=0;i<num.length;i++)
System.out.print(num[i]+" ");
System.out.println();
}
public static void merge(int[] A, int p, int q, int r)
{
int n1 = q - p + 1;
int n2 = r - q;
int []Left = new int[n1];
int []Right = new int[n2];
int i = 0;
int j = 0;
while (i != n1)
{
Left[i] = A[p + i];
++i;
}
while (j != n2)
{
Right[j] = A[q + j + 1];
++j;
}
i = j = 0;
int k = p;
while (i != n1 && j != n2)
{
if (Left[i] <= Right[j])
{
A[k] = Left[i];
++i;
}
else
{
A[k] = Right[j];
++j;
}
++k;
}
if (i == n1)
while (j != n2)
{
A[k] = Right[j];
++k;
++j;
}
if (j == n2)
while (i != n1)
{
A[k] = Left[i];
++k;
++i;
}
}
public static void mergesort(int[] A, int p, int r)
{
if (p < r)
{
int q = (p + r) / 2;
mergesort(A, p, q);
mergesort(A, q+1, r);
merge(A, p, q, r);
}
}
}
输出结果:
未排序前的顺序:
5 8 4 6 2 3 1 9
排序后的顺序:
1 2 3 4 5 6 8 9