CSU汇编语言课程设计

课程设计源码

环境搭建:

https://blog.csdn.net/weixin_30483697/article/details/97345015

  1. 实现快速排序、堆排序、冒泡排序;

  2. 实现100位整数的相加减;

  3. 从键盘输入一个表示年份的正整数(1~65535),然后判断其是否为闰年。若是,则输出“YES”,否则,输出“NO”。

  4. 汇编实现链表的生成,增加,删除操作。

  5. 汇编实现图的邻接表结构,能生成图,并且根据该图获得其最小生成树。

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值