加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

利用汇编语言实现冒泡排序、直接插入排序、折半查找

(2011-10-25 23:09:00)
标签:

8086汇编

冒泡法

直接插入法

折半查找法

校园

分类: 汇编

利用汇编语言实现冒泡排序、直接插入排序、折半查找。

下面以例题的形式进行讲解。

 

例一:在内存Score缓冲区中存放有100个学生的成绩数据,为无符号字节数。

要求:

1、  用冒泡排序对数据从大到小排序;

2、  直接插入排序对数据从小到大排序;

3、  将最高分和最低分分别放在MINMAX单元中。

 

解:

1)冒泡法

         什么叫冒泡法呢?估计大家已经非常熟悉,在C语言中经常用到。用C语言实现冒泡的代码如下:

         for(int i=0;i<100;i++)

   for(int j=i+1;j<100;j++)

   {

            if(a[i]>a[j])

            {

                      int t=a[i];

                      a[i]=a[j];

                      a[j]=t;

            }

   }

 

那么,用汇编语言怎么来实现呢?其实道理很简单,就是按照C语言的形式将其转换成汇编语言。当然,还有其他的一些操作需要处理,如数据段……

 

下面是汇编语言的冒泡排序:

DSEG     SEGMENT

  SCORE DB  11H,02H,15H,32H,5H,6H,7H,8H,9H,10H,90 DUP(05H)    

       MAX      DB  ?

       MIN       DB  ?

DSEG     ENDS

CSEG      SEGMENT

       ASSUME       DS:DSEG,CS:CSEG

START:   MOV      AX,DSEG

       MOV     DS,AX

;————————————————到这,上面的均是模板

       LEA       BX,SCORE     ;取数组的首地址

       MOV      CX,100   ;控制循环次数

       XOR       SI,SI       ;SI清零

       XOR       DI,DI      ;DI清零

L1:  MOV      AH,[BX+SI]    ;用基变址寻址取操作数, L1为外循环,(SI)为循环变量,

                     ;相当于i

 

L2:  MOV      AL,[BX+DI]    ; L2为内循环,(DI)为循环变量,相当于j

      

       CMP      AH,AL

       JAE         L3         

       MOV      DH,AH          ;AH<Al,交换两个数

       MOV      AH,AL          

       MOV      AL,DH

       MOV      [BX+DI],AL    ;将交换后的数存入存储器

       MOV      [BX+SI],AH    ;这两步很重要

L3:  INC        DI           ;AH>=AL,不需交换,(AH)直接和后一个数比较,相当于j++

       CMP      DI,100    ;判断内层循环是否结束

       JB    L2                 ;没结束,继续循环

 

       ;内层循环结束了

       INC      SI           ;外层变量SI加一,相当于i++

       MOV      DI,SI       ;相当于j=i

       LOOP     L1

 

;通过寄存器实现两个存储器数据间的交换

       MOV      AH,BYTE PTR[BX]              ;基址寻址

       MOV      AL,BYTE PTR[BX+99]

       MOV      MAX,AH

       MOV      MIN,AL

       MOV      AH,4CH         ;返回操作系统

       INT      21H

CSEG      ENDS

END      START

 

要注意的几点:

   数据段使用的DUP相当于C语言中的数组,可以很简便的输入很多数据,即使这些数据都是相同的,但不影响对程序的测试。

   在寄存器间接寻址、基址寻址、变址寻址、基变址寻址中,注意下面:

A、中括号[]中只能是BXSIDI三种寄存器,而不能加入其他的寄存器,如“MOV            AX,[BX+DX]”是错误的;

B、而且[]中也不能同时出现两个变址寄存器SIDI,如“MOV    AX,[SI+DI+3]”是错误的;

C、如果在[]内加入了存储器,如“MOV     AX,[BX+MAX]”,则此时的MAX代表着偏移地址,而不是MAX所对应的数据的值。

   在交换数据时,不仅要交换寄存器中的数据,而且要将存储器中的数据交换过来。

 

 

2)直接插入法

直接插入排序:将一个数据插入到一个已排好序的数据中,主要步骤如下:

   查找应该插入的位置,这个过程免不了要比较数据的大小;

   找到位置后,需将这个位置以及其后的数据都向后移动一位,空出此位置,等待插入

   插入数据。

 

C语言版的代码如下:

for(int i=2;i<=100;i++)

         if(a[i]<a[i-1])              ;找到位置

         {

                   a[0]=a[i];

                   a[i]=a[i-1];

                   for(int j=i-2;a[0]<a[j];j--)

                            a[j+1]=a[j];                 ;向后移

                   a[j+1]=a[0];                ;插入数据

         }

其中a[0]不存放数据,充当转换的中间容器。数据从a[1]a[100]

 

按照上面的代码将其转换成汇编版的插入排序法:

DSEG     SEGMENT

       SCORE   DB  31H,02H,15H,4H,5H,6H,7H,8H,9H,10H,90 DUP(05H)

       MAX      DB  ?

       MIN       DB  ?

DSEG     ENDS

CSEG     SEGMENT

       ASSUME              DS:DSEG,CS:CSEG

START:   MOV      AX,DSEG

       MOV     DS,AX

 

       MOV      CX,99     ;设置循环次数,注意不是100,这主要由程序的写法决定的

L1:  INC       SI           ;  i++

L2:  MOV      AL,[BX+SI]            ; a[i]>(AL)

       MOV      DL,[BX+SI-1]        ; a[i-1]>(DL)

       CMP      AL,DL

       JAE     L1           ;a[i] >=a[i-1]

 

;a[i] < a[i-1]

