基于8086CPU的汇编课程设计,题目:1、快速排序,2、折半查找

最近课设在写汇编课程设计,题目也算是不经意间选了两个,并且两个题目之间也有相似部分,实现的方法也是类似的。

2019夏之汇编课程设计,保证代码,注释都开源。若有错误,欢迎指教。

课本:From 王爽老师

题目:快速排序+折半查找


一、快速排序

快速排序大家对算法都很熟悉,用汇编语言来实现主要是解决字符的输入输出,与有限的寄存器的矛盾。采用栈,缓冲区等方法来保存数据,增大保存信息的容量,不失为一种好方法。对于数据区的定义,存入,取出都是对CPU运作原理的理解与应用。

关于快速排序实现的思想,这篇博客给了我很多启发,Thanks,贴:大佬链接,对快拍的理解很深啊。 

https://blog.csdn.net/man_sion/article/details/70138747

不只是标准思路,选第一个作为标准,一个方向:从前往后找一个 大于标准值的,找到先暂停,另一个方向,从后往前找一个小于标准值的,将这两个数字交换,如此继续,两个坐标相向而行,直到相遇,相遇后讲标准值和相遇点的值交换,从相遇点将数组看成两段,继续做快拍,所以快拍的时间复杂度为 Nlog2(N),每次都是二分的思想,所以是很快的。

但是假如用汇编实现,所需要的寄存器数量比较多,写起来肯定复杂,寄存器交作。所以采用下面这种两头交换法,二分分段的思想,实现,(两头交换法与标准算法思想的差异是,先从左边开始找到大于基准值的那个数,再从右边找到小于基准值的那个数,将两个数交换(这样比基准值小的都在左边,比基准值大的都在右边)。直到数列分成大于基准值和小于基准值的两个区间,以这两个区间进行同样的排序操作。)

汇编Code如下:

assume cs:code,ds:data
data segment
    count dw 10
    buffer db 20H dup(?)    ;  例: 88,9,00,5,7,3,44,2,44,8
                            ; (字节型能保存的最大数值是 0 -- 2^8-1,
                            ;  但是为了简化输入和输出,只考虑了0-99,想做三位数后面的注释有提示 )
    str0 db 0DH,0AH,24H     ;回车,换行,结束
    string db '--please input 10 numbers--',0DH,0AH,'$' ;,0DH,0AH,表示回车换行,'$'表示结束符
    str1   db '--The 10 numbers Out as  --',0DH,0AH,'$' ;,0DH,0AH,表示回车换行,'$'表示结束符
data ends
code segment
start:
    mov ax,data
    mov ds,ax
    call show
    call input
    mov si,offset buffer
    mov di,offset buffer
    mov bx,offset buffer
    add bx,count        ;count 代表数据个个数
    dec bx
    call QSORT
    call display
    mov ah,4CH      ;结束
    int 21H
;-------------------------------------
;show函数
show proc near
    mov dx,offset string
    mov ah,09H
    int 21H
    ret
show endp
;---------------------------------------------------
;input函数
input proc near
    lea dx,buffer
    mov bx,dx
    mov cx,count
AG1:
    mov ah,01   ;处理十位 输入必须是两位数 例0要输入00
    int 21H     ;若是要改三位数,则此处的输入必须是三位数,
                ;然后逐位分离,数值累加到DH上,DH能接受的数值范围是 0-255
    mov ah,10
    sub al,'0'
    mul ah
    mov dh,al

    mov ah,01   ;处理个位
    int 21H
    sub al,'0'
    add dh,al
    mov [bx],dh
    inc bx

    mov ah,01   ;处理空格
    int 21H
    loop AG1
    mov dx,offset str0 ;换行
    mov ah,09H
    int 21H
    ret
input endp
;----------------------------------------------------------------
;函数名:QSORT
;子程序功能:递归快速排序
;入口:DI,BX分别为起始和结束地址
;出口:内存中的数据已排序

QSORT   PROC     NEAR
       PUSH DI
       PUSH BX
       CMP  DI,BX
       JNB NEXT    ;不低于跳转=结束
       PUSH DI
       PUSH BX
       CALL PARTITION
       POP BX
       POP DI
       PUSH BX      ; 因为在下次调用qsort时,需要BX的值不变
       MOV BX,AX
       DEC BX
       PUSH DI
       PUSH BX
       CALL QSORT
       POP BX
       POP DI
       POP BX       ;对应上面的
       MOV DI,AX
       INC DI
       PUSH DI
       PUSH BX
       CALL QSORT
       POP BX
       POP DI
