【问题标题】:Display Binary Tree Recursively递归显示二叉树
【发布时间】:2019-08-15 05:37:18
【问题描述】:

我的代码可以在 16 位汇编器中正确地将节点添加到树中。我可以毫无问题地显示任意数量的左树。每次我试图让正确的孩子打印它时,系统都会崩溃。我试图查看 turbo 调试器中发生了什么,并假设我没有正确保存或弹出堆栈。

我通过 turbo 调试器运行此代码的次数超出了我的记忆,并且无法查看问题出在哪里。

.MODEL small
.STACK 100h

.DATA
menuchoice DB 10, 10, 13, 'Please enter your choice from the menu. $'

message DB 10, 10, 13, 'Please enter the character you would like to add (enter # to exit): $'

menu    DB 10, 10, 13, 'Binary Search Tree Menu'
        DB 10, 10, 13, '1 - Add a character to the tree'
        DB 10, 10, 13, '2 - Search the tree for a character'
        DB 10, 10, 13, '3 - Display the contents of the tree'
        DB 10, 10, 13, '4 - Exit the program $'

empty   DB 10, 10, 13, '     The tree is empty. $'

crlf    DB 10, 13, '     $'

bintree DB 60 DUP(0) ; create a list with a size of 20 characters

node    DB 0 ; node starts at zero become 1 once value is added
root    DB 1 ; next available slot
next    DB 1 ; next is the pointer to the next slot for the character


.CODE
tree PROC
     ; first two lines in main in all assembler 
       mov ax, @data
       mov ds, ax

DISPLAYMENU: ; set up my label

     ; display menu
       mov dx, OFFSET menu
       mov ah, 09h
       int 21h

     ; display menu choice prompt
       mov dx, OFFSET menuchoice
       mov ah, 09h
       int 21h

     ; get the character from the keyboard with echo
       mov ah, 01h
       int 21h

MAINLOOP: ; set up my label

     ; compare data entry to 4 to exit program
       cmp al, 34h
       je exitprog

     ; compare data entry to 1 to add node
       cmp al, 31h
       je starttree

     ; set root to 1
       mov root, 1

     ; determine if tree is empty, if empty display message
       cmp node, 0
       je emptymessage

     ; compare data entry to 2 to search tree
       cmp al, 32h
       jne check3
       call searchtree

CHECK3: ; set up my label

     ; compare date entry to 3 to display data
       cmp al, 33h
       jne mainloop
       call disptree

       jmp mainloop

     ; set si to zero to represent empty
     ;  mov si, 0

     ; set di to zero to represent empty
     ;  mov di, 0

EXITPROG: ; set up my label       

     ; exit to DOS
       mov al, 0
       mov ah, 04ch
       int 21h

EMPTYMESSAGE: ; set up my label

     ; display empty message
       mov dx, OFFSET empty
       mov ah, 09h
       int 21h

     ; move back to main
       jmp displaymenu

STARTTREE:  ; set up my label

     ; display message
       mov dx, OFFSET message
       mov ah, 09h
       int 21h

     ; get character from keyboard with echo
       mov ah, 01h
       int 21h

       mov ah, 0

     ; check to see if the character entered is #
       cmp al, 23h

     ; if equal jump to exit program
       je exitprog

       mov root, 1

     ; compare next to 60 to determine if there is still space in the tree if not exit
       cmp next, 60
       jnl exitprog

CHECKTREE: ; set up my label

     ; check to see if tree is empty and jump to addnode if equal
       cmp node, 0
       je addnode

     ; compare root to zero and jump to addnode if equal
       cmp root, 0
       je addnode

     ; if not equal then jump to evaltree
       jne evaltree

ADDNODE: ; set up my label

     ; change node value to 1
       mov node, 1

     ; move the array position value in next to si
       mov bl, next
       mov bh, 0
       mov si, bx

     ; move the value into tree
       mov [bintree + si], al

     ; increment next by 3 to move position to next character slot
       add next, 3

     ; jump back to menu
       jmp displaymenu

EVALTREE: ; set up my label

     ; move root to di to compare position
       mov bl, root
       mov bh, 0
       mov di, bx

     ; compare bintree to value
       cmp al, [bintree + di]

     ; if less than jump to left child
       jl leftchild

     ; if greater than jump to right child
       jg rightchild

LEFTCHILD: ; set up my label

     ; subtract 1 from di
       sub di, 1

     ; move the position in bintree + di to root
       mov bl, [bintree + di]
       mov root, bl

     ; compare root to zero and if equal jump to change pointer and not equal to checktree
       cmp root, 0

       je changeptr

       jne checktree

