我在一位教我 C++(作为第一语言)的朋友的指导下编写了递归函数。但是,我真的不明白发生了什么事。他帮助我(以及 SO 社区)编写了一个合并排序函数。

std::vector<int> mergeSort(std::vector<int> original)

//code here to create two vectors, farray and sarray, out of the 
//original std::vector<int> original ; each is half the length,
//note: if the size % 2 != 0, sarray takes the odd int

farray = mergeSort(farray);
sarray = mergeSort(sarray);

//code here merges the two into a single, final sorted std::vector   

在此函数中,我分配:

farray = mergeSort(farray);
sarray = mergeSort(sarray);

这里究竟发生了什么?它以 farray 和 sarray 作为参数调用 mergeSort 并更改值。mergeSort 递归执行到什么程度?只是递归函数调用吗?

有帮助吗?

解决方案

每个你递归调用函数时,它有效地使得它所需要的信息,新的副本,并继续下去。

您可以有复发“无限”,即一个程序,直到耗尽资源,通常栈空间 - 在这些副本去的空间。这将看起来像

void recur(){
    recur();
}

int main(){
    recur();
    exit(0); /* won't ever really get here.*/
}

显然,这不是很有用,所以你要编写上有重复出现的频率一些限制的程序。下面是一个管理着一个非常简单的程序:

#include <iostream>
using namespace std;
void recurSome(int count){
    cout << "RecurSome called with " << count << endl;
    if (count > 0){
        recurSome(count-1);
        cout << "Back at " << count << endl;
    }else{
        cout << "Bottom." << endl;
    }
    return;
}

int main(){
    recurSome(10);
    exit(0);  /* now it will get here. */
}

如果你编译并运行,以说:

bash $ g++ -Wall -o rc recursome.cpp
bash $ ./rc

您会获得满意的结果:

RecurSome called with 10
RecurSome called with 9
RecurSome called with 8
RecurSome called with 7
RecurSome called with 6
RecurSome called with 5
RecurSome called with 4
RecurSome called with 3
RecurSome called with 2
RecurSome called with 1
RecurSome called with 0
Bottom.
Back at 1
Back at 2
Back at 3
Back at 4
Back at 5
Back at 6
Back at 7
Back at 8
Back at 9
Back at 10
bash $ 

请参阅它被如何要求10,然后如图9所示,等等,然后将其到达底部之后,它示出了它回来1,则2,依此类推回升到10?

在基本规则是:每一个的递归函数应该有一些,使一个基本情况,其中之一的的再次调用本身。在这其中,基本情况是count == 0。事实上,我们可以写此作为递归定义

  

recursome:结果       如果c = 0:打印底部,点击       如果c> 0:打印计数,和recursome(C-1)

您会看到诸如此类的许多递归定义,你在数学上移动

这里的更好的输出稍微niftier C版:

#include <stdio.h>
#include <stdlib.h>

int max = 10;

void recurSome(int count){
    printf("RecurSome %*c Called with %d\n", max-count+1, ' ', count);
    if (count > 0){
        recurSome(count-1);
        printf("RecurSome %*c Back at %d\n", max-count+1, ' ', count);
    }else{
        printf("RecurSome %*c Bottom.\n", 2*max, ' ');
        printf("RecurSome %*c Back at %d\n", max-count+1, ' ', count);
    }
    return;
}

int main(){
    recurSome(max);
    exit(0);  /* now it will get here. */
}

输出:

RecurSome   Called with 10
RecurSome    Called with 9
RecurSome     Called with 8
RecurSome      Called with 7
RecurSome       Called with 6
RecurSome        Called with 5
RecurSome         Called with 4
RecurSome          Called with 3
RecurSome           Called with 2
RecurSome            Called with 1
RecurSome             Called with 0
RecurSome                      Bottom.
RecurSome             Back at 0
RecurSome            Back at 1
RecurSome           Back at 2
RecurSome          Back at 3
RecurSome         Back at 4
RecurSome        Back at 5
RecurSome       Back at 6
RecurSome      Back at 7
RecurSome     Back at 8
RecurSome    Back at 9
RecurSome   Back at 10

