我正在尝试将合并排序算法从高级语言(可能是 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,同时考虑到每个元素的大小。这些更改现在反映在上面的代码中,但仍然不起作用!