[汇编版]冒泡排序、快速排序、堆排序

来源:互联网 发布:办公必备软件 编辑:程序博客网 时间:2024/05/19 02:19
[汇编版]冒泡排序、快速排序、堆排序

download2_3代码下载

 

刚刚看完<Intel汇编程序语言设计>一书,用汇编写了几个基本的排序算法。编写的汇编函数代码都是是使用stdcall调用规范的,所以C语言工程也可以链接并调用这些函数的,怎么调用以后在再文章说明。另外,我把程序的不同模块放在不同的源文件中,使代码结构更清晰。和C编译器生成的汇编代码不同的是,为了效率最佳,内存操作最少,我在函数中都没有定义局部变量,大量使用寄存器,刚好算法不是太复杂,寄存器够用,坏处是代码可读性比较差了。程序的编译环境是VS2008,关于如何配制编译环境,可以参看我之前的文章<用Visual Studio 2008编写Win32汇编程序>。算法都是些基本的算法,就不多加说明,只是在程序中加了少许注释。我把几个算法都放在一个工程中,下面是工程中的源文件和简单介绍。

 

Head.inc

BubbleSort.asm

QuickSort.asm

HeapSort.asm

PrintNumber.asm

main.asm

 

包含文件:Head.inc

包含文件类似于C/C++的头文件,我们可以把引用的库函数,或者是其他源文件中定义的函数的声明放在里面。和C语言一样,包含文件中的函数声明告诉编译器,在这个源文件中我们没有这个函数的实现,但是你可以使用它,在Link时可以在其他.obj文件中找到它的实现。(此外,和C语言一样,如果被调用的函数在源代码中的位置调用者之后,也要在调用者上面的位置声明被调用的函数),下面是源代码:

 

ExitProcess PROTO,dwExitCode:DWORD;Windows APIGetStdHandle PROTO, nStdHandle:DWORD;Windows APIWriteConsoleA PROTO,hConsoleOutput:DWORD,;Windows APIlpBuffer:PTR DWORD,nNumberOfCharsToWrite:DWORD,lpNumberOfCharsWritten:PTR DWORD,lpReserved:PTR DWORDPrintNumber PROTO,inputNumber:SDWORDBubbleSort PROTO,pArray:PTR SDWORD,len : SDWORDHeapSort PROTO,pArray : PTR SDWORD,len : SDWORDAdjustHeap PROTO,pArray : PTR SDWORD,len : SDWORD,rootIndex : SDWORDQuickSort PROTO,pArray : PTR SDWORD,len : SDWORDQuickSortRecursion PROTO,pArray:PTR SDWORD,headIndex:SDWORD,tailIndex:SDWORD

 

源文件:BubbleSort.asm

和C语言一样,一个汇编源文件可以不包括入口点函数,而仅包含一些库函数的实现。但你也不能把一个函数定义放里面就完事了,它需要包含完整的格式,包括:TITLE,.386,.MODEL,.stack,.data,.code等部分,当然其中有些字段是可选的,但是必须是一个完整的合法的格式,源文件在末尾以END结尾。和C语言一样,每个源文件都会编译成一个.obj文件,最后所有的.obj文件由Linker生成.exe或者.dll文件。代码如下:

TITLE Bubble Sort.386.MODEL flat,stdcallINCLUDE Head.inc.codeBubbleSort PROC USES eax ebx ecx edx esi edi,pArray:PTR SDWORD,len : SDWORDmov EAX,pArraymov EDX,lensub EDX,2shl EDX,2;EAX=pArray,EDX=LastIndex-1,ESI=i,EDI=jL1:mov ESI,0mov EDI,4L2:mov EBX,[EAX+ESI]mov ECX,[EAX+EDI]cmp EBX,ECXjl L3;exchange two numbersmov [EAX+ESI],ECXmov [EAX+EDI],EBXL3:ADD ESI,4ADD EDI,4CMP ESI,EDXjle L2sub EDX,4cmp EDX,0jge L1retBubbleSort ENDPEND

 

源文件:QuickSort.asm

TITLE Quick Sort.386.MODEL flat,stdcallINCLUDE Head.inc.codeQuickSort PROC USES eax ,pArray:PTR SDWORD,len : SDWORDmov eax,lendec eaxINVOKE QuickSortRecursion,pArray,0,eaxretQuickSort ENDPQuickSortRecursion PROC USES eax ebx ecx esi edi,pArray : PTR SDWORD,headIndex : SDWORD,tailIndex : SDWORDmov EAX,pArraymov ESI,headIndexmov EDI,tailIndexmov EBX,[EAX+4*ESI];ESI = left pointer, EDI = right pointer, EBX= middle number L1:CMP ESI,EDIjge L4L2:cmp ESI,EDIjge L4cmp EBX,[EAX+4*EDI]jg E1dec EDIjmp L2E1:mov ECX,[EAX+4*EDI]mov [EAX+4*ESI],ECXinc ESIL3:cmp ESI,EDIjge L4cmp EBX,[EAX+4*ESI]jl E2inc ESIjmp L3E2:mov ECX,[EAX+4*ESI]mov [EAX+4*EDI],ECXdec EDIjmp L1L4:mov [EAX+4*ESI],EBXdec ESIinc EDIcmp ESI,headIndexjle L5INVOKE QuickSortRecursion,pArray,headIndex,ESIL5:cmp EDI,tailIndexjge END1INVOKE QuickSortRecursion,pArray,EDI,tailIndexEND1:retQuickSortRecursion ENDPEND

 

