算法导论系列:分治算法

1,207 阅读4分钟

说起分治法,大家一定也都听过秦始皇采用郡县制将国家分为三十六郡的故事,我们常说”山高皇帝远”,意思就是山高路远,皇帝都管不了,实际上无论皇帝多远,山有多高,整个国家都属于朝廷统治,但皇帝一个人是管不了这么多事情的,那如何一统天下?秦始皇的郡县制其实就是分而治之的一种变种,我们现在的国家也是这样,国家分省,市,县,乡,这样层次管理,无论在那个偏僻的角落,都不是无政府的.

而我们的分治法,其实是一种很古老的策略,<孙子兵法>里有句古话,”凡治众如治寡,分数是也”,这里的”分数”,是指分到各层次的部分,”数”是指每部分人的人数,意思就是将帅只需要通过管理少数几个人即可实现管理全部队的各个组织,这样,人数众多的军队,就如同管理几个人一样容易.在算法设计中,我们也引入分而治之的策略,称为分治算法,其本质其实就是将一个问题分解为若干个规模较小的相同子问题,分而治之.


分治算法秘籍:
分治法解题的基本步骤如下:
1:分解问题:
将要解决的问题分解为若干个规模较小,相互独立,与原问题形式相同的子问题

2:问题治理:

求解各个子问题,由于各个子问题和原问题的形式相同,只是规模较小,因此当子问题划分的足够小时,我们就可以用较为简单的方法去解决.

3:问题合并

按照原问题的要求,将子问题的解逐层的合并构成原问题的解.

一句话总结,分治法就是将一个难以直接解决的大问题,分割成规模较小的相同子问题,以便各个击破,分而治之.


在使用分治法时,使用递归算法是解决问题的利器.下面我们用二分搜索,这个最典型的分治问题来举例,看看分治算法是如何进行工作的.

二分搜索-猜数问题

我们一定都玩过猜数游戏,现在我们两个人玩这个游戏,我在我的手心写一个100以内的整数,并且只能给你大了或小了的提示,并且只有三次机会,那如何才能以最快的速度猜出来呢?


解题思路:

从问题的描述来看,如果是n个数,最坏的情况我们得猜n次才可以成功,其实我们没有必要非得一个个的去猜,这显然是一个笨方法,因为这些数是有序的,我们可以按照折半查找的方式,每次和中间的元素去比较,如果每次比中间的部分大,去后半部分找,比中间部分小,去后半部分找.

那我们现在思路有了,可以将问题抽象描述出来:

给定n个元素,假设这些元素是有序的,从中查找特定元素x.


解题思想:

将有序序列先大致分为数目相等的两组,然后去中间的元素与特定的查找元素进行比较,如果x等于中间元素,查找成功,如果x小于中间元素,在前半部分继续执行分解和治理操作,如果x大于中间元素,去后半部分进行分解和治理.

算法设计:
使用一维数组S[]放置该有序序列,设置变量low和high表示查找的上下界,middle表示中间的位置,x为特定的查找元素.

1:初始化.令low=0(S[]中的第一位数),high=n-1(S[]中最后一位数).

2:middle = (low+high)/2,表示中间的查找范围.

3:判断low<high是否成立,如果成立,继续下一步,否则结束.

4:判断x与S[middle]的关系,如果两者相同,算法结束,输出结果,否则,如果x>S[middle],low = middle+1,如果x<S[middle],则high = middle-1.


实战演练:

实验结果: