利用分治法排序

分治法:

有很多算法在结构上是递归的,为了解决这一给定的问题,算法要一次或者多次的递归调用其自身来解决问题,通常这样的算法会用到分治法,那么什么是分治法呢?分治法就是将一个规模很大的问题,分解为很多的可以很用以就得到解决的子问题,而且这些子问题与原问题有着相似的结构,然后,分别求解这些子问题的解,最后,合成这些子问题的解,从而得到原问题的解的方法。

 

 

分治策略:(三步走)

分解(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 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值