Отображать двоичное дерево рекурсивно - PullRequest
1 голос
/ 25 марта 2019

У меня есть код, который будет правильно добавлять узлы в дерево в 16-битном Ассемблере.Я могу отобразить любое количество левых деревьев до максимума без проблем.Каждый раз, когда я пытаюсь найти нужного ребенка для печати, происходит сбой системы.Я попытался увидеть, что происходит в турбо-отладчике, и предположил, что я не получаю что-то сохраненное или извлеченное из стека должным образом.

Я запускал этот код через турбо-отладчик больше раз, чем я помню, и не смогчтобы увидеть, где проблема (ы).

.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 и затем вернуться в меню.Программа аварийно завершает работу, когда оценивает правильное дерево и пытается его отобразить.

1 Ответ

0 голосов
/ 26 марта 2019

Было нелегко следить за ходом вашей программы, но я думаю, что мне удалось найти ряд (важных) причин, по которым происходит сбой кода.

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

disptree процедура оставляет слово в стеке, используя стек манипуляции в ldispret: , , но вопреки вашему комментарию выше, вы ничего не получите из стека!Используйте pop bx mov 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: код сначала появляется в корне значение, а затем всплывает обратный адрес .Это адрес возврата, который вы по ошибке используете в качестве индекса в массиве bintree .Используйте pop bx pop ax jmp dispright.


Для любой программы, использующей рекурсию, лучше всего выделить большой стек.256 байтов - это немного дешево.


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

Ваша программа входит в бесконечный цикл, если пользователь не может набрать число в диапазоне от 1 до 4.

Если это произойдет, вам нужно попросить другого персонажа у пользователя.Переместите метку mainloop на 2 строки выше.

...