合并排序示例中的c ++递归

时间:2013-11-17 19:15:25

标签: c++

我对c ++中的递归有一个非常普遍的问题。为了更好地理解,我使用以下合并排序示例来解释我的不确定性。

   void mergesort (int* first, int* last)
{
   int n = last - first;
   if (n<=1)return;
   int* middle = first + n/2;
   mergesort (first, middle);
   mergesort (middle, last);
   merge (first,middle, last);
}

必须定义函数merge。函数参数int* first,int* last分别指向数组中第一个和最后一个元素的指针。假设数组的长度为10.让我们看看会发生什么:

  1. 由于10大于1,我们声明一个指针int* middle = first + 5;
  2. 现在我的问题:我们正在调用mergesort(first, middle),一旦我们将单个“元素”中的第一个数组拆分,这个递归就会结束。但是mergesort(middle,last)mergesort(first,middle)终止或同时执行后会执行吗?不知何故,它必须同时出现,否则我们不会将后半部分分成单个“元素”。与上次合并排序相同的问题。那么递归如何执行多个函数调用?

    编辑我添加了完整的源代码以及输出:

    //Mergesort.cpp
    //
    
    #include <iostream>
    void merge (int* first, int* middle, int* last)
    {
      int n = last - first;
      std::cout<<"merge part, n= " << n<<"\n";
      std::cout<<"merge part, middle= " << *middle << "\n";
      std::cout<<"merge part, last= "<<*last << "\n";
      int* deck = new int[n];
    
      int* left = first;
      std::cout<<"merge part, left = first " << *left<< "\n";
      int* right = middle;
      std::cout << "merge part, right = middle " << *right << "\n";
      for (int* d = deck; d!=deck+n;++d){
        if (left == middle) *d = *right++;
        else if (right==last ) *d=*left++;
        else if (*left < *right) *d = *left++;
        else *d = *right++;}
    
      int *d = deck;
      while (first != middle) *first++ = *d++;
      while (middle != last) *middle++ = *d++;
    
      delete[] deck;
    }
    
    
    void mergesort (int* first, int* last)
    {
      int n = last - first;
      if (n <= 1) return;
      std::cout << "n= " << n;
      int* middle = first + n/2;
      std::cout << "first = "<< *first << "middle = "<< *middle<<"\n";
      mergesort (first, middle);
      mergesort (middle, last);
      merge (first, middle, last);
    }
    
    int main () 
    {
      int a[4]={6,2,1,3};
      int* first = a;
      int* last = a+4;
      mergesort (first, last);
      std::cout<< a[0]<< a[1]<< a[2]<< a[3]<<"\n";
      return 0;
    }
    

    输出:

    ThinkStation-S20:~/c++/test_files$ ./mergesort 
    n= 4first = 6middle = 1
    n= 2first = 6middle = 2
    merge part, n= 2
    merge part, middle= 2
    merge part, last= 1
    merge part, left = first 6
    merge part, right = middle 2
    n= 2first = 1middle = 3
    merge part, n= 2
    merge part, middle= 3
    merge part, last= 4197792
    merge part, left = first 1
    merge part, right = middle 3
    merge part, n= 4
    merge part, middle= 1
    merge part, last= 4197792
    merge part, left = first 2
    merge part, right = middle 1
    1236
    

2 个答案:

答案 0 :(得分:2)

像C一样,C ++一个接一个地按顺序执行语句。因此第二次调用mergesort将在第一次返回后发生。通过merge的适当定义,这将很好地工作。我强烈建议您自己尝试该程序,用纸和笔模拟计算机。它不会花太长时间(诚实!)它应该解决你的疑虑。

与quicksort一样,mergesort可以(部分)并行执行。对mergesort的两个递归调用是相互独立的,因此执行可能会重叠。但是,如果没有相当多的额外工作,C ++就不会为你做到这一点。


这是用铅笔和纸做的一种方法,我认为比试图解释printf输出更容易理解。

  1. 制作十几张卡片大小的纸张。
  2. 从第一次调用mergesort开始,来自main
  3. 抓住其中一张牌,并填写四个变量:first,last,middle,n。
  4. 逐步进入mergesort,直到您拨打新电话。在当前卡上写下呼叫的行号,将其放在“堆栈”(从空白处开始),然后继续执行步骤3.
  5. 当你到达mergesort的末尾时,丢弃当前的卡并返回到前一个卡,它将位于堆栈的顶部。继续执行步骤4,从mergesort中的下一行开始。
  6. 当你完成了所有的牌时,你就完成了。

答案 1 :(得分:0)

同时没有任何事情发生,它有助于将每个连续的函数调用视为添加到堆栈。在函数结束时,它会弹出堆栈并继续。

http://www.youtube.com/watch?v=_r0gV2hQYf0