其他提示

检查出来在字典中:

<强>递归:名词。参见递归

现在,作为严重,在上面的玩笑,递归的定义在递归本身来给出。即递归。

一个递归算法是一种算法,其实现是基于算法本身。开发这样的算法的过程开始于最基本的情况下,其溶液是预先已知的,或者可以被平凡计算。然后,你在其本身来定义的算法。

作为简单的示例,在计算一个给定的整数的n次方我可能是一个功能power( int number, int power )。你怎么能实现呢?很多方面。最简单的是到库的调用,接着一个循环,或者你可以用自身的定义函数:

int power( int number, unsigned int pow )
{
   // Basic trivial case, cuts the recursion:
   if ( pow == 0 ) return 1;

   // Implement power in terms of itself:
   return number * power( number, pow-1 );
}
int main()
{
   int power = power( 2, 10 );
}

我们已经在其本身来定义该函数。你开始用最简单的情况下(N ^ 0 = 1)。如果我们不是在简单的情况下,您可以用自身的表达你的算法。

该计划将启动在主要通过调用power( 2, 10 )将递归并调用power( 2, 9 )减少问题的的的问题,然后将组成最终答案的简单问题的条款。

在实际工作调用跟踪将是:

power( 2, 5 )
  power( 2, 4 )
    power( 2, 3 )
      power( 2, 2 )
        power( 2, 1 )
          power( 2, 0 )    // simplest case: return 1
        return 2 * 1 -> 2  // obtain next solution in terms of previous
      return 2 * 2 -> 4
    return 2 * 4 -> 8
  return 2 * 8 -> 16
return 2 * 16 -> 32

在开发递归算法通常让我相信我已经有算法和运行,只是在新的结果进行还原/合成工作。

递归可以理解为归纳原理的实际应用。为了证明所有 n 的陈述 P(n),其中 P(n) 意味着“从 1 到 n 的整数之和是 n(n+1)/2”,我们必须证明两件事:

  1. 基本情况: P(n) 对于特定整数成立。P(1) 为真,因为 1 = 1(1+1)/2。
  2. 电感案例: 如果 P(n) 为真,则 P(n+1) 也必定为真。1 + ...+ n + (n+1) = n(n+1)/2 + (n+1) = n(n+1)/2 + 2(n+1)/2 = (n+1)((n +1)+1)/2,即语句P(n+1)。

类似地,在像 mergeSort 这样的递归函数中,我们需要处理两种情况:

  1. 基本情况: 如果数组只有一个元素,则它已排序;否则
  2. 递归情况: 将数组拆分为两个较小的数组,对每个数组进行合并排序,然后将它们合并在一起。

关键是这两个数组是 较小 比原来的要好,否则其中之一永远不会达到基本情况。由于数组大致分为两半,因此在这种情况下递归的深度约为 log2(n)。

就问题中的代码而言,存在三个问题:

  1. 基本情况缺失。
  2. 重用变量 farray 和 sarray 并不是绝对必要的,而且可能会造成混乱。
  3. 由于创建和销毁的 std::vector 数量较多,代码将非常慢。mergeSort 的最佳接口采用两个向量::迭代器作为输入,类似于 std::sort() 函数。

新程序员应该尝试用纸和笔运行合并排序。

有关一个递归函数来不可能是无限的,需要有一些条件,其中它返回而不调用本身。对于一些算法,该条件是其对数据进行通话不再有意义的点。

在你的情况下,如果拆分传入向量和结束两个向量,每个只包含1项,是否有意义呼吁他们归并()?号

您可以通过检查farray和sarray的大小,决定是否将它们结合起来,并在返回前组合上的一个或两个调用归并()处理这个问题。

如果一个有2个项目和一个具有1?上的尺寸2调用归并(),但不是在尺寸1。

当于归并()的调用不返回之前在任farray或sarray调用归并(),递归将开始退绕。

有一个在维基百科页面排序合并更多的信息,你”重新尝试做的。

作为一个旁注,要知道,你让你给出一个参数每载体的拷贝。使用矢量<>常量&代替。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top