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

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

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 API

GetStdHandle PROTO, nStdHandle:DWORD	;Windows API

WriteConsoleA PROTO,hConsoleOutput:DWORD,	;Windows API
					lpBuffer:PTR DWORD,
					nNumberOfCharsToWrite:DWORD,
					lpNumberOfCharsWritten:PTR DWORD,
					lpReserved:PTR DWORD
					
PrintNumber PROTO,	inputNumber:SDWORD	

BubbleSort PROTO,	pArray:PTR SDWORD,
					len : SDWORD
					
HeapSort PROTO,		pArray : PTR SDWORD,
					len : SDWORD

AdjustHeap PROTO,	pArray : PTR SDWORD,
					len : SDWORD,
					rootIndex : SDWORD

					
QuickSort PROTO,		pArray : PTR SDWORD,
					len : SDWORD
						
QuickSortRecursion 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,stdcall
INCLUDE Head.inc
.code
BubbleSort PROC USES eax ebx ecx edx esi edi,
		pArray:PTR SDWORD,
		len : SDWORD
		
	mov EAX,pArray
	mov EDX,len
	sub EDX,2
	shl EDX,2
	
	;EAX=pArray,EDX=LastIndex-1,ESI=i,EDI=j
	L1:
	mov ESI,0
	mov EDI,4
		L2:
		mov EBX,[EAX+ESI]
		mov ECX,[EAX+EDI]
		cmp EBX,ECX
		jl L3
		;exchange two numbers
		mov [EAX+ESI],ECX
		mov [EAX+EDI],EBX
		L3:
		ADD ESI,4
		ADD EDI,4
		CMP ESI,EDX
		jle L2
	sub EDX,4
	cmp EDX,0
	jge L1
		
	ret
BubbleSort ENDP
END

 

源文件:QuickSort.asm

TITLE Quick Sort
.386
.MODEL flat,stdcall
INCLUDE Head.inc
.code
QuickSort PROC USES eax ,
		pArray:PTR SDWORD,
		len : SDWORD
	mov eax,len
	dec eax
	INVOKE QuickSortRecursion,pArray,0,eax
	ret
QuickSort ENDP

QuickSortRecursion PROC USES eax ebx ecx esi edi,
		pArray : PTR SDWORD,
		headIndex : SDWORD,
		tailIndex : SDWORD
		
	mov EAX,pArray		
	mov ESI,headIndex
	mov EDI,tailIndex
	mov EBX,[EAX+4*ESI]
	
	;ESI = left pointer, EDI = right pointer, EBX= middle number 
	L1:
	CMP ESI,EDI
	jge L4
		L2:
		cmp ESI,EDI
		jge L4	
		cmp EBX,[EAX+4*EDI]
		jg E1
		dec EDI
		jmp L2
		E1:
		mov ECX,[EAX+4*EDI]
		mov [EAX+4*ESI],ECX
		inc ESI
		
		L3:
		cmp ESI,EDI
		jge L4
		cmp EBX,[EAX+4*ESI]
		jl E2
		inc ESI
		jmp L3
		E2:
		mov ECX,[EAX+4*ESI]
		mov [EAX+4*EDI],ECX
		dec EDI
	jmp L1
	
	L4:
	mov [EAX+4*ESI],EBX
	dec ESI
	inc EDI
	cmp ESI,headIndex
	jle L5
	INVOKE QuickSortRecursion,pArray,headIndex,ESI
	L5:
	cmp EDI,tailIndex
	jge END1
	INVOKE QuickSortRecursion,pArray,EDI,tailIndex
	END1:
	
	ret
QuickSortRecursion ENDP
END

 

源文件:HeapSort.asm

TITLE Heap Sort
.386
.MODEL flat,stdcall
INCLUDE Head.inc
.code
HeapSort PROC USES eax ebx ecx edx esi edi,
		pArray : PTR SDWORD,
		len : SDWORD		
	
	;build heap.
	;EAX=(len-2)/2
	mov EAX,len
	sub EAX,2
	shr EAX,1	
	L1:
	INVOKE AdjustHeap,pArray,len,EAX
	DEC EAX
	CMP EAX,0
	jge L1
	
	;EAX=pArray, EBX=len, ECX=LastIndex
	mov EAX,pArray
	mov EBX,len
	mov ECX,EBX
	dec ECX
	;begin to sort
	L2:
	cmp EBX,2
	jl  END1
	mov ESI,[EAX+4*ECX]
	mov EDI,[EAX]
	mov [EAX+4*ECX],EDI
	mov [EAX],ESI
	dec EBX
	dec ECX
	INVOKE AdjustHeap,pArray,EBX,0
	jmp L2
			
	END1:			
	ret
HeapSort 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 : SDWORD
			
	mov EDX,rootIndex
	mov EAX,pArray
	;ESI = left sub-node index, EDI= right sub-node index		
	L1:
	mov ESI,EDX
	shl ESI,1
	inc ESI
	cmp ESI,len
	jge END1
	mov EDI,ESI
	inc EDI
	cmp EDI,len
	jge Exchange
	mov EBX,[EAX+4*ESI]
	mov ECX,[EAX+4*EDI]
	cmp EBX,ECX
	jge Exchange
	mov ESI,EDI
		
	;ESI=selected sub-node index(used to exchange with father node),
	;EDI= father node index
	Exchange:
	mov EDI,EDX
	mov EBX,[EAX+4*ESI]
	mov ECX,[EAX+4*EDI]
	cmp EBX,ECX
	jle END1
	mov [EAX+4*ESI],ECX
	mov [EAX+4*EDI],EBX	
	mov EDX,ESI	 
	jmp L1
			
	END1:
	ret
AdjustHeap ENDP
END	

 

源文件:PrintNumber.asm

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

TITLE Print Number
.386
.MODEL flat,stdcall
INCLUDE Head.inc
.code
PrintNumber PROC USES eax ecx edx esi edi,
			inputNumber:SDWORD
	LOCAL	IsNegative:DWORD,
			outputBuffer[13]:BYTE,
			handle:DWORD,
			charWritten:DWORD
	;Decide if inputNumber is a negative number,
	;if it is, then IsNegative=1,inputNumber=-inputNumber
	mov IsNegative,0				
	bt inputNumber,31
	jnc L1
	mov IsNegative,1
	neg inputNumber
    
    L1:  
	mov EAX,inputNumber
	mov EDX,0
	;EDI will be the dividend.
	mov EDI,10
	lea ESI,outputBuffer
	;"line break" is insert at the end of outputBuffer
	mov [ESI+11],BYTE PTR 0Ah
	mov [ESI+12],BYTE PTR 0Dh
	;ECX is the current index of outputBuffer
	mov 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  
ret
PrintNumber ENDP
END

 

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

TITLE It is Main function
.386
.MODEL flat,stdcall

INCLUDE Head.inc

.data  

pArray SDWORD -2147483648,100,2147483647,-100,-100,2147483647
len SDWORD ($-pArray)/4

.code
main PROC USES eax ecx,
	
	INVOKE BubbleSort,ADDR pArray,len
	;INVOKE HeapSort,ADDR pArray,len
	;INVOKE QuickSort,ADDR pArray,len
	
	;Print Numbers
	mov EAX,OFFSET pArray
	mov ECX,len
	P1:
	INVOKE PrintNumber,[EAX]
	ADD EAX,4
	LOOP P1
	
	INVOKE ExitProcess,0
main ENDP
END main

 

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

posted @ 2010-09-28 12:21  Binhua Liu  阅读(5970)  评论(0编辑  收藏  举报