【问题标题】:Understanding Recursion using flow of control through recursion calls for Merge Sort通过合并排序的递归调用了解使用控制流的递归
【发布时间】:2017-01-08 18:08:45
【问题描述】:

我正在研究合并排序中使用递归的控制流程。

我使用的特定算法是:

MergeS(ar, p, r){

 1. if p<r{
 2.    k = floor[(p+r)/2]
 3.    MergeS(ar, p , k)
 4.    MergeS(ar, k+1, r) //in the schematic diagram I have written this as mergeS(,,)
 5.    Merge(ar, p ,k, r)
 6. } 
 7.}

Merge(ar, p, k, r){

 8.  n1 = k-p+1
 9.  n2 = r-p
 10. let L[1...n1+1] and R[1....n2+1] be new arrays

 11. for i=1 to n1
 12.   L[i] = ar[p+i-1]

 13. for j=1 to n2
 14.   R[j] = ar[k+j]

 15. L[n1+1] = Infinity
 16. R[n2+1] = Infinity

 17. i = 1
 18. j = 1

 19. for t = p to r
 20.   if L[i] <= R[j]
 21.     A[t] = L[i]
 22.     i = i+1
 23.   else
 24.     A[t] = R[j]
 25.     j = j+1
 30. }

MergeS(ar, k+1, r)merge(ar, k+1, r) 完全相同。我在后者中使用了小写的m,只是为了在示意图中获得更好的视觉清晰度

为了便于理解,我举了一个数组的例子——43,32,56,12,4

递归调用的流程如下图所示,直到第一次调用 Merge 并执行该块内的代码。

---1:MergeS(ar, 0, 5)-----

if(0<5):true ; set k=(0+5)/2

---暂停1:MergeS(ar, 0, 5)-----Call-->2:MergeS(ar, 0, 2) ---------

if(0<2):true ; set k=(0+2)/2

---暂停2:MergeS(ar, 0, 2)-----调用-->3:MergeS(ar, 0, 1) ---------

if(0<1):true ; set k=(0+1)/2

---暂停 3:MergeS(ar, 0, 1)-----Call-->4:MergeS(ar, 0, 0) ---------

if(0<0):false  

---简历3:MergeS(ar, 0, 1)-----Call-->5:mergeS(ar, 0+1, 5)强>---------

if(1<5):true ; set k=(1+5)/2

---暂停5:mergeS(ar, 0+1, 5)-----调用-->6:MergeS(ar, 1, 3)强>---------

if(1<3):true ; set k=(1+3)/2

---暂停 6:MergeS(ar, 1, 3)--Call-->7:MergeS(ar, 1, 2) ---------

if(1<2):true ; set k=(1+2)/2

---暂停 7:MergeS(ar, 1, 2)-----Call-->8:MergeS(ar, 1, 1) ---------

if(1<1):false

---简历 7:MergeS(ar, 1, 2)-----Call-->9:mergeS(ar, 1+1, 5)---------

if(2<5):true ; set k=(2+5)/2

---暂停9:mergeS(ar, 2, 5)--------调用-->10:Merge(ar, 2, 3)---------

if(2<3):true ; set k=(2+3)/2

---暂停 10:Merge(ar, 2, 3)-------调用-->11:Merge(ar, 2, 2)强>---------

if(2<2):false 

---简历 10:MergeS(ar, 2, 3)-----Call-->12:mergeS(ar, 2+1, 5)强>---------

if(3<5):true ; set k=(3+5)/2

---暂停 12:mergeS(ar, 2+1, 5)--------调用-->13:MergeS(ar, 5, 5 )---------

if(5<5):false 

---简历12:mergeS(ar, 2+1, 5)-------调用-->Merge(ar, 3, 4, 5) ---------

n1 = 4-3+1=2
n2 = 5-4=1

for(i = 0 to i=1):
  iteration1: 
    L[0] = ar[3+0-1]= ar[2] //value 56 is assigned to ar[2]
  iteration2:
    L[1] = ar[3+1-1] = ar[3] //value 12 is assigned to ar[3]

