课程设计源码
环境搭建:
https://blog.csdn.net/weixin_30483697/article/details/97345015
-
实现快速排序、堆排序、冒泡排序;
-
实现100位整数的相加减;
-
从键盘输入一个表示年份的正整数(1~65535),然后判断其是否为闰年。若是,则输出“YES”,否则,输出“NO”。
-
汇编实现链表的生成,增加,删除操作。
-
汇编实现图的邻接表结构,能生成图,并且根据该图获得其最小生成树。
1. 实现快速排序、堆排序、冒泡排序;
快速排序done:
DATAS SEGMENT
COUNT DW 6
DATA DB 6,5,4,3,2,1
DATAS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS
START:
MOV AX,DATAS ;内存数不可以直接装入段寄存器,需要中转一下
MOV DS,AX
MOV SI,OFFSET DATA
MOV DI,OFFSET DATA;di左边界
MOV BX,OFFSET DATA
ADD BX,COUNT
DEC BX ;BX右边界
CALL QSORT
MOV CX,COUNT
CALL SHOW
MOV AH,4CH
INT 21H
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 ;BX--
PUSH DI
PUSH BX
CALL QSORT
POP BX
POP DI
POP BX ;对应上面的
MOV DI,AX
INC DI ;DI++
PUSH DI
PUSH BX
CALL QSORT
POP BX
POP DI
NEXT:
POP BX
POP DI
RET
QSORT ENDP
PARTITION PROC NEAR ;单趟排序把数据按枢轴CL分成两段,DI= &r[low], BX=&r[high],返回枢轴位置AX
MOV CL,[DI]
AG: CMP DI,BX
JNB NEXT
A: CMP DI,BX
JNB ONE
CMP [BX],CL
JB ONE
DEC BX ;BX从高位减一
JMP A
ONE: MOV CH,[BX] ;交换DI,BX
MOV AH,[DI]
MOV [DI],CH
MOV [BX],AH
B: CMP DI,BX
JNB TWO
CMP [DI],CL
JA TWO
INC DI ;ax从低位加一
JMP B
TWO: MOV CH,[BX]
MOV AH,[DI]
MOV [DI],CH
MOV [BX],AH
JMP AG
NEXT:
MOV AX,DI ;枢轴地址给Ax
RET
PARTITION ENDP
SHOW PROC NEAR ;显示排序好的数据,SI是起始地址,cx是输出个数
AG:
XOR AL,AL
ADD AL,[SI]
ADD AL,'0'
MOV DL,AL
INC SI
MOV AH,02
INT 21H
MOV DL,' '
MOV AH,02
INT 21H
LOOP AG
RET
SHOW ENDP
CODES ENDS
END START
堆排序:done
DATA SEGMENT
BUF DB 03H,02H,01H,05H,04H
COUNT EQU $-BUF ;EQU是一条等价伪指令 表示COUNT等价于$-BUF,定义完BUF后存储器单元地址减去BUF地址
DATA ENDS
STACK SEGMENT STACK
DB 200 DUP(0)
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACK
START:MOV AX,DATA
MOV DS,AX
MOV SI,OFFSET BUF ;取BUF偏移地址送SI
MOV CX,COUNT ;设置循环计数器
LOOP1: ;外层循环
CALL LOOP2 ;调用子函数LOOP2进行内层循环,两层循环实现排序
INC SI ;地址指针加1
DEC CX ;计数器减1
JNZ LOOP1
MOV SI,OFFSET BUF
MOV CX,COUNT
LP: CALL OUTPUT ;调用子函数OUTPUT输出排序结果
INC SI
DEC CX
JNZ LP
MOV AH,4CH ;退出
INT 21H
LOOP2 PROC NEAR ;子函数LOOP2
PUSH CX ;CX进栈保护现场
MOV DI,SI ;选择排序,令内外层偏移值相等
MOV AX,DI
SUB AX,OFFSET BUF
MOV DX,COUNT
SUB DX,AX
MOV CX,DX ;调整好计数器的值
AGAIN: ;内层循环
MOV AL,[SI]
MOV BL,[DI]
CMP AL,BL ;选择排序思想,每次将第i小的数放到第i个位置
JA SWAP ;调用交换子函数
JMP CONTINUE
SWAP: MOV AL,[SI] ;交换
XCHG AL,[DI]
XCHG AL,[SI]
JMP CONTINUE
CONTINUE:
INC DI
DEC CX
JNZ AGAIN ;不等于0就继续
POP CX ;CX出栈回复现场
RET
LOOP2 ENDP
OUTPUT PROC NEAR ;输出单个数的子程序
MOV DL,30H ;DL初始值30H,因为数字0的ASCII值为30H
MOV AH,02H
ADD DL,[SI]
INT 21H
RET
OUTPUT ENDP
CODE ENDS
END START
冒泡排序done
SHOWM macro string ; 显示字符串的宏
push ax
lea dx, string
mov ax, 0900h
int 21h
pop ax
endm
DATA SEGMENT
BUFFER DB 20 DUP(0FFH)
;定义数据段,放入20个FFH字节,DPU()相当于malloc(x),用于写入数据
MSG1 DB 13,10,'PUT IN NUMBERS TO SORT:$'
MSG2 DB 13,10,'SORTED NUMBERS:$'
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
;代码段
;设置代码段和数据段的段基地址
START:
MOV AX,DATA
MOV DS,AX
MOV BX,OFFSET BUFFER
MOV DX,0
MOV AX,0
SHOWM MSG1
JMP NEXT
NNUM:;先把当前数字放入内存,然后使BX+2,然后下一个数字的开始(到NEXT)
MOV [BX],DX
ADD BX,2
MOV DX,0
;这里要让AL=0,DX=0,防止NEXT的第一句将数字*10对输入的第一个字符起作用
NEXT:
;输入下一个数字,AH=1键盘输入回显
MOV AH,1
INT 21H
;对输入的数进行判定,看是否是空格或者回车
CMP AL,0DH ;如果是回车符号,则证明输入完了
JZ SORTSTART ;结尾的话跳到SORT部分排序
CMP AL,' '
JZ NNUM ;如果是空格,则证明当前输入完了,将CX里的数字放到存储器中去
;对之前的数字的高位数字调整,压缩BCD
MOV CL,4
SHL DX,CL
;加入这次的个位数
SUB AL,30H ;-30H得到对应的数字
ADD DL,AL
JMP NEXT ;如果不是空格,证明当前元素没输入完,则再次检测输入当前数字的下一位
SORTSTART:
MOV AX,DATA
MOV DS,AX
MOV AX,BX
SHR AX,1 ;内容/2,得到数字个数
MOV CX,AX ;外层循环AX趟
;这里是外层循环
FORI:
PUSH CX ;保存外层循环次数
;注意到外层第1次循环,内循环执行CX-1次,外层第2次循环,内循环执行CX-2次,...控制外循环的cx值恰就是内层循环次数
MOV SI, 0 ;相当于内层循环时取数组内容的指针
;这里是内层循环
FORJ:
MOV AX, [SI] ;(ax)即a[j]
CMP AX, [SI+2] ;a[j]与a[j+1]比较
JBE NEXTNUM ;a[j]<=a[j+1]时 ,跳到下一步NEXTNUM不交换
XCHG AX, [SI+2] ;交换
MOV [SI], AX ;最终效果是a[j]与a[j+1]交换了
;循环控制和转跳部分
NEXTNUM:
ADD SI, 2 ;下一个数,j++
lOOP FORJ ;内层循环,使得CX--,然后再次执行,直到CX=0
POP CX ;恢复外层循环的CX,相当于当前的内层for(j)结束了,执行外层的fori
lOOP FORI ;外层循环
;最后显示
OUT_ALL:
;为了保证最后一个数字的正确录入,要求手动输入最后一个数字之后,先' '后'回车'
MOV DL,13 ;回车 结尾
MOV AH,2
INT 21H
SHOWM MSG2
MOV DL,10 ;换行
MOV AH,2
INT 21H ;AH=2 单独显示DL的内容
MOV BYTE PTR [BX],'$';结尾加上结尾符号标志
MOV CX,BX
MOV SI,0
SHOW:
MOV DL,32 ;空格 用于显示下一个数字
MOV AH,2
INT 21H
MOV BX,[SI]
ADD SI,2 ;指向下一个字节的内容
CMP BL,'$'
JZ EXIT ;设置出口
MOV CL,4 ;CL是用在下面的SHL部分
MOV CH,4 ;用于内层循环
;单独处理每两个字节的四位数字显示
BYTE1:
MOV DX,BX
AND DX,0F000H ;仅保留最高四位
SHR DH,CL ;挪到DH的低四位
MOV DL,DH
ADD DL,30H ;DL存放的恰好是所需要的ASCII码
MOV AH,2
INT 21H
SHL BX,CL ;将BX左移4位,把最高位让给下个字符
DEC CH
CMP CH,0
JNZ BYTE1 ;内层循环
JMP SHOW
EXIT:
MOV AH,4CH
INT 21H
CODE ENDS
END START
2. 大数加减done
DATA SEGMENT
MSG1 DB "Input The First Number:",0DH,0AH,"$"
MSG2 DB "Input The Second Number:",0DH,0AH,"$"
REM DB "The Reslut Is:$"
N1_LEN DW 0
NUM1 DB 100 DUP(0)
N2_LEN DW 0
NUM2 DB 100 DUP(0)
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
;----------------------
MAIN PROC FAR ;主程序
MOV DX,DATA
MOV DS,DX
LEA DX,MSG1
MOV AH,09
INT 21H ;显示第一句提示语
LEA BX,NUM1 ;输入第一个数
CALL INPUT
CALL CRLF
LEA DX,MSG2
MOV AH,09
INT 21H ;显示第二句提示语
LEA BX,NUM2 ;输入第二个数
CALL INPUT
CALL ADDER ;调用加法函数
CALL CRLF
LEA DX,REM
MOV AH,09
INT 21H ;显示结果提示语
LEA BX,NUM1
CALL SHOW
CALL CRLF
EXIT:
MOV AH,4CH
INT 21H
RET
MAIN ENDP
;------------------------
CRLF PROC NEAR ;回车换行
MOV DL,0DH
MOV AH,2
INT 21H
MOV DL,0AH
MOV AH,2
INT 21H
RET
CRLF ENDP
;-----------------------
INPUT PROC NEAR ;bx:数组首地址,第一个元素方长度
PUSH DS
PUSH AX
PUSH DX
XOR SI,SI ;SI清零
INC SI
NEXT:
CMP SI,100
JE OVER ;等于转移,不能超过100位
MOV AH,01
INT 21H
CMP AL," " ;空格结束
JE OVER
CMP AL,0DH ;回车结束
JE OVER
CMP AL,"0" ;忽略其他不是0-9的字符
JB NEXT ;小于转移
CMP AL,"9"
JA NEXT ;大于跳转
SUB AL,30H ;转换为十进制
MOV [BX+SI],AL;将数据输入数组中
INC SI
JMP NEXT
OVER:
DEC SI
MOV WORD PTR [BX-1],SI ;保存长度
POP DX
POP AX
POP DS
RET
INPUT ENDP
;-------------------------
SHOW PROC NEAR
PUSH DS
PUSH AX
PUSH DX
MOV CX,[BX-1] ;数组长度,BX:数组首地址
XOR SI,SI
INC SI
NEXTSHOW:
MOV AH,02
MOV DL,BYTE PTR [BX+SI]
ADD DL,30H ;转换为ASCII码
INT 21H
INC SI
LOOP NEXTSHOW
POP DX
POP AX
POP DS
RET
SHOW ENDP
;----------------------
ADDER PROC NEAR ;NUM1,NUM2分别是数组的首地址,结果放到NUM1数组中,进位CF
PUSH DS
PUSH AX
PUSH DX
MOV SI,WORD PTR [NUM1-1] ;SI存放BX的长度
MOV CX,SI
MOV DI,WORD PTR [NUM2-1] ;DI存放BP的长度
XOR DL,DL ;DL清零
CMP CX,DI
MOV WORD PTR [NUM1-1],CX
JAE CONTINUE ;CX存放两个数组中较大一个的长度
MOV CX,WORD PTR [NUM2-1]
MOV WORD PTR [NUM1-1],CX ;修改结果的长度
CONTINUE:
MOV AL,DL
XOR DL,DL
CMP SI,0
JE LA ;等于转移,加数已经加完
ADD AL,[NUM1+SI]
DEC SI
JMP LB
LA:
ADD AL,0
LB:
CMP DI,0
JE LC
ADD AL,BYTE PTR [NUM2+DI]
DEC DI
AAA
ADC DL,0 ;将进位标志值1加入到DX
JMP LD
LC:
ADD AL,0
AAA
ADC DL,0
LD:
MOV BX,CX
MOV [NUM1+BX],AL
LOOP CONTINUE
POP DX
POP AX
POP DS
RET
ADDER ENDP
CODE ENDS
END MAIN
3. 判断闰年done
DATA SEGMENT
MSG1 DB 13,10,'Please Input the Year:$'
VAR1 DB 13,10,'YES!','$'
VAR2 DB 13,10,'NO!','$'
MSG2 DB 13,10,'Input Error!$'
x DW ? ;年份:0~65535
B DW 4
G DW 400
F DW 100
DATA ENDS
;----------------------------
CODE SEGMENT
ASSUME CS: CODE, DS: DATA
START:
MOV AX, DATA
MOV DS, AX
MOV DX, OFFSET MSG1 ;提示 Please Input :
MOV AH, 9
INT 21H
IN_LOOP:
MOV x, 0 ;数据清零.
MOV CX, 4 ;输入4位
_INX:
PUSH CX
MOV AH, 1 ;输入单个字符.
INT 21H
CMP AL, '0'
JB _IN_ERR ;小于'0',不是数字.
CMP AL, 3AH
JB SUB_30H ;'0'~'9'.
_IN_ERR:
MOV DX, OFFSET MSG2 ;提示 Input ERROR.
MOV AH, 9
INT 21H
JMP EXIT
SUB_30H:
SUB AL,'0';得到偏移量
MOV AH,0
MOV CX,AX;cx存偏移量
MOV AX,x
MOV BX,10
MUL BX ;每输入一个数左移,相当于乘10
ADD AX,CX;ADD NEW DATA
MOV x,AX;SAVE
POP CX;BACK TO CX
LOOP _INX
MOV AX,x
CWD;TO 32 BITS
DIV B; DIV 4
CMP DX,0
JNZ L1;NOT 0 THEN NOT LEAP YEAR
;-------------------------------
MOV AX,x
CWD
DIV G; DIV 400
CMP DX,0
JZ L2; IS 0 THEN IS LEAP YEAR
;-----------------------------------------
MOV AX,x
CWD
DIV F;DIV 100
CMP DX,0
JNZ L2;IS NOT 0 THEN IS LEAP YEAR
L1:
MOV DX,OFFSET VAR2; SHOW VAR2 NOT LEAP
JMP _O_STR
L2:
MOV DX,OFFSET VAR1;SHOW VAR1 IS LEAP YEAR
_O_STR:
MOV AH,09H
INT 21H
EXIT:
MOV AH,4CH
INT 21H
CODE ENDS
END START
4. 链表done
assume cs:code
;如何实现动态分配空间
name1 segment
dw 128 dup(0) ;name1:0为头结点,,,,0存放值,1存放下一个段的段地址
name1 ends
data segment
dw 15,58,4,28,77,14,29,7012,45,16,17
dw 11,22,33,44,55 ;要插入的数据
dw 7,5,6,2,4 ;插入后的结点位置,首节点位置为1
dw 1,8,9,6 ;删除的结点位置,首结点位置为1
divisors dw 10000,1000,100,10,1 ;用于将数字的每个位分开变成相应的字符串
results db 0,0,0,0,0,0,0,'$' ;用来显示数据,最后2个0选择换行和空格
data ends
stack segment
dw 0,0,0,0,0,0,0,0 ;栈用来临时保存数据
stack ends
code segment
start:
mov ax,data
mov ds,ax ;ds存放数据源的段地址
mov ax,name1
mov es,ax ;es存放存放目的数据的段地址
mov ax,stack
mov ss,ax
mov sp,10h ;利用栈来临时保存数据
mov cx,11 ;cx决定插入的数据个数
mov bx,0 ;bx决定了存放值的偏移地址
mov di,0 ;di决定存放数据源的偏移地址
mov word ptr es:[bx+2],4 ;定义头结点,头结点指向的偏移地址为4
mov bx,4
call install ;调用初始化函数
push bx ;bx结果为44,保存
mov bx,0
mov bx,es:[bx+2] ;找到开始的头结点指向的首结点
call show ;显示初始化后的数据
pop si ;si决定插入数据存放的内存单元地址
mov cx,5 ;插入的数据量
mov di,22 ;指向要插入数据的首地址
call insert ;向指定地方插入数据
mov bx,0
mov bx,es:[bx+2] ;找出第一个结点
call show ;显示链表
mov cx,4 ;删除的数据量
mov bx,0
mov di,42 ;指向删除的结点首地址
call delete ;删除指定结点
mov bx,0
mov bx,es:[bx+2]
call show ;显示链表
mov ax,4c00H
int 21H
;----------------------链表初始化---------------------
install:
mov ax,[di]
mov es:[bx],ax ;bx为4,8,12
cmp cx,1
jna judge ;比较cx是否为1,为1则跳转到judge处
push bx
add bx,4 ;存储数据的内存单元向后移4个字节
mov ax,bx ;用ax来保存bx
pop bx ;临时保存一下bx
mov es:[bx+2],ax
return:
add bx,4
add di,2 ;bx和di转换成一下个段的数值
loop install
ret
judge: mov word ptr es:[bx+2],0 ;将最后一个结点指向的下一个结点为0
jmp short return
;初始化后bx=44, bx+4
;--------------------插入链表:插入在两个结点之间---------------
insert: ;完成插入
mov bx,0 ;bx表示头结点的段地址
push cx
mov ax,[di+10] ;找到插入的位置,di=20,di+10指明插入后结点的位置
mov cx,ax ;cx控制寻找结点的次数
sub cx,1
cmp cx,0
je insertnode ;当cx为0时,头结点就是bx为0
call searchnode ;bx保存了前一个结点
insertnode: ;寻找插入位置的前一个结点
mov ax,[di] ;获得插入的数据值
mov es:[si],ax ;es:[si]存放要插入的值,si为最后保存的bx地址
push es:[bx+2] ;暂存原来下一个结点
mov es:[bx+2],si ;前一个结点指向要插入的结点位置
pop ax ;ax接收原来储存的下一个结点
mov es:[si+2],ax ;es:[si+2]存放下一个结点
add di,2 ;数据源位置定位
add si,4 ;存放插入数据的内存单元加4
pop cx
loop insert
ret
searchnode: ;返回bx为前一个结点
mov ax,es:[bx+2] ;ax为下一个结点的位置
mov bx,ax ;比如当cx=1时,bx为4
loop searchnode
ret
;*****************************删除数据**************************
delete: ;删除结点
mov bx,0 ;找到头结点
push cx
mov ax,[di] ;ax为相应删除的结点位置
mov cx,ax
sub cx,1
cmp cx,0 ;cx为0时显示的就是bx为0的结点
je deletenode
call searchnode ;得到前一个结点
deletenode: ;删除结点的具体过程
mov dx,bx
mov bx,es:[bx+2] ;删除结点的首地址
mov ax,es:[bx+2] ;下一个结点的首地址
mov bx,dx
mov es:[bx+2],ax ;前一个结点指向下一个结点
add di,2 ;找到下一个要删除的结点
pop cx
loop delete ;循环删除
ret
;*************************显示数据*******************************
show:
mov si,offset divisors ;对应除数的偏移地址
mov di,offset results ;对应显示内容ds:dx的偏移地址
mov cx,7 ;5个因为字节表示的范围是5位数,第6个表示空格,第7个表示换行
mov ax,es:[bx] ;显示的循环次数为最后的条件
;cal处理一个数据
fenkai: ;进行5次除法把数转换成单独的字符,如650,0,0转换成6,5,0,0,0
cmp cx,2 ;用来选择是否输出空格
je kongge
mov dx,0 ;div指令的高16位dx
div word ptr [si] ;除以6000,结果商放在ax,dx存放余数
add al,30H ;转换成相应的字符串
mov byte ptr [di],al
inc di
add si,2
mov ax,dx ;余数给ax
loop fenkai
kongge: ;将六个字符设为空格的ASCII码
mov byte ptr [di],32
mov bx,es:[bx+2] ;bx是下一个结点的偏移地址
inc di ;di指向第6个字符
cmp bx,0 ;当bx为0时决定将第7个字符设置为换行符,否则设置为空格
je huanhang
mov byte ptr [di],32 ;最后字符选择空格
jmp short ready
huanhang: ;输出换行
mov byte ptr [di],10 ;最后选择输出结束则换行
ready: mov cx,4 ;决定ds:dx输出的内容是否带省略不需要的0
mov di,offset results
jmpzero: cmp byte ptr [di],'0' ;跳过省略的0
jne print
inc di
loop jmpzero
print: ;进行输出
mov dx,di
mov ah,9 ;当ah=9时,
int 21h ;int 21h表示将ds:dx内容输出
cmp bx,0 ;bx重定位和选择是否结束
je ok ;结束循环
jmp short show
ok:ret
code ends
end start
5. 最小生成树done
assume cs:code, ds:data, ss:stack
SHOW macro string ; 显示字符串的宏
push ax
lea dx, string
mov ax, 0900h
int 21h
pop ax
endm
CLS macro ; 清屏的宏
push ax
mov ax, 0003h
int 10h
pop ax
endm
NODE struc ; 结构体
score dw 0
link dw 3 dup (0)
weight dw 3 dup (0)
NODE ends
data segment ; 数据段
la NODE 20 dup(<>) ; 结构体数组
count dw 128 dup(0) ; 边的权值段
edge dw 128 dup(0) ; 边段
str_list dw 128 dup ('$')
closed dw 128 dup (0) ; closed表,里面存放已经扩展了的节点
leng dw 0 ; 输入的数据的长度
lengEdge dw 0 ; 存在的边的长度
number dw 0 ; 字符串转数字后存储位置
factor dw 10 ; 除数,在数字与字符串相互转换的时候使用
keybuf db 20
db ?
db 20 dup(?) ; 数据缓冲区
input_value db 0dh, 0ah, 'Please Input the value: ', '$'
after_node db 0dh, 0ah, 'Please Input the after node : ', '$'
input_weight db 0dh, 0ah, 'Please Input the weight: ', '$'
how_many_node db 0dh, 0ah, 'Please Input the number of nodes: ', '$'
how_many_link db 0dh, 0ah, 'Please Input the number of links: ', '$'
tree db 0dh, 0ah, 'The tree is: ', '$'
str_Full db 0dh, 0ah, 'The Nodes is full!!(Any key returns to the main menu)', 0dh, 0ah, '$'
data ends
stack segment stack
dw 256 dup(0)
stack ends
code segment
start:
mov ax, data
mov ds, ax
mov ax, stack
mov ss, ax
CLS
call AddNode
call ChangeEdge
call ChangeWeight
call MinimumSpanningTree
call ShowString
CLS
SHOW tree
SHOW str_list
mov ax, 4c00h
int 21h
; 添加节点
AddNode:
push ax
push bx
push cx
push si
SHOW how_many_node
call InputString ; 调用输入字符串的函数
call StrtoNum ; 将输入的字符串转换为数字,存放在number
mov cx, number ; cx中存放需要的节点个数
mov bx, 0 ; bx为数组下标
addanode:
SHOW input_value
call InputString
call StrtoNum
add leng, 1
mov ax, number
mov word ptr la[bx].score, ax ; 存放score
push cx
SHOW how_many_link
call InputString
call StrtoNum
mov cx, number ; 存放link的个数
cmp cx, 0 ; 如果没有link,直接跳过
je zero
mov si, 0 ; si为数组中link段的下标
addalink:
SHOW after_node
call InputString
call StrtoNum
mov ax, number
mov word ptr la[bx].link[si], ax ; 存放link
SHOW input_weight
call InputString
call StrtoNum
mov ax, number
mov word ptr la[bx].weight[si], ax ; 存放weight
add lengEdge, 1
add si, 2 ; link下标加2,指向下一个字
loop addalink ; 循环
zero:
add bx, 14 ; 指向下一个结构体数组元素
pop cx
loop addanode
pop si
pop cx
pop bx
pop ax
ret
; 将字符串转换位数字
StrtoNum:
push ax
push bx
push cx
push dx
mov word ptr number[0], 0 ; 先将number里面的数字清零
; call len_y
mov bl, keybuf[1] ; 将缓冲区的字符串长度存入bl
xor bh, bh ; 将bh清零
mov cx, bx ; cx中存放循环次数
mov ax, 1 ; 将权重1存入ax
convertNum:
push ax ; 暂存ax里面的值
mov dl, keybuf[bx+1] ; 将最后一个字符存入dl中
sub dl, 30h ; 将dl中存放的字符转换为数字
mov dh, 0
mul dx ; 获得数字
add number[0], ax ; 存入number里面
dec bx ; 下一个
pop ax ; 去除ax里面的值
mul factor ; ax中的权重值乘以10
loop convertNum ; 循环
pop dx
pop cx
pop bx
pop ax
ret
; 输入函数
InputString:
push ax
push dx
mov dx, offset keybuf
mov ax, 0a00h
int 21h
pop dx
pop ax
ret
; 最小生成树
MinimumSpanningTree:
push ax
push bx
push cx
push dx
push di
push si
; 寻找最小的边,将其加入closed表,第一次不需要检测是否已经重复
call FindSmallestWeight ; 寻找到最小的下标,这条边的权值已经被置为999
mov di, 0 ; closed表的下标
add si, si ; 定位edge的下标
mov ax, edge[si] ; 得到边的起始节点
mov closed[di], ax ; 加入closed表
add di, 2 ; closed表的下标加2
mov ax, edge[si+2] ; 得到边的末尾节点
mov closed[di], ax ; 加入closed表
add di, 2 ; closed表的下标加2
mov cx, leng ; cx存储要剩下要加入的边的个数
sub cx, 2
FindSpanningTree:
call FindSmallestWeight ; 寻找到最小的下标,这条边的权值已经被置为999
add si, si ; 定位edge的下标
; 判断两条边是否都在closed表中,只要有一条边不在就可以加入
mov ax, edge[si] ; 得到边的起始节点
mov bx, 0 ; bx作为定位closed表的小标
ClosedCmp: ; closed表里面的比较,找这一边的第一个节点
mov dx, closed[bx] ; 从closed表里面取出内容
cmp dx, 0 ; 如果内容为0的话就说明已经到达closed表的末尾
je join ; 说明没有重复的,就可以加入closed表
cmp dx, ax ; 比较closed表中的和edge
je NextCmp ; 如果相等则跳转到下一次比较
add bx, 2 ; 跳转到closed表中的下一个元素
jmp ClosedCmp ; 继续比较,要不然dx为0说明没有相同的,要不然就是相同的跳转到下一次比较
NextCmp: ;找这一边的第二个结点
mov bx, 0 ; 先将closed表的下标清零,这一次又开始循环重新比较
mov ax, edge[si+2] ; ax中存储边的下一个顶点
NextCmp1: ; 第二次比较
mov dx, closed[bx] ; 从closed表里面取出内容
cmp dx, 0 ; 如果内容为0的话就说明已经到达closed表的末尾
je join ; 说明没有重复的,就可以加入closed表
cmp dx, ax ; 比较closed表中的和edge
je Same ; 如果再次相等则不加入这一条边
add bx, 2 ; 跳转到closed表中的下一个元素
jmp NextCmp1 ; 继续比较,要不然dx为0说明没有相同的,要不然就是相同的跳转到下一次比较
Same: ; 两节点都相同,都重复的话就不需要加边了
jmp over
join:
mov ax, edge[si] ; 得到起始节点
mov closed[di], ax ; 加边
add di, 2
mov ax, edge[si+2] ; 得到末尾节点
mov closed[di], ax ; 加边
add di, 2
dec cx ; 加入一条边后边计数减去1
cmp cx, 0 ; 看看边计数是否为0
je Finally ; 为0的话就说明已经加入了足够多的边
over:
jmp FindSpanningTree ; 再次加边
Finally:
pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret
; 寻找最小的权重
; Output: si中存储了最小的权值所在的位置,并将这个权值设为了999占位符
FindSmallestWeight:
push ax
push cx
push di
mov di, 0
mov si, 0 ; si指向最小权值所在的位置
mov cx, lengEdge
dec cx
mov ax, count[di] ; 初始权重
add di, 2
FindCompare:
cmp ax, count[di] ; 比较ax与当前权重
jb NoSwap ; 如果ax小于的话就不将权重值交换
mov ax, count[di] ; 交换权重值
mov si, di
NoSwap:
add di, 2
loop FindCompare ; 找到了最小权值
mov count[si], 999 ; 用一个很大的数字占位
pop di
pop cx
pop ax
; 边修改
ChangeEdge:
push ax
push bx
push cx
push di
push si
; 将存储结构修改
mov cx, leng ; 循环次数
mov bx, 0 ; bx遍历数组
mov si, 0 ; si遍历link
mov di, 0 ; di遍历edge
change:
; 边的结构修改
addedge:
mov ax, la[bx].link[si] ; 尾
cmp ax, 0 ; 尾不为0的话,才加入一条边
je next
mov ax, la[bx].score
mov edge[di], ax ; 加入头
add di, 2
mov ax, la[bx].link[si]
mov edge[di], ax ; 加入尾
add si, 2
add di, 2
jmp addedge
next:
mov si, 0
add bx, 14
loop change
pop si
pop di
pop cx
pop bx
pop ax
ret
; 权重的结构修改
ChangeWeight:
push ax
push bx
push cx
push di
push si
mov cx, leng ; 循环次数
mov bx, 0 ; bx遍历数组
mov si, 0 ; si遍历weight
mov di, 0 ; di遍历count
change2:
addWeight:
mov ax, la[bx].weight[si] ; 权重
cmp ax, 0 ; 权重不为0的话,才加入一条边
je next1
mov ax, la[bx].weight[si]
mov count[di], ax ; 加入权重
add si, 2
add di, 2
jmp addWeight
next1:
mov si, 0
add bx, 14
loop change2
pop si
pop di
pop cx
pop bx
pop ax
ret
; function: 将数字转换为字符串
; input: ax--the number bx--the first empty place of string
; output: bx--after the last place of string
NumtoStr:
push dx
push cx
mov cx, 0 ; cx中存放得到的字符串长度
div1:
mov dx, 0 ; 进行32位数除法
div factor ; 除以10
add dx, 30h ; DX中存放余数,将余数转换为字符串
push dx ; 将字符串存入栈中
inc cx ; 得到的字符串长度加1
cmp ax, 0 ; 如果得到的商为0的话就说明除法已经结束了,退出循环
jnz div1
whileN2:
pop dx ; 从栈中取出字符串
mov byte ptr str_list[bx], dl ; 将字符串存入str_list中
inc bx ; 存的位置加1
loop whileN2 ; 采用循环的方式,因为cx总存放了字符串的长度
pop cx
pop dx
ret
; 将结果以字符串的形式展现出来
ShowString:
push ax
push bx
push cx
push di
mov cx, lengEdge
dec cx
add cx, cx ; cx中存放边的顶点的个数
mov di, 0
mov bx, 0
convert:
mov ax, closed[di]
call NumtoStr
; 加入分隔符号
mov str_list[bx], ' '
inc bx
mov str_list[bx], '-'
inc bx
mov str_list[bx], '>'
inc bx
mov str_list[bx], ' '
inc bx
add di, 2
loop convert
; 结尾符号
mov str_list[bx], 'E'
inc bx
mov str_list[bx], 'N'
inc bx
mov str_list[bx], 'D'
inc bx
mov str_list[bx], ' '
inc bx
pop di
pop cx
pop bx
pop ax
ret
code ends
end start