| 网站首页 | 业界新闻 | 群组 | 交易 | 人才 | 下载频道 | 博客 | 代码贴 | 编程论坛
共有 4849 人关注过本帖, 1 人收藏
标题:大家来写写匯编小玩意(二)
只看楼主 加入收藏
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:204
专家分:1362
注 册:2016-5-15
结帖率:100%
  已结贴   问题点数:20  回复次数:17   
大家来写写匯编小玩意(二)
在别的论坛看见一些有点意思的题目,貼这里让大家练练手。

题目一:
从键盘接收任意字符(长度<=20) ,将其中小写字母以递减方式排序(z......a),
并一次性显示其前后字符,每项资料以空白分隔。
例1:-
输入:12aBb23cD
输出:3cD Bb2 2aB
例2:-
a12z50yw9b8cn34x
2z5 0yw 4x  yw9 cn3 8cn 9b8  a1
另外,因为程序比较简单,希望大家以最短代码完成(不是程式大小),
意即用多少行代码写成。
下面是我用54行完成任务,嗯,应该还有优化的空间。


题目二:
已知BUF1中有N1个从小到大的顺序排列互不相等的字符号数,
BUF2中有N2个从小到大的顺序排列互不相等的字符号数,
编写程序将BUF1和BUF2中的数合并到BUF3中,使在BUF3中存放的数互不相等(意即排除相等),
且从小到大的顺序排列。
程式要求:
1.不能另写排序代码(因已排序),先印出buf1及buf2,再印出buf3,均以十进制显示。
2.以最短代码完成(不是程式大小)。

测试数据:
 buf1 db 3,12,14,15,17,19,22,23,88,99,101,105,106,109,202
 buf2 db 1,3,5,6,10,12,14,18,19,21,22,45,101,103,105,106,109

列印结果:
1 3 5 6 10 12 14 15 17 18 19 21 22 23 45 88 99 101 103 105 106 109 202

下面是我用91行完成任务,应该可以再短些。


有趣兴可以写写,贴出代码,或者说说想法也可以。

[此贴子已经被作者于2016-6-21 20:41编辑过]

附件: 您没有浏览附件的权限,请 登录注册
搜索更多相关主题的帖子: 键盘  空间  资料  字母  
2016-06-20 13:31
wmf2014
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:156
帖 子:1716
专家分:9546
注 册:2014-12-6
  得分:20 
回复 楼主 Valenciax
先就这样吧。交第一题作业,包含5行伪代码共55行,抽空再优化下。
程序代码:
code segment
assume cs:code,ds:code,es:code,ss:code
org 100h
start:    jmp begin
buf    db 80 dup(0)
rmov:    cmp dl,'a'
    jb  mlp3
    cmp dl,'z'
    ja  mlp3
    push si          ;比较大小,找到显示数据插入点,起始位置si,数据顺序是bl bh dl dh,分别位于bx,dx中
    mov cl,dl
mlp1:    cmp cl,[si+2]
    jbe mlp2
    mov di,si
    xor cl,cl        ;找到插入点至di
mlp2:    mov ah,[si]
    add si,4
    cmp ah,'$'
    jnz mlp1         ;判断是否找到字符串结束标志$
    mov cx,si
    sub cx,di
    mov di,si
    sub si,4
    sub cx,3
    std
    rep movsb
    inc si
    cmp dh,13
    jnz mlp4
    mov dh,20h
mlp4:    mov [si],bx
    mov [si+2],dx    ;插入当前显示的数据
    pop si
mlp3:    ret
begin:    mov bx,2020h
    mov dx,bx
    mov si,offset buf
    mov word ptr[si],'$'
blp1:    mov ah,1
    int 21h
    mov bh,dl
    mov dl,dh
    mov dh,al
    call rmov
    cmp al,13
    jz blp2
    cmp al,'$'
    jnz blp1