源文件:HeapSort.asm

TITLE Heap Sort.386.MODEL flat,stdcallINCLUDE Head.inc.codeHeapSort PROC USES eax ebx ecx edx esi edi,pArray : PTR SDWORD,len : SDWORD;build heap.;EAX=(len-2)/2mov EAX,lensub EAX,2shr EAX,1L1:INVOKE AdjustHeap,pArray,len,EAXDEC EAXCMP EAX,0jge L1;EAX=pArray, EBX=len, ECX=LastIndexmov EAX,pArraymov EBX,lenmov ECX,EBXdec ECX;begin to sortL2:cmp EBX,2jl  END1mov ESI,[EAX+4*ECX]mov EDI,[EAX]mov [EAX+4*ECX],EDImov [EAX],ESIdec EBXdec ECXINVOKE AdjustHeap,pArray,EBX,0jmp L2END1:retHeapSort ENDP;----------------------------;AdjustHeap method used to adjust the binary-tree to a heap,;it assume that the initial condition is two sub-tree of the binary-tree are;heap but the root node is not biggest number.;----------------------------AdjustHeap PROC USES eax ebx ecx edx esi edi,pArray : PTR SDWORD,len : SDWORD,rootIndex : SDWORDmov EDX,rootIndexmov EAX,pArray;ESI = left sub-node index, EDI= right sub-node indexL1:mov ESI,EDXshl ESI,1inc ESIcmp ESI,lenjge END1mov EDI,ESIinc EDIcmp EDI,lenjge Exchangemov EBX,[EAX+4*ESI]mov ECX,[EAX+4*EDI]cmp EBX,ECXjge Exchangemov ESI,EDI;ESI=selected sub-node index(used to exchange with father node),;EDI= father node indexExchange:mov EDI,EDXmov EBX,[EAX+4*ESI]mov ECX,[EAX+4*EDI]cmp EBX,ECXjle END1mov [EAX+4*ESI],ECXmov [EAX+4*EDI],EBXmov EDX,ESI jmp L1END1:retAdjustHeap ENDPEND

 

源文件:PrintNumber.asm

该源文件用来在控制台打印数字,在WIN32汇编中,I/O操作不再使用中断,而是调用Windows API,这和C/C++,C#等高级语言是一样的。

TITLE Print Number.386.MODEL flat,stdcallINCLUDE Head.inc.codePrintNumber PROC USES eax ecx edx esi edi,inputNumber:SDWORDLOCALIsNegative:DWORD,outputBuffer[13]:BYTE,handle:DWORD,charWritten:DWORD;Decide if inputNumber is a negative number,;if it is, then IsNegative=1,inputNumber=-inputNumbermov IsNegative,0bt inputNumber,31jnc L1mov IsNegative,1neg inputNumber        L1:  mov EAX,inputNumbermov EDX,0;EDI will be the dividend.mov EDI,10lea ESI,outputBuffer;"line break" is insert at the end of outputBuffermov [ESI+11],BYTE PTR 0Ahmov [ESI+12],BYTE PTR 0Dh;ECX is the current index of outputBuffermov ECX,11;convert inputNumber to chars and store it into outputBuffer.    L2:    div edi    add EDX,'0'    dec ECX    mov [ESI+ECX],DL    mov EDX,0    cmp EAX,0    jnz L2        ;if inputNumber is negative number, insert '-' at front of string    cmp IsNegative,0    jz L3    dec ECX    mov [ESI+ECX],BYTE PTR '-'        ;print the number    L3:    INVOKE GetStdHandle,-11    mov handle,eax    lea EDX,charWritten    ;ESI+ECX is the beginning of printed buffer.    add ESI,ECX    ;len of printed buffer = 13-ECX    sub ECX,13    neg ECX    INVOKE WriteConsoleA,handle,ESI,ECX,EDX,0  retPrintNumber ENDPEND

 

源文件:main.asm(入口点)

TITLE It is Main function.386.MODEL flat,stdcallINCLUDE Head.inc.data  pArray SDWORD -2147483648,100,2147483647,-100,-100,2147483647len SDWORD ($-pArray)/4.codemain PROC USES eax ecx,INVOKE BubbleSort,ADDR pArray,len;INVOKE HeapSort,ADDR pArray,len;INVOKE QuickSort,ADDR pArray,len;Print Numbersmov EAX,OFFSET pArraymov ECX,lenP1:INVOKE PrintNumber,[EAX]ADD EAX,4LOOP P1INVOKE ExitProcess,0main ENDPEND main

 

发现我在文中总是说“和C语言一样”,这是我的一点感触。发现和其他高级语言,比如C#那样抽象程度非常高的语言,C语言和汇编真的很接近,C语言只是汇编的朴素的封装而已,C语言大约只是封装了对通用寄存器的操作,2者生成的.obj文件都是可以相互链接的。

0 0
原创粉丝点击