设计算法之分治法

1. 分治法的思想

许多有用的算法在结构上是递归的:为了解决一个给定的问题,算法一次或多次递归地调用其自身以解决紧密相关的若干子问题。这些算法典型地遵循分治法的思想:将原先问题分解为几个规模较小但类似于原问题的子问题,递归地求解这些子问题,然后再合并这些问题的解来建立原问题的解。

2.分治法的步骤

分治模式在每层递归时都有三个步骤:

1)        分解:分解原问题为若干子问题,这些子问题是原问题的规模较小的实例。

2)        解决:解决这些子问题,递归地求解各子问题。然而,若子问题的规模足够小,则直接求解。

3)        合并:合并这些子问题的解成为原问题的解。

归并排序算法完全遵循分治模式。直观上其操作如下:

1)        分解:分解待排序的n 个元素的序列成各具n/2个元素的两个子序列。

2)        解决:使用归并排序递归地排序两个子序列。

3)        合并:合并两个已排序的子序列以产生已排序的答案。

3.分治法实现排序伪代码   

MERGE(A,p,q,r)
  n1 = q – p + 1
  n2 = r – q
  let L[1..n1+1] and R[1..n2+1] be new arrays
  for i = 1 to n1
L[i] = A[p + i - 1]
  for j = 1 to n2
R[j] = A[q +j]
  L[n1 + 1] = ∞
  R[n2 + 1] = ∞
  i = 1
  j = 1
for k = p to r
if L[i] <= R[j]
  A[k] = L[i]
  i = i + 1
else
  A[k] = R[j]
j = j +1

4.分析算法

   在上面伪代码中,我们是假设有两个数组是排序好的,分别是L和R。所以通过上面的算法来将两个已经排序好的数据放到一个数据A中,A数组最终的结果应该是有序的。所以上面的代码只是实现了其中一部分的核心功能。如果要想将一个数据分成两个数组,并且每个数组都是已经排序好的,那么我们的算法应该使用到递归的算法。结合上面的算法,我们完善一下算法,如下:

MERGE-SORT(A,p,r)
  if p < r
q = [(p + r)/2]
MERGE-SORT(A,p,q)
MERGE-SORT(A,q + 1, r)
MERGE(A,p,q,r)
这样,我们先将一个数组分为两个部分,然后对各自的进行排序,之后再整合到一个数组中。如下图所示:

归并排序在数组A=[5,2,4,7,1,3,2,6]上的操作。随着算法自底向上地推进,待合并的已排好序的各序列的长度不断增加。

5.javap实现分治算法

现在我们假设有一组数据,前半部分与后半部分都是排序好的,我们使用上面已经写过的算法,用java来实现。

public class DivideAndConquer
{

	public int[] merge(int[] array, int p, int q, int r)
	{
		int n1 = q - p + 1;
		int n2 = r - q;
		Integer [] lArray = new Integer[n1+1];
		Integer [] rArray = new Integer[n2+1];
		
		for(int i = 0; i < n1; i++)
		{
			lArray[i] = array[p + i ];
		}
		
		for(int j = 0; j < n2; j++)
		{
			rArray[j] = array[q + j +1];
		}
		
		lArray[n1] = Integer.MAX_VALUE;
		rArray[n2] = Integer.MAX_VALUE;
		
		int i = 0;
		int j =0;
		for(int k = p; k <= r; k++)
		{
			if (lArray[i] <= rArray[j])
			{
				array[k] = lArray[i];
				i = i + 1;
			}
			else 
			{
				array[k] = rArray[j];
				j = j + 1;
			}
			
		}
		
		return array;
	}

}

我们使用Junit测试:

@Test
	public void testMerge()
	{
		DivideAndConquer dac = new DivideAndConquer();
		int[] a = {2, 4, 5, 7, 1, 2, 3, 6};
		int[] resultA = {1, 2, 2, 3, 4, 5, 6, 7 };
		assertArrayEquals(dac.merge(a,0,3,7), resultA);
	}

6.总结

    我们通过上面提到的分治的步骤,首先,将一个数组进行分解成两个部;其次就是将每个部分进行排序,笔者给出的例子是已经排序好的,这就是解决问题;最后将排序好的两个数组合并成一个排序好的数组。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值