blp2:    mov dx,si
    mov ah,9
    int 21h
    mov ax,4c00h
    int 21h
code ends
end start


[此贴子已经被作者于2016-6-22 07:39编辑过]


能编个毛线衣吗?
2016-06-21 19:21
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:204
专家分:1362
注 册:2016-5-15
  得分:0 
回复 2楼 wmf2014
灰常感谢wmf2014班竹参与游戏!
题一,我又想到了优化方法,缩减到42行…
今早起床洗脸时,忽然脑海又闪出另一种完全不同的方法,苦哈哈的敲了键盘30分钟,居然才减了区区一行到41行,好象意思不大,但因为是两种方法,回头整理一下再发上来。
2016-06-22 08:09
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:204
专家分:1362
注 册:2016-5-15
  得分:0 
回复 2楼 wmf2014
汇编果然千变万化,班竹的想法是另辟蹊径,也挺巧妙,利用栈操作,看来反倒不像我的一板一眼。

新的42bytes方案由54bytes那个优化的,就直接说说42bytes吧。

这里用最传统的int21h,0Ah函数读入字符串,取了长度后,直接在输入字符串前后补上空白。利用lodsb读入al,其中比较a-z用了这个方法
sub al,'a'  ;减去ascii, a ->0 .... z ->25
cmp al,25 ;比较是否小写a-z内
若读入'a',减去'a',则字符'a'-'z'会转为值0-25,那么比较一次25就限制在a-z内,不用再2次比较。
mov eax,[si-2] ;取输入区4字节
这里利用32bit代码,直接取该字符前一位置之后4字节入EAX
再由输出区
1)
mov ebx,[di]取输出区4字节
若这EBX为空白,则该输出区为空白,直接放入EAX值,另把第4字节置空白
若EBX不为空白,比较cmp ah,bh,这是比较 [小写] 谁大,
若ah大,则新值置入该[输出区],交换EAX和EBX,新的EAX就是原来较小的值
增加输出区地址add di,4,再跳到1)从新和下值比较,如此就相当于泡泡法排序。
编写下来是42行,代码为了压缩空间,用的是比较新式的.MODEL TINY格式,
须用masm 6.x编译,直接转为ex2.com

ML /AT ex2.asm

程序代码:

.MODEL TINY
.386   
.code
ORG 100H
start:    mov dx,offset inputBuf
    mov ax,0c0ah ;清除键盘缓冲,并输入函数
    int 21h
    mov si,offset inputbuf + 2
    xor ecx,ecx
    mov cl,[si-1] ;取输入数
    jcxz quit ;没输入,离开
    mov byte ptr [esi+ecx],20h   ;0d->20h 加空白于后
    mov byte ptr [si-1],20h    ;size->20h ;加空白于前
next:    mov di,offset headbuf + 2
    lodsb    ;取字符
    sub al,'a'  ;减去ascii, a ->0 .... z ->25
    cmp al,25 ;比较是否小写a-z内
    ja next9    ;不是
    mov eax,[si-2] ;取输入区4字节
next1:    mov ebx,[di] ;取输出区4字节
    cmp ebx,20202020h ;是否空白
    jnz next2 ;不是
    stosd ;空白则送到输出区
    mov byte ptr [di-1],20h ;遮罩第4字节成空白
    jmp short next9 ;回圈
next2:    cmp ah,bh ;比较 [该小写] 谁大
    ja next4 ;大于
next3:    add di,4 ;少于则下一个
    jmp short next1
next4:    stosd ;取代输出区项目
    mov byte ptr [di-1],20h ;遮罩第4字节空白
    xchg ebx,eax ;交换二值,eax=原来输出区资料
    jmp short next1 ;再和下一资料比较,即泡泡排序法
next9:    loop next ;回圈 ;  因lodsb 已自动 inc si ;下一输入字节
    mov dx,offset headbuf ;----印结果----
    mov ah,9
     int 21h