NEXT:
       POP BX
       POP DI
       RET
QSORT   ENDP
;-------------------------------------------------------------
;子程序名:partition
;功能:进行一趟排序,将数据按枢轴分为两段
;入口:DI= &l[low], BX=&h[high]
;出口:返回基准轴位置在AX

PARTITION   PROC     NEAR
        MOV CL,[DI]     ;开始作为基准值
AG:
        CMP DI,BX
        JNB NEXT1       ;不低于跳转
Comeback:
        CMP DI,BX
        JNB ONE
        CMP [BX],CL
        JB  ONE         ;低于跳转
        DEC   BX
        JMP Comeback
ONE:
        MOV CH,[BX]
        MOV AH,[DI]
        MOV [DI],CH
        MOV [BX],AH
Gohead:
        CMP DI,BX
        JNB TWO
        CMP [DI],CL
        JA TWO          ;高于跳转
        INC DI
        JMP Gohead
TWO:
        MOV CH,[BX]
        MOV AH,[DI]
        MOV [DI],CH
        MOV [BX],AH
        JMP AG
NEXT1:
        MOV AX,DI       ;基准轴地址给Ax
        RET
PARTITION   ENDP
;---------------------------------------------------------
;display函数
display proc near
    mov dx,offset str0  ;输出换行
    mov ah,09H
    int 21H
    mov dx,offset str1  ;'--The 10 numbers Out as  --',0DH,0AH,'$'
    mov ah,09H
    int 21H
    mov cx,count
    mov si,offset buffer
AG2:
    XOR AL,AL
    ADD AL,[SI]     ;这个是适用于个位数,十位数要跳转的
    cmp al,10
    JNB d2

d1:                 ;一位数
    ADD AL,'0'
    MOV DL,AL
    INC SI
    MOV AH,02
    INT 21H
    JMP AG3         ;为0即相等跳转
d2:                 ;两位数
    mov ah,0
    mov bl,10
    div bl
    mov dh,ah
    mov dl,al
    add dl,'0'
    MOV AH,02
    INT 21H
    mov dl,dh
    add dl,'0'
    MOV AH,02
    INT 21H
    add si,1
    jmp AG3

AG3:                ;回到循环
    MOV DL,' '
    MOV AH,02
    INT 21H
    LOOP AG2
    ret
display endp

code ends
end start


大部分都会汇编课上学到的指令,还有INT 21H中断的应用。INT 21H中断表在站内已经给出了很好的解释,还有JMP家族。

附带链接:

1:INT 21H中断表 https://blog.csdn.net/iDeal98/article/details/6567837

2:JMP家族表 https://blog.csdn.net/do2jiang/article/details/5262327

1.运行

2.运行解释(强行解释)

输入数据必须为两位数,因为涉及输入格式,处理空格操作,输入10个两位数,并且以空格等一个字符隔开,

回车就是结果,数值大小在(0-99)之间,输出数值的位数,和数值位数对应,输出结果从小往大排序。大部分解释都在代码里面。

感觉差不多了。


二、折半查找

折半查找也是熟悉算法,这里就解释下输入输出过程吧。

输入一个两位数,假如找到就,输出Y(Yes),并且输出数值所在数组的坐标位置。

假如没找到,就输出N(No),肯定不用输出坐标位置了。

然后输出这个数组。

1.汇编Code如下

assume cs:code,ds:data
data segment
    number db  0,1,8,14,22,37,49,50,67,99
    count  dw  10
    str0   db  0dh,0ah,24h
    string db  '--tell one number to find--',0DH,0AH,'$' ;,0DH,0AH,表示回车换行,'$'表示结束符
    str2   db  '-- the array as the down --',0DH,0AH,'$' ;,0DH,0AH,表示回车换行,'$'表示结束符
data ends

code segment
start:
    mov ax,data
    mov ds,ax
    call show
    call input
    call finding  ;找到之后输出坐标要加1
    call display
    mov ah,4cH
    int 21H
;------------------------
;show函数
show proc near
    mov dx,offset string
    mov ah,09H
    int 21H
    ret
