我是一个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。
输出说我“在堆栈空间之外(无限循环?)”。老实说,我没有看到代码中的问题。我哪里错了?
答案 0 :(得分:1)
一个问题是,您的代码使用[lrange $lst 0 $middle]
来获取字符串的左侧部分,但由于lrange
的范围是从零开始的,这意味着对于两个成员列表{7 8}
,您将middle
等于1
而left
将为{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]
}