数据结构学习-递归与分治
在上一篇日志中提及的递归解法中有两个:Hanoi塔问题及Fibonacci数列问题,都用到了两个递归,每一个调用处理输入的一半信息。这种递归模式就是著名的针对算法设计的“分治法”(divide and conquer)范型最很重要的例子,这个范型是许多重要算法的基础。
看下面这个问题:寻找一个数组中最大的那个元素,我们可以轻而易举的完成这个任务,只要遍历一遍数组即可。
for(t=a[0],i=1;i<N;i++)
{
if(a[i]>t)
{
t=a[i];
}
}
我们还可以用递归式的分治法给出一个也是十分简单的(但完全不同的)算法,来解决同样的问题:
这个函数将数组a[l],….a[r],分成工A[l],…..a[m],和a[m+1]……a[r]两个部分,分别求出每一部分的最大元素(递归地),并返回较大的那一个作为整个数组的最大元素。如果数组大小是偶数,两部分总是相等,如果是奇数,两部分大小差1;
Item max(Item a[],int l, int r)
{
if(l==r) return a[l];
int m=(l+r)/2;
Item u=max(a,l,m);
Item v=max(a,m+1,r);
if(u>v) return u; else return v;
}
以前也听说过分治法,还以为多么复杂呢,今天才知道原理其实非常简单,只是要实际运用,就确实需要机智与经验了。
总的来说,递归程序依赖于子问题在选定顺序下的解决顺序,对其它计算来说(如上面的寻找最大值问题)我们解决这个子问题的顺序是不相关的。对于这一类计算,惟一的约束就是我们先解决子问题再解决主问题。理解什么时候有重排计算的灵活性,不仅是使算法设计成功的关键,而且在许多上下文中有直接的实际效果,比如说,如果要考虑在并行处理器中实现算法的时候,这就是至关重要的。
分治法的应用非常广泛,如矩阵乘法、残缺棋盘、归并排序、折半查找,选择和计算一个几何问题——找出二维空间中距离最近的两个点。现在没有认真看过线性代数,又没看到排序搜索部分,所以应用就以后再说吧。