算法系列之经常使用算法之一----分治算法

1、基本概念算法

在计算机科学中,分治法是一种很重要的算法。分治算法,字面上的解释是“分而治之”,分治算法主要是三点:数组

1.将一个复杂的问题分红两个或更多的相同或类似的子问题,再把子问题分红更小的子问题----“分”函数

2.将最后子问题能够简单的直接求解----“治”spa

3.将全部子问题的解合并起来就是原问题打得解----“合”blog

这三点是分治算法的主要特色,只要是符合这三个特色的问题均可以使用分治算法进行解决(注意用词,是”用”,至于好很差就是另一回事了)排序

2、分治法的特征递归

分治法所能解决的问题通常具备如下几个特征:内存

1) 该问题的规模缩小到必定的程度就能够容易地解决开发

2) 该问题能够分解为若干个规模较小的相同问题,即该问题具备最优子结构性质。get

3) 利用该问题分解出的子问题的解能够合并为该问题的解;

4) 该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子子问题。

第一条特征是绝大多数问题均可以知足的,由于问题的计算复杂性通常是随着问题规模的增长而增长;

第二条特征是应用分治法的前提它也是大多数问题能够知足的,此特征反映了递归思想的应用;、

第三条特征是关键,可否利用分治法彻底取决于问题是否具备第三条特征,若是具有了第一条和第二条特征,而不具有第三条特征,则能够考虑用贪心法或动态规划法。

第四条特征涉及到分治法的效率,若是各子问题是不独立的则分治法要作许多没必要要的工做,重复地解公共的子问题,此时虽然可用分治法,但通常用动态规划法较好

3、为何用分治法?怎么正确使用分治法?

为何用分治算法?咱们使用一种算法的缘由大部分状况下都是为了”快“,只有在少数状况下,在程序已经足够”快“的前提下,咱们才会牺牲一部分的”快“,去保全一些开发因素(好比,程序的可维护性等等),那么分治算法为何快?咱们在用这个算法以前必需理解清楚这个问题。

分治算法的思想就是将一个问题规模比较大的问题划分为几个相同逻辑性质(或者直接理解为相似)的问题规模变小的子问题。咱们能够从这里入手。

举个超级简单的例子:

假若有一个存在n个元素的int型数组,咱们须要求该数组的和。

可能有些人想不想就是一个分治算法,将这个问题分为两个子问题,而后每一个子问题再分为两个子问题,当子问题的规模为只有两个数时进行相加。。。

然而,这种办法是使用了分治算法,但是效率比直接遍历一遍相加获得的效率还要低的多.

为何?由于分治算法自己不适合这种单次遍历就能够搞定的简单问题。大家在阅读一遍分治算法的思想:分治算法的思想就是将一个问题规模比较大的问题划分为几个相同逻辑性质的问题规模变小的子问题,那么这个定义存在一个隐含的前提,当问题规模比较大时,该问题解决起来要成倍的困难!

咱们能够举这样一个简单的例子:
咱们对一个存在n个元素的数组,使用简单排序进行排序时:

当n=1时,无需比较

当n=2时,咱们须要1次比较

当n=3时,咱们须要3次比较

当n=4时,咱们须要6次比较

当n的数值比较大时,咱们须要比较的次数愈来愈多将会是一个巨大的数字。

而对于前面的求和的例子:
当n=1时,无需相加

当n=2时,咱们须要1次相加

当n=3时,咱们须要2次相加

当n=4时,咱们须要3次相加

仔细观察这组数据,是否发现了什么?

对于求和的例子来讲,该问题的计算量与问题规模成正比,在相同的条件下,咱们根本无须使用分治算法,由于即便这个问题规模变大,他的解决问题的难易程度没有丝毫改变,它所付出的,只不过是增大了问题规模后所必须付出的计算量,归纳起来就是线性增加的问题规模致使了线性增加的计算量。

而对于排序的例子,当问题规模变大时,计算量的增大是成幂次型增加的,归纳起来就是线性增加的问题规模致使了幂次型计算量的增加。使得问题规模大的问题解决起来更加困难。

综合起来归纳,在问题规模与计算量成正比的算法中,分治算法不是最好的解法,而且有多是效率极其底下的算法。若是存在某个问题,线性增加的问题规模可能带动计算量的非线性增加,而且符合分治算法的三个特征,那么分治算法是一个很不错的选择。

4、实例解析

1.二分查找

实例分析:也许有人看到这里认为二分查找算法与我前面的推论是矛盾的,但其实并不矛盾。不矛盾的缘由在于二分查找算法是存在前提条件的。二分查找的数组必须是有序状态的,二分查找是根据它的规则特性人们找到的一种取巧的方法。对于一个无序的查找方法,个人结论依然有效。

代码来一波:

image

 

2.棋盘覆盖

问题描述: 一个2^k×2^k 个方格组成的棋盘中,恰有一个方格与其余方格不一样,称该方格为一特殊方格,且称该棋盘为一特殊棋盘。在棋盘覆盖问题中,要用图示的4种不一样形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格之外的全部方格,且任何2个L型骨牌不得重叠覆盖。

image

 

实例分析:每次都对分割后的四个小方块进行判断,判断特殊方格是否在里面。这里的判断的方法是每次先记录下整个大方块的左上角(top left coner)方格的行列坐标,而后再与特殊方格坐标进行比较,就能够知道特殊方格是否在该块中。若是特殊方块在里面,这直接递归下去求便可,若是不在,这根据分割的四个方块的不一样位置,把右下角、左下角、右上角或者左上角的方格标记为特殊方块,而后继续递归。在递归函数里,还要有一个变量s来记录边的方格数,每次对方块进行划分时,边的方格数都会减半,这个变量是为了方便判断特殊方格的位置。其次还要有一个变nCount来记录L型骨牌的数量。

代码秀:

image

 

运行结果:

image

 

3.归并排序/合并排序

实例分析:咳咳,大名鼎鼎的合并排序不用我多说吧。。。缺点是须要多占一些内存充当缓冲区。。

上代码:

image

 

4.快速排序

运行结果:有了合并排序怎么能够没有快速排序咧

代码:

image

相关文章
相关标签/搜索