for(j=0 to j=0):
  iteration1:
    R[0] = ar[4+0] = ar[4] //value 4 is assigned to ar[4]

x = 0;
y = 0;

for(t=0 to t=1):
  iteration1: 
   /* if(L[0]<= R[0]) //56<=4:false */
   else
     ar[0] = R[0] //4 is assigned to ar[0]
     y = y+1
  iteration2:
   if(L[0]<=R[1]): //56<=infinity
     ar[1] = L[0] // 56 is assigned to ar[1]

在上一步之后,我在ar[0] 中得到了一个值4,在ar[2] 中得到了一个值56。我的猜测是这是错误的。

我需要帮助了解我出错的地方以及对此的解释。

【问题讨论】:

  • 显示的递归调用流显示从 0 开始的索引,但伪代码显示从 1 开始的索引。使用 p = 起始索引和 r = 结束索引 (1过去数组的最后一个元素)。两个 MergeS 递归调用将是 MergeS(ar, p, k) 和 MergeS(ar, k, r) ...(k 而不是 k+1)。
  • 如果我采用 MergeS(ar, k, r) 则中间索引元素将不必要地在每个递归调用中多次复制(当调用除法的右侧部分时)。如果您可以检查我在每次调用中传递的参数并验证它们是否正确?如果不是,我在什么电话中输入了错误的参数。
  • 假设 r 是 MergeS(ar, p, r) 中的结束索引,那么整个数组的基于 C 的循环将是 for(i = 0; i
  • 好的,明白了。你和我在终止条件上基本不同(我假设

标签: algorithm sorting recursion merge


【解决方案1】:

问题中算法中的索引需要在代码中修改,以方便使用。我不是说算法错了,绝对正确,只需要修改。

Merge的调整代码:

 private static void Merge(int[] ar, int p, int k, int r) {

    int n1 = k-p+1;
    int n2 = r-k;
    int[] L = new int[n1+1];
    int[] R = new int[n2+1];

    for(int i=0; i<n1; i++){
        L[i] = ar[p+i]; // p+i and not p+i-1
    }
    for(int i=0; i<n2; i++){ 
        R[i] = ar[k+i+1]; //k+1+i and not k+i
    }

    // Use of Tnteger.MAX_VALUE
    L[n1]=Integer.MAX_VALUE;
    R[n2]=Integer.MAX_VALUE;

    int i = 0;
    int j = 0;

    for(int t=p; t<=r; t++){ //carefully set initialization and t<=r and not simply t<r
        if(L[i]<r[j]){
            ar[t] = L[i];
            i++;
        }
        else{

              ar[t] = R[j];
              j++;
            }
        }
    }
}

递归调用的正确流程如下图所示:(上面控制图的变化用斜体表示

---1:MergeS(ar, 0, 5)-----

if(0<5):true ; set k=(0+5)/2

---暂停1:MergeS(ar, 0, 5)-----调用-->2:MergeS(ar, 0, 2) ---------

if(0<2):true ; set k=(0+2)/2

---暂停2:MergeS(ar, 0, 2)-----调用-->3:MergeS(ar, 0, 1) ---------

if(0<1):true ; set k=(0+1)/2

---暂停3:MergeS(ar, 0, 1)-----调用-->4:MergeS(ar, 0, 0) ---------

if(0<0):false  

---Break 4:MergeS(ar, 0, 0)-----Call-->5:mergeS(ar, 0 +1,1)---------

if(1<_1_):_false_ ; 

---Break 5:mergeS(ar, 0+1, 1)-----Call-->Merge(ar,0,0,1) em>

使用参数ar, 0, 0, 1 执行Merge 函数后,数组43 32 56 12 4 的前两个索引处的元素被交换。

维护一堆函数调用就派上用场了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-15
    • 2017-12-22
    • 1970-01-01
    • 2013-10-05
    • 2021-11-06
    • 2019-01-22
    相关资源
    最近更新 更多