To iterate is human, to reverse, divine. // 迭代乃人工, 递归显神通。
虽说如此,但是我们发现很多时候我们用到的是迭代,而不是递归 ???
举个栗子 1.数组求和
1.1迭代法
1 int sum1(int A[], int n){ 2 int sum = 0; //O(1) 3 for(int i = 0; i < n; i++){ //O(n) 4 sum += A[i]; //O(1) 5 } 6 return sum; //O(1) 7 } 8 //无论 A[] 内容如何,都有:T(n) = 1 + n * 1 + 1 = O(n)
此处可用减而治之的思想//单调性
将原问题分成两个子问题,
令其中一个问题规模缩减,并治理,//未被加和的A[i]
另一个问题规模不变,也进行治理,//每次加和的A[i]
最后将两个子问题合并。
1.2线性递归法
void sum2(int A[], int n){ return (n < 1) ? 0 : sum2(A, n - 1) + A[n - 1];}//T(n) = O(n)
2.数组倒置
其实这个在c++里有相应的函数,但是作为acmer,凡是用啥都得自己造 /坚强
2.1递归法
void Reverse(int* A, int lo, int hi){ if(lo < hi){//需要两个递归基 swap(A[lo], A[hi]); reverse(A, lo + 1, hi - 1); } else{ //考虑 0 和 1 两个特殊情况 return; } }
在此之外,我特地查了一下c++库中reverse()的代码
// reverse algorithm example #include <iostream> // std::cout #include <algorithm> // std::reverse #include <vector> // std::vector int main () { std::vector<int> myvector; // set some values: for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9 std::reverse(myvector.begin(),myvector.end()); // 9 8 7 6 5 4 3 2 1 // print out content: std::cout << "myvector contains:"; for (std::vector<int>::iterator it=myvector.begin(); it!=myvector.end(); ++it) std::cout << ‘ ‘ << *it; std::cout << ‘\n‘; return 0; } //template <class BidirectionalIterator> // void reverse (BidirectionalIterator first, BidirectionalIterator last) //{ // while ((first!=last)&&(first!=--last)) { // std::iter_swap (first,last); // ++first; // } //} //用了一个双向迭代器,思路大致一样
总的来说,就是一个分而治之的思想
将原问题分解成两个子问题,
同时进行治理,
最后合并治理。
由此我们是不是也能对刚刚第一个数组求和用这种方法呢
1.3二分递归法
void sum3(int A[], int lo, int hi){ if(lo == hi){ return A[lo]; } else{ int mi = (lo + hi) >> 1; return sum3(A, lo, mi) + sum3(A, mi + 1, hi); } } // T(n) = O(n)
3.MAX
在区间 [lo, hi)里找出最大的两个整数A[x1] 和 A[x2] //A[x1] > A[x2]
要求元素比较次数尽可能的少
3.1迭代
1 void max1(int A[], int lo, int hi, int &x1, int &x2){ 2 for(x1 = lo, int i = lo + 1; i < hi; i++){ 3 if(A[x1] < A[i]){ 4 x1 = i; 5 } 6 7 } //比较了n - 1次 8 for(x2 = lo, int i = lo + 1; i < x1; i++){ 9 if(A[x2] < A[i]){ 10 x2 = i; 11 } 12 13 } 14 for(int i = x1 + 1; i < hi; i++){ 15 if(A[x2] < A[i]){ 16 x2 = i; 17 } 18 } 19 20 } // 总共比较了2 * n - 3 次
我们不妨改变一下思路:先选 A[lo] 和A[lo + 1] 为基准找出两者间最大数的下标给x1,最小数下标给x2,
然后让A[x2] 和后面的元素比较,如果有比这个元素大的交换下标,
让A[x2]再和A[x1]比较,如果比这个元素大,那么再交换下标。
void max1(int A[], int lo, int hi, int &x1, int &x2){ if(A[x1 = lo] > A[x2 = lo + 1]){ swap(x1, x2); } for(int i = lo + 2; i < hi; i++){ if(A[x2] < A[i]){ if(A[x1] < A[x2 = i]){ swap(x1, x2); } } } } // best 比较了1 + (n - 2) * 1 = n - 1 次 // worst 比较了1 + (n - 2) * 2 = 2 * n - 3 次
似乎没有改变最糟糕的情况
不妨递归 + 分治
仿照上面二分递归的方法
思路:在数组两边选出x1L, x2L, x1R, x2R // x1L > x2L, x1R > x2R
比较两个最大的x1L, x1R, 两个中最大的即为x1
void max2(int A[], int lo, int hi, int &x1, int &x2){ if(lo + 2 == hi){ return; } else if(lo + 3 == hi){ return; } else{ int mi = (lo + hi) >> 1; int x1L, x2L, x1R, x2R; max2(A, lo, mi + 1, x1L, x2L); max2(A, mi + 1, hi, x1R, x2R); if(A[x1L] > A[x1R]){ x1 = x1L; x2 = (x2L > x1R)? x2L : x1R; } else{ x1 = x1R; x2 = (x2L > x1L)? x2L : x1L; } } } //T(n) = 2 * T(n / 2) + 2 = 5 * n / 3 - 2
原文地址:https://www.cnblogs.com/nibaba131237/p/12326038.html