1

我正在尝试将合并排序算法从高级语言(可能是 java?)直接翻译成 MASM615。我要翻译的实现如下:

// sort the subarray arr[i]..arr[j]
void mergeSort(int &arr, int i, int j)
{
if (i == j) return;          // terminating condition
int m = (i+j)/2;             // Step 1: compute the splitting point
MergeSort(arr, i, m);        // Step 2: sort the left part
MergeSort(arr, m+1, j);      // Step 3: sort the right part
Merge(a, i, m, j);           // Step 4: merge the sorted parts
}

// merge two subarrays arr[i]..arr[m] and arr[m+1]..arr[j] into a single array
// arr[i]..arr[j]
void merge(int &arr, int i, int m, int j)
{
int l = i;                   // left pointer
int r = m+1;                 // right pointer
int k = i;                   // index in the aux array

while((l <= m) && (r <= j))  // fill out the aux array
{
if (arr[l] < arr[r])       // take the minimum of arr[l] and arr[r]
{
aux[k] = arr[l];         // ... and put it into aux
l++;                     // update the left pointer
k++;                     // update the aux pointer
}
else
{
aux[k] = arr[r];
r++;                     // update the right pointer
k++;                     // update the aux pointer
}
}

while (l<=m)                 // put the rest of the left part to aux
{
aux[k] = arr[l];
l++;
k++;
}

while (r<=j)                 // put the rest of the right part to aux
{
aux[k] = arr[r];
r++;
k++;
}

for (k=i; k<=j; k++)  // save the changes in the original array arr
{
arr[k] = aux[k];
}
}

我相信我在 MASM615 中的实现几乎完全复制了这一点。但是,程序在运行时挂起。我测试了 mergeSort 过程,它运行良好。因此,我认为合并过程中存在一些错误。然而,我看了好几遍,发现它是一个精确的副本,据我所知。这是我的书面代码:

TITLE MASM Template                        (main.asm)

INCLUDE Irvine32.inc

.data
info1 BYTE "Array contents before mergeSort procedure:", 0
info2 BYTE "Array contents after mergeSort procedure: ", 0
arr DWORD -9, -64, -57, 81, 24
;, -98, 79, -59, -44, 19
    ;DWORD 52, -60, -51, -63, 23, -22, -37, 13, 88, 36
arrLen DWORD $ - arr
aux DWORD 5 DUP(0)

;variable definitions
a textequ <esi>
i textequ <eax>
j textequ <ebx>
k textequ <edi>
l textequ <ebp>
m textequ <edx>
r textequ <ecx>

.code

main PROC
;output original array
mov edx, OFFSET info1
call WriteString
call Crlf
call Crlf

push arrLen
push OFFSET arr
call printArr
call Crlf
call Crlf
call Crlf

;call mergeSort
mov eax, arrLen
shr eax, 2
dec eax
push eax
push 0
push OFFSET arr
call mergeSort

mov edx, OFFSET info2
call WriteString
call Crlf
call Crlf
push arrLen
push OFFSET arr
call printArr

ProgEnd:
call Crlf
exit
main ENDP

merge PROC USES eax ebx ecx edx esi edi ebp
;take in params. High level code conversion:
;  * i = eax   | * &arr = esi
;  * m = edx   |   k = edi
;    r = ecx   |   l = ebp
;  * j = ebx
;  NOTE: '*' means that the value is passed into the process.

mov a, [esp + 32]
mov i, [esp + 36]
mov m, [esp + 40]
mov j, [esp + 44]

;calculate additional variables: ecx, edi, ebp
mov l, i
mov k, i
mov r, m
inc r

;while loop 1 of 3
While1:
cmp l, m
jg afterWhile1
cmp r, j
jg afterWhile1

;if cond1 && cond2 (need to push pop eax and ebx to compare
;since we are out of general use registers!
push ebx
push eax
mov eax, [a + 4 * l]
mov ebx, [a + 4 * r]
cmp eax, ebx
jge While1_else


;do "if condition success" commands
mov eax, [a + 4 * l]
xchg [aux +  4 * k], eax
inc l
inc k

;restore registers
pop eax
pop ebx

jmp While1

While1_else:
;do "if condition failure" commands
mov eax, [a +  4 * r]
mov [aux + 4 * k], eax
inc r
inc k

;restore registers from above
pop eax
pop ebx

jmp While1

afterWhile1:
;push eax for popping later after BOTH the
;second and third while loop.
push eax

;while loop 2 of 3
While2:

;terminating condition
cmp l, m
jg While3

mov eax, [a + 4 * l]
mov [aux + 4 * k], eax
inc l
inc k
jmp While2

;final While loop
While3:

;terminating condition
cmp r, j
jg afterWhileLoops

mov eax, [a + 4 * r]
mov [aux + 4 * k], eax
inc r
inc k
jmp While3

afterWhileLoops:
;pop eax, since we are done with
;while loops 2 and 3.
pop eax

;set k = i
mov k, i

forLoop1:
;check if k <= j]
cmp k, j
jg endMergeProc

;sacrifice the value of m (edx), since we are
;not using it, nor will need it in the future.
mov m, [aux + 4 * k]
mov [a + 4 * k], m

inc k
jmp forLoop1


endMergeProc:
ret 16
merge ENDP

mergeSort PROC USES eax ebx edx esi
;take in params
mov a, [esp + 20] ;array address
mov i, [esp + 24] ;begin of merge
mov j, [esp + 28] ;end of merge

;return condition: start and end are equal.
cmp i, j
je endMergeSort

;edx = midpoint of eax, ebx
mov m, i
add m, j
shr m, 1

;do recursion part 1.
push m
push i
push a
call mergeSort

;do recursion part 2.
inc m
push j
push m
push a
call mergeSort

;call merge fn (&a, i, m, j)
dec m
push j
push m
push i
push a
call merge

endMergeSort:
ret 12
mergeSort ENDP

printArr PROC USES esi eax ebx ecx
mov esi, [esp + 20] ;array address
mov ecx, [esp + 24] ;array length
xor eax, eax
xor ebx, ebx

printElements:

cmp ebx, ecx
jge endPrintArr

mov eax, [esi + 1 * ebx]
call writeInt
mov al, ' '
call writeChar
add ebx, 4
jmp printElements

endPrintArr:
ret 8
printArr ENDP

END main

请注意,我注释掉了原始数组的一部分。最终长度为 20,但我想让它首先与 5 一起正常工作!;) 我一遍又一遍地查看我的代码,没有看到我的错误。我做错了什么?

编辑:意识到我有时仍在思考高级语言!在更高级别的语言中,您将数组索引增加 1。在汇编中,您需要将索引增加 4,同时考虑到每个元素的大小。这些更改现在反映在上面的代码中,但仍然不起作用!

4

1 回答 1

0

我已经为高级调用“MergeSort(arr, m+1, j);”增加了“m”,但是当我不得不做“Merge(a, i, m, j);”时 我忘记了这个 m 确实是我需要 +1 的值。我现在在第二次调用之前的代码中再次减少了 m,并且修复了它!问题中编写的代码现在是正确的!

于 2013-10-01T20:50:32.633 回答