quit:    mov ah,4ch ;离开
    int 21h
 headbuf db 0dh,0ah, 4 * 20 dup (20h),'$'
 inputBuf db 21,0,21 dup(0)
end start  ;-----------代码结束---------------


[此贴子已经被作者于2016-6-22 09:38编辑过]

2016-06-22 09:34
wmf2014
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:156
帖 子:1716
专家分:9546
注 册:2014-12-6
  得分:0 
另一种算法,36行代码完成任务(应该还能优化),我没有32位masm:
程序代码:
code segment
assume cs:code,ds:code,es:code,ss:code
org 100h
start:    mov di,offset buf+1
    mov ah,1
slp1:    int 21h
    stosb
    cmp al,0dh
    jnz slp1
    mov byte ptr[di-1],20h
    mov al,'z'
slp5:    mov di,offset buf+1
    mov cx,22
slp4:    repnz scasb
    cmp cx,0
    jz  slp2
    push ax
    push cx
    mov si,di
    sub si,2
    mov cx,4
    mov al,20h
slp3:    int 29h
    lodsb
    loop slp3
    pop cx
    pop ax
    loop slp4
slp2:    dec al
    cmp al,'a'
    jae slp5
    mov ax,4c00h
    int 21h
    buf db 22 dup(20h)
code ends
end start

能编个毛线衣吗?
2016-06-22 13:44
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:204
专家分:1362
注 册:2016-5-15
  得分:0 
回复 5楼 wmf2014
班竹很厉害,写得挺不错的,学习了!
slp4:    repnz scasb
    cmp cx,0
    jz  slp2
这里或者可以优化一下,因为停下来一定是找到或找不到,找到zr或找不到nz
slp4:    repnz scasb
    jnz  slp2

若加入32bit写法
mov si,di
sub si,2
这两句可以归纳一句:
Lea si,[edi-2]


另外题目要求20字节内,这程式却没有限制

[此贴子已经被作者于2016-6-22 14:45编辑过]

2016-06-22 14:18
wmf2014
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:156
帖 子:1716
专家分:9546
注 册:2014-12-6
  得分:0 
回复 6楼 Valenciax
我是做了实验才这样写得,scas不管什么情况只要出了rep都会造成zr标志.限制到20字节大概多2句,另这样写法允许显示$符号。Lea si,[edi-2]不需要32为asm,现在就可实现,少一句。

[此贴子已经被作者于2016-6-22 14:51编辑过]


能编个毛线衣吗?
2016-06-22 14:46
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:204
专家分:1362
注 册:2016-5-15
  得分:0 
回复 7楼 wmf2014
在cx次内,找不到会是nz, 找到是zr , cx的值并不决定找寻结果

附件: 您没有浏览附件的权限,请 登录注册
2016-06-22 15:02
wmf2014
Rank: 18Rank: 18Rank: 18Rank: 18Rank: 18
等 级:贵宾
威 望:156
帖 子:1716
专家分:9546
注 册:2014-12-6
  得分:0 
回复 8楼 Valenciax
看了下第二题,觉得比第一个还容易些,用50句应该能解决。
你的scan指令用错。8088串指令都是针对si和di寻址的,不是dx,我实验结果如下图:
附件: 您没有浏览附件的权限,请 登录注册

能编个毛线衣吗?
2016-06-22 17:03
Valenciax
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:10
帖 子:204
专家分:1362
注 册:2016-5-15
  得分:0 
回复 9楼 wmf2014
呵呵对不起,不是理解错,是di写错了dx
CX不能用来判别找到或找不到是因为有边界条件
若找寻的字符在最后,用cx来判就有问题





[此贴子已经被作者于2016-6-22 17:33编辑过]

附件: 您没有浏览附件的权限,请 登录注册
2016-06-22 17:30







关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.030998 second(s), 8 queries.
Copyright©2004-2018, BCCN.NET, All Rights Reserved