show endp
;-----------------------
;input函数
input proc near
    mov ah,01   ;处理十位 输入必须是两位数 例0要输入00
    int 21H
    mov ah,10
    sub al,'0'
    mul ah
    mov dh,al

    mov ah,01   ;处理个位
    int 21H
    sub al,'0'
    add dh,al
    ret
input endp
;---------------------------
;finding函数
finding proc near
    lea bx,number
    mov cx,count
    mov ax,0

F1:
    cmp ax,cx
    jg  NotFind          ;大于跳转

    mov di,ax
    add di,cx
    sar di,1            ;di右移一位 变为一半

    cmp dh,number[bx+di]
    jz  Finded          ;为0跳转
    cmp dh,number[bx+di]
    jb  NextF          ;低于跳转

    add di,1
    mov ax,di
    jmp F1

NextF:
    dec di
    mov cx,di
    jmp F1

NotFind:
    mov dx,offset str0
    mov ah,09h
    int 21H

    mov dl,4eh ;78为N的ASCII码
    jmp Out1

Finded:
    mov dx,offset str0
    mov ah,09h
    int 21H

    mov dl,59h ;89为Y的ASCII码
    mov ah,2
    int 21H
    mov dl,' '
    mov ah,2
    int 21H
    mov cx,di
    mov dl,cl
    cmp dl,09
    jnb Out2      ;不低于跳转
    inc dl
    add dl,'0'
    ;inc dx ;输出的时候进行+1操作 还要判断这个数字是否大于10 >10跳转 Out2 ,<10顺序到Out1

Out1:
    mov ah,2    ;打印输出(找到坐标10以下或者未找到)
    int 21H
    ret
Out2:           ;打印输出(坐标大于10,为两位数)
    mov dl,1
    add dl,'0'
    mov ah,2    ;打印输出
    int 21H
    mov dl,0
    add dl,'0'
    mov ah,2    ;打印输出
    int 21H
    ret
finding endp
;----------------------
;display函数
display proc near
    mov dx,offset str0  ;输出换行
    mov ah,09H
    int 21H
    mov dx,offset str2  ;输出'-- the array as the down --’
    mov ah,09H
    int 21H
    mov cx,count
    mov si,offset number
AG2:
    XOR AL,AL
    ADD AL,[SI]     ;这个是适用于个位数,十位数要跳转的
    cmp al,10
    JNB d2

d1:                 ;一位数
    ADD AL,'0'
    MOV DL,AL
    INC SI
    MOV AH,02
    INT 21H
    JMP AG3         ;为0即相等跳转
d2:                 ;两位数
    mov ah,0
    mov bl,10
    div bl
    mov dh,ah
    mov dl,al
    add dl,'0'
    MOV AH,02
    INT 21H
    mov dl,dh
    add dl,'0'
    MOV AH,02
    INT 21H
    add si,1
    jmp AG3

AG3:                ;回到循环
    MOV DL,' '
    MOV AH,02
    INT 21H
    LOOP AG2
    ret

display endp

code ends
end start

2.运行解释

好吧大部分解释也在前面的叙述,和代码里面了,没有太多值得解释的。题目可能比同学的哈希简单多了。

贴图运行过程

折半查找 1没找到 17  ,2找到 0

好吧,也就这样吧。


三、收获之类的

在汇编里面实现排序算法,算法在数据结构和程序设计中已经学了,很熟悉了,在汇编中的难点就是,面对寄存器少,面对CPU,面对基础指令,实现数据转移,段跳转,子程序跳转。

字符处理:CPU寄存器保存的是  数值,而键盘输入的事ASCII码字符,所以输入输出之间的转换,

输入数值到寄存器中去,输入 ASCII码,保存的是数值,所以减去‘0’(0的ASCII码为 48)保存,

输出之前是数值,输出的事字符。所以加上‘0’,否则输入输出乱码,

多位数要逐位处理,乘法MUL,除法DIV的运用在输入,输出搭建实现。

INT 21H实现输入输出回显,处理空格,以AH为标志位,AL输入回显,DL输出字符,逐位输入,逐位输出。

MOV AH,4CH是 MOV AX,4C00H的有效成份。


四、感谢

感谢周学长(t,tkal),lixuezhang,pengxuezhang……等等不能列举。

发布了38 篇原创文章 · 获赞 27 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Waybyway/article/details/93407913