Lua 中的递归合并排序显示错误行为;虽然几乎相同的 python 代码运行良好

recursive merge sort in Lua showing wrong behavior; while almost same python code works well

对不起,如果我的英语不好,我的母语是韩语。

我尝试使用下面的伪代码 Lua 实现递归归并排序:

void merge(int h, int m, const keytype U[], const keytype V[], keytype S[]) {
    index i, j, k;
    i = 1; j = 1; k = 1;
    while (i <= h && j <= m) {
        if (U[i] < V[j]) {
            S[k] = U[i];
            i++;
        } else {
            S[k] = V[j];
            j++;
        }
        k++;
    }
    if (i > h) {
        copy V[j] through V[m] to S[k] through S[h+m];
    } else {
        copy U[i] through U[h] to S[k] through S[h+m];
    }
}
void mergesort(int n, keytype S[]) {
  if (n > 1) {
    const int h = ⌊n/2⌋, m= n - h;
    keytype U[1..h], v[1..m];
    copy S[1] through S[h] to U[1] through U[h];
    copy S[h+1] through S[n] to V[1] through V[m];
    mergesort(h,U);
    mergesort(m,V);
    merge(h,m,U,V,S);
  }
}

我写了 Lua:

function merge(h, m, U, V, S)
    print(S[1], S[h+m])
    i, j, k = 1, 1, 1
    while i<=h and j<=m do
        if U[i] < V[j] then
            S[k] = U[i]
            i = i+1
        else
            S[k] = V[j]
            j = j+1
        end
        k = k+1
    end
    if i>h then
        while j<=m do
            S[k] = V[j]
            j, k = j+1, k+1
        end
    else
        while i<=h do
            S[k] = U[i]
            i, k = i+1, k+1
        end
    end
end

function mergeSort(n, S)
    if n>1 then
        h = math.floor(n/2)
        m = n - h
        local U = {}
        local V = {}
        i = 1
        while i<=h do
            U[i] = S[i]
            i = i + 1
        end
        while i<=n do
            V[i-h] = S[i]
            i = i + 1
        end
        print(h, m)
        mergeSort(h, U)
        mergeSort(m, V)
        merge(h, m, U, V, S)
    end
end

s = {52, 33, 14, 27, 8, 31, 24, 11, 5, 36, 44, 47, 20}
mergeSort(#s, s)
for k, v in ipairs(s) do
    print(v)
end

但结果是 14, 33, 14, 27, 8, 31, 24, 11, 5, 36, 44, 47, 20,未排序且元素重复。 但是,我尝试将此 Lua 代码转换为 python 代码:

import math

def merge(h, m, U, V, S):
    print(S[1], S[h+m])
    i, j, k = 1, 1, 1
    while i<=h and j<=m:
        if U[i] < V[j]:
            S[k] = U[i]
            i = i+1
        else:
            S[k] = V[j]
            j = j+1
        k = k+1
    
    if i>h:
        while j<=m:
            S[k] = V[j]
            j, k = j+1, k+1
    else:
        while i<=h:
            S[k] = U[i]
            i, k = i+1, k+1

    
def mergeSort(n, S):
    if n>1:
        h = math.floor(n/2)
        m = n - h
        U = {}
        V = {}
        i = 1
        while i<=h:
            U[i] = S[i]
            i = i + 1
        while i<=n:
            V[i-h] = S[i]
            i = i + 1
        print(h, m)
        mergeSort(h, U)
        mergeSort(m, V)
        merge(h, m, U, V, S)

a = [52, 33, 14, 27, 8, 31, 24, 11, 5, 36, 44, 47, 20]
s = dict(enumerate(a, 1))
mergeSort(len(s), s)
print([s[i] for i in range(1, len(s)+1)])

我认为这与 pythonic 代码相去甚远,但无论如何,这段代码毕竟对序列进行了很好的排序,结果是 [5, 8, 11, 14, 20, 24, 27, 31, 33, 36, 44, 47, 52]。 所以我发现这个错误与 Lua table 有关,但是通过 print() 调试给出的信息很少,我找不到任何与此相关的 lua 参考。 我的 lua 代码会有什么问题?另外,如何让我的 python 代码更 pythonic?

问题源于您使用全局变量而不是局部变量。函数调用将以这种方式改变调用“父”函数的值。如果将函数内声明的所有全局变量本地化,它既可以修复错误又可以提高性能。考虑使用 linter 来发现此类全局变量错误。

固定代码:

function merge(h, m, U, V, S)
    print(S[1], S[h+m])
    local i, j, k = 1, 1, 1
    while i<=h and j<=m do
        if U[i] < V[j] then
            S[k] = U[i]
            i = i+1
        else
            S[k] = V[j]
            j = j+1
        end
        k = k+1
    end
    if i>h then
        while j<=m do
            S[k] = V[j]
            j, k = j+1, k+1
        end
    else
        while i<=h do
            S[k] = U[i]
            i, k = i+1, k+1
        end
    end
end

function mergeSort(n, S)
    if n>1 then
        local h = math.floor(n/2)
        local m = n - h
        local U = {}
        local V = {}
        local i = 1
        while i<=h do
            U[i] = S[i]
            i = i + 1
        end
        while i<=n do
            V[i-h] = S[i]
            i = i + 1
        end
        print(h, m)
        mergeSort(h, U)
        mergeSort(m, V)
        merge(h, m, U, V, S)
    end
end

local s = {52, 33, 14, 27, 8, 31, 24, 11, 5, 36, 44, 47, 20}
mergeSort(#s, s)
for k, v in ipairs(s) do
    print(v)
end