RIGHTCHILD: ; set up my label

     ; add 1 from di
       add di, 1

     ; move the position in bintree + di to root
       mov bl, [bintree + di]
       mov root, bl

     ; compare root to zero and if equal jump to change pointer and not equal to checktree
       cmp root, 0

       je changeptr

       jne checktree

CHANGEPTR: ; set up my label

     ; move next to bintree + di
       mov bl, next
       mov [bintree + di], bl

     ; jump to checktree
       jmp checktree

tree ENDP

searchtree PROC

searchtree ENDP

disptree PROC

     ; save the value in root to the stack
       mov bl, root
       mov bh, 0
       push bx

     ; mov value in root to si
       mov si, bx

     ; decrement si to check the left child of character
       sub si, 1

     ; compare the value in bintree to 0
       cmp [bintree + si], 0
       je ldispret

     ; move the value in bintree + si to root
       mov bl, [bintree + si]
       mov root, bl

     ; return to disptree
       call disptree

     ; get root value from the stack
       mov root, bl

     ; move root to si
       mov bl, root
       mov bh, 0

DISPRIGHT: ; set up my label

       mov si, bx

     ; display the character
       mov dl, [bintree + si]
       mov ah, 02h
       int 21h

     ; increment si to check the right child of the character
       add si, 1

     ; compare the value in bintree + si to 0
       cmp [bintree + si], 0
       jne goright
       jmp rdispret

GORIGHT: ; set up my label

     ; move the value in bintree + si to root
       mov bl, [bintree + si]
       mov root, bl

     ; go back to disptree
       call disptree

ldispret: ; set up my label
     pop bx
     pop ax
     push bx
     push ax
     ret

rdispret: ; set up my label
     ; mov cl, root
     ; add cl, 3
     ; cmp next, cl
     ;je tomain 

     pop bx
     pop bx 

     jmp dispright

     pop bx
     pop bx
     ret

disptree ENDP 

TOMAIN: ; set up my label

     ;jmp mainloop

       end tree  

当它显示二叉树的内容时,它应该按字母顺序打印字符。如果我的输入是 m, b, a, c 它应该显示 abcm 然后返回菜单。程序在评估正确的树并尝试显示它时崩溃。

【问题讨论】:

  • 当你在 turbo 调试器中运行它时,你有没有单步执行代码?你有没有发现哪里出了问题?每条指令只是您编写时考虑到特定行为的一小部分工作。使用调试器来验证确实发生了什么。应该很容易发现偏差。 PS:如果您发现您的问题格式错误,请使用edit link 并自行修复。使用工具栏上的代码按钮。
  • 我已经逐步完成了代码。它将正确显示任何左孩子。我相信这与数组中的位置没有被正确比较或堆栈中的值没有正确比较有关。它无法正确比较以获取标签 rdispret,该标签旨在操纵堆栈。发生的另一个问题是,如果我放入根节点,然后放入一个右孩子,它在堆栈上没有足够的空间来操作

标签: recursion assembly binary-tree dos x86-16


【解决方案1】:

遵循您的程序流程并不容易,但我想我设法找到了导致代码崩溃的许多(重要)原因。

; return to disptree
  call disptree
; get root value from the stack
  mov root, bl

disptree 过程使用 ldispret: 中的堆栈操作在堆栈上留下一个单词,与您上面的评论相反,您没有'不要从堆栈中取出任何东西!使用pop bxmov root, bl

请注意,第一次调用 disptree(来自菜单的那个)也必须从堆栈中丢弃这个词。


rdispret: ; set up my label
  pop bx
  pop bx 
  jmp dispright

DISPRIGHT: ; set up my label
  mov si, bx
  ; display the character
  mov dl, [bintree + si]

rdispret: 代码首先弹出一个root 值,然后弹出一个返回地址。它是您随后错误地将其用作 bintree 数组中的索引的返回地址。使用pop bxpop axjmp dispright


对于任何使用递归的程序,最好分配一个大堆栈。 256 字节有点便宜。


CHECK3: ; set up my label
  ; compare date entry to 3 to display data
  cmp al, 33h
  jne mainloop

如果用户未能输入“1”到“4”范围内的数字,您的程序将进入无限循环。

如果发生这种情况,您需要向用户请求另一个字符。将 mainloop 标签向上移动 2 行。

【讨论】:

  • 谢谢。我会检查一下,看看它是如何工作的。我很感激。
猜你喜欢
  • 2016-04-19
  • 2014-03-29
  • 1970-01-01
  • 1970-01-01
  • 2010-12-07
  • 2020-09-15
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
相关资源
最近更新 更多