Tcl:递归proc给出“堆栈空间”

时间:2012-12-02 01:36:49

标签: list recursion tcl

我是一个Tcl新手,为了学习我正试图实现维基百科的合并排序算法伪代码:

function merge_sort(list m)
// if list size is 1, consider it sorted and return it
if length(m) <= 1
    return m
// else list size is > 1, so split the list into two sublists
var list left, right
var integer middle = length(m) / 2
for each x in m before middle
     add x to left
for each x in m after or equal middle
     add x to right
// recursively call merge_sort() to further split each sublist
// until sublist size is 1
left = merge_sort(left)
right = merge_sort(right)
// merge the sublists returned from prior calls to merge_sort()
// and return the resulting merged sublist
return merge(left, right)

在我的Tcl脚本中,我做了:

proc merge_sort { lst } {

   if { [llength $lst] <= 1 } {
       return $lst
   }

   set middle [expr {[llength $lst] / 2}]

   set left [lrange $lst 0 $middle]
   set right [lrange $lst [expr {$middle + 1}] [llength $lst]]

   set left [merge_sort $left]
   set right [merge_sort $right]

   return [merge $left $right]
}

根据我的调试尝试,一切正常,直到递归调用merge_sort proc。

输出说我“在堆栈空间之外(无限循环?)”。老实说,我没有看到代码中的问题。我哪里错了?

1 个答案:

答案 0 :(得分:1)

一个问题是,您的代码使用[lrange $lst 0 $middle]来获取字符串的左侧部分,但由于lrange的范围是从零开始的,这意味着对于两个成员列表{7 8},您将middle等于1left将为{7 8}

此外,由于您使用[lrange $lst [expr {$middle + 1}] [llength $lst]]作为right,因此对于同一列表,它会导致空列表,因为[lrange $lst 2 2]对于两个成员列表为空。

我还将右lrange更改为使用end作为最后一个索引,因为这是一种常见的最佳做法,而不是[expr {[llength $lst] - 1}]本来是等效的。

proc merge_sort { lst } {

   if { [llength $lst] <= 1 } {
       return $lst
   }

   set middle [expr {[llength $lst] / 2}]

   #for each x in m *before* middle add x to left
   set left [lrange $lst 0 [expr {$middle - 1}]]

   #for each x in m *after or equal* middle add x to right
   set right [lrange $lst $middle end]

   set left [merge_sort $left]
   set right [merge_sort $right]

   return [merge $left $right]
}