来自于《Intel汇编语言程序设计》(第四版)第九章。
以下为冒泡排序的原文代码:
;---------------------------------------------------------
BubbleSort PROC USES eax ecx esi,
pArray:PTR DWORD, ; pointer to array
Count:DWORD ; array size
;
; Sort an array of 32-bit signed integers in ascending
; order , using the bubble sort algorithm
; Receives : pointer to array,array size
; Returns: nothing
;---------------------------------------------------------
mov ecx,count
dec ecx ; decrement count by 1
L1: push ecx ; save outer loop count
mov esi,pArray ; point to first value
L2: mov eax,[esi] ; get array value
cmp [esi+4],eax ; compare a pair of values
jge L3 ; if [esi] <= [edi] , don't exch
xchg eax,[esi+4] ; exchange the pair
mov [esi],eax
L3: add esi,4 ; move both pointers forward
loop L2 ; inner loop
pop ecx ; retrieve outer loop count
loop L1 ; else repeat outer loop
L4: ret
BubbleSort ENDP
我们知道冒泡排序是一种每次循环都会把此次循环中最大的一个数放到最后的排序算法。最少要执行n-1次外部循环,时间复杂度为O(N*N)。也即排序时间与数组的个数是平方的关系。当少量数组时,可以使用冒泡。而当数组数量十万以上时,排序时间将变得过于漫长。
我们来看一下冒泡的汇编代码:
其实这里使用到了汇编语言对于二维数组的处理,由此涉及到了另外两个概念:
基址变址操作数和相对基址变址操作数。
基址变址操作数将两个寄存器的值相加(称为基址和变址)来产生偏移地址,操作数中可使用任意两个32位通用寄存器。
基址变址操作数很像我们用一维数组来模拟二维数组时的行列索引,这样说的话,应该就很好理解了。例如:
[ row*row_num + col ]
代表第row行第col列的元素。
相对基址变址操作数 在以上的基础上,多了一个偏移地址(displacement),最常见的两种形式为:
[ base + index + displacement ]
displacement [ base + index]
其中的displacement(偏移)可以是变量的名字或者常量表达式。例如:
tableB[ebx+esi]
让我们来看一下冒泡排序的汇编代码:
mov ecx,count ; 将要比较的个数传入ecx
dec ecx ; 减1
L1: push ecx ; 将ecx压入堆栈保存为外部循环计数器
mov esi,pArray ; 将数组首地址传入ESI
L2: mov eax,[esi] ; 得到ESI此时的值,保存到EAX中
cmp [esi+4],eax ; 将EAX此时保存的值与其后面的一个元素比较
jge L3 ; 如果EAX中的值小于下一个元素值,则不需要交换位置,进入L3
xchg eax,[esi+4] ; 否则交换两元素的位置
mov [esi],eax
L3: add esi,4 ; 将内循环的指针移向下一个元素
loop L2 ; 继续执行这次比较(即内循环)
pop ecx ; 一次内循环比较完毕,重新得到ecx的值
loop L1 ; 执行下一次外循环
L4: ret
代码结束。