Assembly 在汇编语言中实现合并排序

Assembly 在汇编语言中实现合并排序,assembly,x86,masm,mergesort,irvine32,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 p

我正试图将合并排序算法从更高级的语言(可能是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];
}
}
//对子数组arr[i]…arr[j]进行排序
无效合并排序(int&arr、int i、int j)
{
if(i==j)返回;//终止条件
int m=(i+j)/2;//步骤1:计算分割点
MergeSort(arr,i,m);//步骤2:对左侧部分进行排序
MergeSort(arr,m+1,j);//步骤3:对右侧部分进行排序
合并(a,i,m,j);//步骤4:合并已排序的部分
}
//将两个子阵列arr[i]…arr[m]和arr[m+1]…arr[j]合并为一个阵列
//arr[i]…arr[j]
无效合并(int&arr、int i、int m、int j)
{
int l=i;//左指针
int r=m+1;//右指针
int k=i;//辅助数组中的索引

虽然((lI增加了“m”,相当于高级调用“MergeSort(arr,m+1,j);”,但是当我必须执行“Merge(a,I,m,j);”我忘记了这个m实际上是我需要的+1的值。在第二次调用之前,我在代码中再次减小了m,这就解决了它!问题中编写的代码现在是正确的!

我只是浏览了一下代码;但我不知道您如何在
While2:
之前执行
推送操作在我看来,在
afterWhileLoops
处的
pop
会使堆栈不平衡。的确!让我确保达到了这一点,也许这会解决它。:)我添加了一个新标签“afterWhile1”,并使用它在第一个while循环的终止条件下到达所提到的代码。这一变化可以在我的原始帖子中看到!但是,这显然没有对数组进行排序。运行在:-9、-64、-57、+81、+24…之前和之后得到的当前代码:-2112、-16129、-57、+81、+24。这不仅是顺序,而且是一些值之后的数据不在原始数组中!感谢您发现堆栈不平衡!!!:D在我递增数组索引的方式中出现了一个基本错误,代码在原始帖子中进行了更新,但仍然无法完全工作。看起来,对于DWORD寻址,值被缩放为4与未被缩放之间仍然存在一些不一致4.为了让事情变得更简单,我建议返回到将它们增加1,并且在实际内存访问中只将它们增加4(例如,
moveax,[a+l*4]
)。
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