分支策略的基本思想:
第一步:将原始问题划分(分成两个或几个不同的部分或步骤)或者归结(归纳总结出普遍适用的解法)为规模较小的子问题
第二步:递归或迭代(iterative)
*迭代(递推+倒推):
确定变量
在可以用迭代算法解决的问题中,至少存在一个直接或间接地不断由旧值递推出新值的变量,这个变量就是迭代变量。
建立关系式
所谓迭代关系式,指如何从变量的前一个值推出其下一个值的公式(或关系)。迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒推的方法来完成。
过程控制
在什么时候结束迭代过程?这是编写迭代程序必须考虑的问题。不能让迭代过程无休止地重复执行下去。
三注意:
分支策略的典型例子:
1. 二分查找
中心思想:通过x与中位数的比较,将原问题归结为规模为n/2的子问题
递归法:
int binary_search(int l, int r, int x){ if(l == r) return 0; int m=(l+r)/2; if(a[m] == x) return m; else if(a[m] > x)binary_search(l,m,x); else if(a[m] < x)binary_search(m+1,r,x); } int main(){ ... binary_search(1,n,x); ... }
递推法:
l=1; r=n; while(l<=r){ m=(l+r)/2; if(a[m]==x){ printf("%d",m); break; } else if(T[m]>x)r=m-1; else l=m+1; }
二分查找最坏情况下时间复杂度:
W(n) = W(n/2) + 1
W(1) = 1
可以解出:
W(n) = log(n) + 1
2. 归并排序
中心思想:将原问题归结为规模为n/2的2个子问题
来源:http://open.163.com/movie/2010/3/D/8/M6U6LS8CV_M6U6NS2D8.html(哈佛CS50公开课)
On input of n elements:
if n < 2
Return.
else:
Sort left halfof elements.
Sort right half of elements.
Merge sorted halves.
/*
做实事的merge 算法中心
"Conquer"
*/ void merge(int l, int m, int r){ int i=l,j=m+1; int k=l; while(i<=m && j<=r){ if(a[i]<a[j])tmp[k++]=a[i++]; else tmp[k++]=a[j++]; } while(i<=m)tmp[k++]=a[i++]; while(j<=r)tmp[k++]=a[j++]; //not j<=n!!! for(i=l;i<=r;i++) a[i]=tmp[i]; } /* 并未做实事
"Divide"
*/ void merge_sort(int l, int r){ if(l == r) return; int m=(l+r)/2; merge_sort(l,m); merge_sort(m+1,r); merge(l,m,r); } int main(){ ... merge_sort(1,n); ... }
归并排序最坏情况下时间复杂度:
W(n) = 2W(n/2) + n-1
W(1) = 0
可以解出:
W(n) = nlog(n) - n + 1
3. 汉诺塔问题
中心思想: 将原问题归结为规模为n-1的2个子问题i.e. 从A到B和从B到C
伪代码:
来源:https://class.coursera.org/algorithms-001/lecture/47 (北京大学算法设计与分析公开课)
Hanoi(A, C, n) //n个盘A到C
if(n=1) then move(A, C) //1个盘A到C
else Hanoi(A, B, n-1)
move(A,C)
Hanoi(B, C, n-1)