在程序集中实现合并排序

时间:2013-07-31 18:41:50

标签: assembly x86 masm mergesort irvine32

我试图将合并排序算法从更高级别的语言(可能是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,但我希望首先让它正常工作! ;)我一遍又一遍地看着我的代码,看不到我的错误。我做错了什么?

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

1 个答案:

答案 0 :(得分:0)

我增加了&#34; m&#34;相当于高级调用&#34; MergeSort(arr,m + 1,j);&#34;,但是当我必须做&#34;合并(a,i,m,j)时;&#34;我忘记了这个m真的是我需要的价值+1。我现在已经在第二次调用之前在代码中再次减少m,并修复了它!问题中写的代码现在是正确的!