例10.13 编写一个程序用动态链表存储20,19,……,1,并用遍历链表的方法来显示每个结点的数值。
解:为了便于理解本例程序的执行过程和所构成的动态链表,我们把该链表的构成过程表示成图10.1所示。
|
图10.1 动态链表数据结构示意图 |
||||
| .MODEL SMALL, C | ||||
| .DATA | ||||
|
Head |
DW 0 | ;链表的头指针,初值为空 | ||
|
PT |
DW ? | ;临时链表指针:当前的链表尾 | ||
|
Buff |
DB ?, ?, "$" | ;存放输出结果的缓冲区 | ||
|
CRLF |
DB 0DH, 0AH, "$" | ;回车、换行信息 | ||
| .CODE | ||||
| DispMsg | PROC USES AX DX, Msg:PTR BYTE | ;显示字符串Msg | ||
| …… | ;参见例10.7 | |||
| DispMsg | ENDP | |||
| .STARTUP | ||||
| MOV | CX, 20 | |||
| .REPEAT | ||||
|
MOV |
BX, 1 | ;申请内存的字节数=BX×16 | ||
|
MOV |
AH, 48H | |||
|
INT |
21H | ;申请内存的空间 | ||
|
.BREAK .IF CARRY? |
;申请内存失败 | |||
|
MOV |
ES, AX | ;AX=申请内存的段地址 | ||
|
MOV |
WORD PTR ES:[0], CX | ;给第一个字赋值 | ||
|
MOV |
WORD PTR ES:[2], 0 | ;给第二个字置“空”(NULL) | ||
|
.IF Head==0 |
||||
|
MOV Head, ES |
;保存链表的头指针 | |||
|
.ELSE |
||||
|
PUSH DS |
||||
|
MOV DS, PT |
||||
|
MOV WORD PTR DS:[2], ES |
;把当前申请到的结点链到链表中 | |||
|
POP DS |
||||
|
.ENDIF |
||||
|
MOV |
PT, ES | ;当前结点向后移 | ||
| .UNTILCXZ | ||||
| MOV | BX, Head | ;从头开始遍历链表 | ||
| .WHILE (BX!=0) | ||||
|
MOV |
ES, BX | ;第一个结点的段地址 | ||
|
MOV |
AX, ES:[0] | ;取第一个结点的数据字段值 | ||
|
MOV |
DL, 10 | |||
|
IDIV |
DL | |||
|
ADD |
AX, 3030H | ;把结点的值转换成字符 | ||
|
LEA |
BX, BUFF | |||
|
MOV |
[BX], 2020H | ;把字符缓冲区清空 | ||
|
.IF AL>30H |
;若十位有非零值,则存储其字符 | |||
|
MOV [BX], AL |
||||
|
INC BX |
||||
|
.ENDIF |
||||
|
MOV |
[BX], AH | ;存储个位字符 | ||
|
INVOKE |
DispMsg, ADDR Buff | ;显示结点数据的字符串 | ||
|
INVOKE |
DispMsg, ADDR CRLF | ;显示回车、换行 | ||
|
MOV |
BX, ES:[2] | ;BX=下一个结点的段地址 | ||
|
MOV |
AH, 49H | ;当前结点的段地址已在ES中 | ||
|
INT |
21H | ;释放当前结点所占的空间 | ||
| .ENDW | ||||
| .EXIT 0 | ||||
| END | ||||