L3:  MOV      DH,AL           ; a[i]>a[0]

       MOV      AL,DL            ; a[i-1]>a[i],虚假的,只是在寄存器中

       MOV      [BX+SI],AL     ; a[i-1]>a[i],真正的,在内存中

       MOV      DI,SI              ; DI相当于ji>j

       SUB        DI,2               ; j-2>j

       JS    L5          ;这一步很重要,防止数组越界

L4:  MOV      DL,[BX+DI]    ;从内存中取出a[j],给(DL)

       CMP      DH,DL           ;比较a[0]a[j]

       JAE    L5     

 

       ;a[0]<a[j],向后移

       MOV      [BX+DI+1],DL       ;存入内存,实现真正的后移

       DEC       DI                  ;j--

       JMP       L4

L5:  MOV      [BX+DI+1],DH      ;a[0]>=a[j]a[0]>a[j+1],实现直接插入

       LOOP     L1

L6:  MOV      AL,BYTE PTR[BX]

       MOV      AH,BYTE PTR[BX+99]

       MOV      MAX,AH

       MOV      MIN,AL

       MOV      AH,4CH         ;返回操作系统

       INT      21H

CSEG     ENDS

END       START

 

可以看出,上述代码的核心就是C代码的汇编语言翻译。

需注意:

   最后将最大值和最小值分别存入MAXMIN单元中时,不能直接从数组的存储单元存入MAXMIN中,如下面的语句是错误的:

MOV     MIN,BYTE PTR[BX]

MOV     MAX, BYTE PTR[BX+99]

这是编译错误,而不是逻辑错误。因为CPU指令系统的MOV指令要求其两个操作数不能同时为存储器操作数。这是初学者经常会犯的错误。

 

 

下面将介绍折半查找。

例二:在内存Score缓冲区中存放有100个学生的成绩数据,为无符号字节数。设计程序完成如下功能:

根据用户输入的一个2位十进制数,作为查找对象,在该数组中查找,若找到则显示“Y”,若没找到则显示“N”。

 

思路:

输入:MOV    AH,01H

      INT       21H

一次只能输入一个字符,且字符的ASCII码值存放在AL中。要输入两位数,就需要连续输入两个字符并将其转换成十进制数(因为分数是十进制数)。

输出:MOV    AH,02H

      INT       21H

输出的字符需要先存在DL中。

 

 

折半查找:以处于区间中间位置的数据和给定值比较,若相等,则查找成功;若不等,则缩小范围,直到新的区间中间位置的数据等于给定值或查找区间的大小小于零是为止。

首先介绍C语言版的折半查找:

int    search(int key)

{

         low=1;

         high=100;

         while(low<=high)

         {

                   mid=(low+high)/2;

                   if(a[mid]==key) return      mid;

                   else  if(key<a[mid]) high=mid-1;

                   else  low=mid+1;

         }

return       0;

}

 

下面是折半查找的汇编语言版:

DSEG        SEGMENT

         SCORE      DB    1H,2H,3H,4H,5H,6H,7H,8H,90 DUP(12H),13H,14H

DSEG        ENDS

CSEG         SEGMENT

         ASSUME   DS:DSEG,CS:CSEG

START:   MOV         AX,DSEG

         MOV        DS,AX

 

         MOV         AH,1                   ;输入第一个字符

         INT         21H

         MOV         AH,10       ;十进制数

         SUB         AL,'0'

         MUL         AH

         MOV         DH,AL

         MOV         AH,1                   ;输入第二个字符

         INT        21H

         SUB        AL,'0'

         ADD       DH,AL       ;最后的十进制数存放在DH

        

         MOV         AH,1                   ;接收回车符<enter>

         INT         21H

 

         MOV         DL,10        ;输出换行

         MOV         AH,2

         INT         21H

 

         LEA           BX,SCORE                  ;数组的首地址放在BX

         MOV         CL,99        ;max初始值为99

         XOR           Ax,Ax        ;min初始值为0

         XOR          CH,CH      ;清零

L1:   

         CMP        AL,CL        ;注意不能将“JG”写成“JA”,即应该是带符号数比较

         JG     L3     ;否则当你输入“00”时,将不输出结果

 

         MOV         DI,AX        ;实现mid=(max+min)/2

         ADD          DI,CX

         SAR           DI,1

 

         CMP       DH,BYTE PTR[BX+DI]       ;keya[mid]的比较

         JZ     L4     ;找到

         CMP       DH,BYTE PTR[BX+DI]       ;key<mid

         JB     L2

         INC  DI     ;min=mid+1

         MOV         AX,DI

         JMP          L1

 

L2:    DEC          DI     ;max=mid-1

         MOV         CX,DI

         JMP          L1

L3:    MOV         DL,'N'       ;存入DL,以待输出

         JMP       L5

L4:    MOV         DL,'Y'

 

L5:    MOV         AH,2                   ;输出结果

         INT        21H

 

         MOV         AH,4CH    ;返回操作系统

         INT        21H

CSEG         ENDS

         END          START

 

 

注意输入输出格式的控制。

 

 

总结:从以上的程序编辑过程来看,只要能将算法的C语言代码写出来,就能够将相应的汇编程序写出来。当然你可能觉得这是不是有点麻烦——在写汇编程序之前还必须将相应的C语言程序写出来,其实这是编写汇编程序的初级阶段,等你熟悉了汇编以后,只要你知道算法的思想,就能够跳过C代码的编写,直接进入汇编程序的编写。

         其实软件开发中,在进行代码编写之前都需要画流程图、NS流程图等等,所以我们得养成先画流程图再写程序的习惯。

 

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有