汇编

题目:汇编语言实现排序算法。先划分一块内存区域,存有10000个数据。
① 任选一种排序算法实现将这10000个数据从小到大排序;
② 快速搜索指定的数据,并统计其个数。
解:
对于第一问,简单的实现思路就可以考虑用冒泡排序。
冒泡排序是基于交换排序的思路,通过在无序区中相邻元素关键字的比较和位置的交换,最终达到排序的目的。其C语言实现如下:

for(int i=0;i<10000;i++)
   for(int j=i+1;j<10000;j++)
   {
            if(a[i]<a[j])
            {
                      int t=a[i];
                      a[i]=a[j];
                      a[j]=t;
            }
   }

假设数据段中存放以BUF开始的10000个字节类型的数据,其汇编实现从小到大排序如下:

ASSUME CS:CODE,DS:DATA
DATA SEGMENT
BUF DB 10000 DUP(?);划分内存区域,buf开始的10000个字节类型的数据,则一个存储单元的
;高四位和低四位各存放一个数据
DATA ENDS

CODE SEGMENT
START:
MOV AX,DATA
MOV DS,AX

LEA BX,BUF;取数据区域的首地址
MOV CX,10000;控制循环次数10000
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,10000;判断内存循环是否结束
JB L2;未结束,则继续循环

;内层循环结束
INC SI;外层变量SI加一,相当于i++
MOV DI,SI;相当于j=i
LOOP L1

MOV AX,4C00H;返回操作系统
INT 21H
CODE ENDS
END START

对于第二问,搜索指定的数据,并给出其出现的次数。不考虑效率的前提下,最直观的思路就是遍历该内存区域,找到待查找的数值后再统计其个数。其汇编语言实现如下:

ASSUME CS:CODE,DS:DATA
DATA SEGMENT
BUF DB 10000 DUP(?);假定内存区域中以buf开始的10000个字节类型的数据已经排好序
DATA ENDS

CODE SEGMENT
START:
MOV AX,DATA
MOV DS,AX
;---------------------------------------------
;假定待查找的元素由用户输入,且为一个2位的16进制数据
MOV AH,1;输入第一个字符
INT 21H
MOV AH,16;十六进制数
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 DX,BUF;取数据区域的首地址
MOV AH,10
INT 21H

MOV CL,BUF+1;
XOR CH,CH
LEA SI,BUF+2
XOR DL,DL;DL清零, ;统计个数记录在DL中
AGAIN:
CMP AL,[SI]
JNZ NEXT
INC DL
NEXT:INC SI
LOOP AGAIN
ADD DL,30H
MOV AH,2
INT 21H

MOV AX,4C00H;返回操作系统
INT 21H
CODE ENDS
END START

很明显,该方法的效率比较低的。
如果仅仅是快速搜索数据,用二分查找就可以解决问题,关键问题如何用二分查找的方法统计该数字出现的次数。这里可以考虑用二分查找法进行两次查找,分别确定要查询的数的下标的上届和下届,则其个数等于上届减去下届加1.其C语言实现如下:

int find_lowest(int *a, int l, int r, int key)//a[l...r]
{
   int mid, lowest;
   int isfind = 0; 
   while(l <= r)
   {
     mid = (l+r)/2;
     if (a[mid] == key)
     {
        isfind = 1;
        lowest = mid;//find if there is a lower one
        r = mid - 1;
     }
     else if (a[mid] > key)
     {
       r = mid - 1;
     }
     else
     {
       l = mid + 1;
     }
   }
   if(isfind)
     return lowest;
   else 
     return -1;
}

int find_highest(int *a, int l, int r, int key)
{
	int mid, highest;
	int isfind = 0; 
	while(l <= r)
	{
		mid = (l+r)/2;
		if (a[mid] == key)
		{
			isfind = 1;
			highest = mid;
			l = mid + 1;
		}
		else if (a[mid] > key)
		{
			r = mid - 1;
		}
		else
		{
			l = mid + 1;
		}
	}
	if(isfind)
		return highest;
	else 
		return -1;
}

如果要在数组a中快速查找指定的元素x,令

x1=find_lowest(a, 0, 9999, x), 
x2=find_lowest(a, 0, 9999, x),

则待查找的元素x出现的次数为x2-x1+1.
下面考虑用汇编语言实现二分查找, 实现如下:

ASSUME CS:CODE,DS:DATA
DATA SEGMENT
BUF DB 10000 DUP(?);假定内存区域中以buf开始的10000个字节类型的数据已经排好序
DATA ENDS

CODE SEGMENT
START:
MOV AX,DATA
MOV DS,AX
;---------------------------------------------
;假定待查找的元素由用户输入,且为一个2位的16进制数据
MOV AH,1;输入第一个字符
INT 21H
MOV AH,16;十六进制数
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,BUF;取数据区域的首地址
MOV CL,BYTE PTR[BX+9999] ;基址寻址,CL中存放最大值
MOV AL,BYTE PTR[BX];AL中存放最小值
XOR CH,CH;清零
L1: 
CMP AL,CL;
JG L3;

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

CMP DH,BYTE PTR[BX+DI];key和a[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,N表示不存在该值
JMP L5
L4: MOV DL,'Y';Y表示存在该值
 
L5: MOV AH,2;输出结果
INT 21H

MOV AX,4C00H;返回操作系统
INT 21H
CODE ENDS
END START

以上汇编程序可能部分地方有点小问题,但是大题思路还是对的O(∩_∩)O~呵呵,二分查找的实现待完善

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值