Часть 2. «Двоичные деревья поиска».
Часть 1. «Быстрая сортировка».
1. Изучение алгоритма: Быстрая сортировка относится к алгоритмам «разделяй и властвуй». Алгоритм состоит из трёх шагов: 1) Выбрать элемент из массива (последний элемент). Назовём его опорным. 2) Разбиение: перераспределение элементов в массиве таким образом, что элементы меньше опорного помещаются перед ним, а больше или равные после. 3) Рекурсивно применить первые два шага к двум подмассивам слева и справа от опорного элемента. Рекурсия не применяется к массиву, в котором только один элемент или отсутствуют элементы.
2. Схема алгоритма :
3. Пример сортировки:
4. Текст программы : 1. lea ebx, [A] 2. mov si, bx 3. mov di, bx 4. mov ax, 3 ;kolichestvo elementov 5. dec ax 6. mov dl, 2 7. mul dl ;tk dw 8. add si, ax 9. push esi 10. mov ebp, esi 11. mov dl, 1 12. mov dh, 0 13. jmp pervaya 14. vtoraya: 15. cmp esi, edi 16. je perehod 17. push esi 18. podchast1: 19. cmp esi, ebp 20. jnl konec 21. cmp esi, edi 22. jng podchast3rs 23. podchast2ls: 24. lea ebx, [A] 25. dec esi 26. dec esi 27. jmp pervaya 28. perehod: 29. add edi, esi 30. podchast3rs: 31. pop esi 32. mov ebx, esi 33. inc ebx 34. inc ebx 35. pop esi 36. push esi 37. cmp esi, ebp 38. je perehod2 39. dec esi 40. dec esi 41. perehod2: 42. cmp ebx, esi 43. je podchast1 44. pervaya: 45. mov ecx, esi 46. sub ecx, ebx 47. cmp ecx, 0 48. jle vtoraya 49. cmp dl, dh 50. jg sravnenie1 51. jmp sravnenie2 52. sravnenie1: 53. mov ax, [ebx] 54. mov cx, [esi] 55. cmp ax, cx 56. jg zamena 57. inc bx 58. inc bx 59. jmp pervaya 60. sravnenie2: 61. mov ax, [ebx] 62. mov cx, [esi] 63. cmp ax, cx 64. jg zamena 65. dec si 66. dec si 67. jmp pervaya 68. zamena: 69. mov [ebx], cx 70. mov [esi], ax 71. xchg dl, dh 72. jmp pervaya 73. konec: 74. mov dl, 1 75. ret 76. section .data 77. A dw 0x3, 0x7, 0x4
5. Трассировочная таблица:
6. Анализ сложности алгоритма: Ясно, что операция разделения массива на две части относительно опорного элемента занимает время: O(log2n). Поскольку все операции разделения, проделываемые на одной глубине рекурсии, обрабатывают разные части исходного массива, размер которого постоянен, суммарно на каждом уровне рекурсии потребуется также O(n) операций. Следовательно, общая сложность алгоритма определяется лишь количеством разделений, то есть глубиной рекурсии. Глубина рекурсии, в свою очередь, зависит от сочетания входных данных и способа определения опорного элемента.
Лучший случай: O(n*log2n)
Среднее: O(n*logn)
Худший случай: O(n2)
7. Отчёт: Один из самых быстродействующих (на практике) из алгоритмов внутренней сортировки общего назначения. Прост в реализации. Однако сильно деградирует по скорости в худшем или близком к нему случае, что может случиться при неудачных входных данных. Прямая реализация в виде функции с двумя рекурсивными вызовами может привести к ошибке переполнения стека, так как в худшем случае ей может потребоваться сделать O(n) вложенных рекурсивных вызовов. Неустойчив.
Часть 2. «Двоичные деревья поиска».
1. Структура данных:
Двоичное дерево поиска записывается в один массив. Для хранения информации об одном узле необходимо четыре байта. Место под данные резервируется с помощью директивы db. В первом байте – значение узла; во втором – относительный номер строки меньшего по значению потомка; в третьем – относительный номер строки большего по значению потомка; в четвертом – «0», так как необходимо расширение до степени 2. Порядок работы программы: 1) Поиск вводимого элемента итеративным способом. 2) Добавление вводимого элемента в дерево (пропуск, если элемент был найден). 3) Поиск следующего вводимого элемента рекурсивным способом. 4) Добавление вводимого элемента в дерево (пропуск, если элемент был найден). 5) Обход дерева и вывод всех элементов в порядке возрастания. 2. Схемы алгоритмов: 1) Рекурсивный поиск:
2) Итеративный поиск:
3) Добавление элементов:
4) Обход дерева:
3. Код программы : 1) xor eax, eax 2) mov ebp, len 3) shr ebp, 2 4) call Iterativnii_poisk 5) call Rekursivnii_poisk 6) Obhod_dereva: lea ebx, [A] 7) xor ah, ah 8) mov ebp, 1 9) push ebp 10) print_tree: mov al, [ebx+1] 11) cmp al, 0 12) je skip_l 13) push ebx 14) shl ax, 2 15) add bx, ax 16) call print_tree 17) skip_l: mov al, [ebx] 18) PRINT_DEC 1, al 19) PRINT_STRING [Pr] 20) mov al, [ebx+2] 21) cmp al, 0 22) je skip_r 23) push ebx 24) shl ax, 2 25) add bx, ax 26) call print_tree 27) skip_r: pop ebx 28) pop ebx 29) cmp ebx, ebp 30) je konec 31) mov cl, [ebx+1] 32) cmp cl, 0 33) je obnulit 34) mov cl, 0 35) mov [ebx+1], cl 36) call print_tree 37) obnulit: mov [ebx+2], cl 38) jmp skip_r 39) konec: NEWLINE 40) PRINT_STRING [Print5] 41) ret
42) Iterativnii_poisk: pop eax 43) push eax 44) GET_DEC 1, dl 45) lea ebx, [A] 46) lea esi, [A] 47) xor edi, edi 48) xor ecx, ecx 49) poisk2: mov cl, [ebx] 50) cmp cl, dl 51) je goodend2 52) cmp di, 2 53) je noviiuzel 54) cmp di, 1 55) je praviisin 56) leviisin: inc di 57) mov ebx, esi 58) mov cl, [esi+1] 59) cmp cl, 0 60) je praviisin 61) shl cl, 2 62) add bl, cl 63) push ebx 64) jmp poisk2 65) praviisin: inc di 66) mov ebx, esi 67) mov cl, [esi+2] 68) cmp cl, 0 69) je noviiuzel 70) shl cl, 2 71) add bl, cl 72) push ebx 73) jmp poisk2 74) noviiuzel: inc ch 75) add ecx, ebp 76) cmp ch, cl 77) je badend2 78) pop esi 79) xor di, di 80) jmp leviisin 81) badend2: PRINT_STRING [Print1] 82) PRINT_DEC 1, dl 83) PRINT_STRING [Print3] 84) PRINT_STRING [Print2] 85) NEWLINE 86) call Dobavlenie_elementa 87) ret 88) goodend2: cmp eax, ecx 89) je vivod 90) pop ecx 91) jmp goodend2 92) vivod: push ecx 93) PRINT_STRING [Print1] 94) PRINT_DEC 1, dl 95) PRINT_STRING [Print2] 96) NEWLINE 97) ret
98) Rekursivnii_poisk: GET_DEC 1, dl 99) lea ebx, [A] 100) xor ecx, ecx 101) sub esp, 4 102) poisk: add esp, 4 103) mov al, [ebx] 104) cmp al, dl 105) je goodend 106) jl menshe 107) mov cl, [ebx+1] 108) cmp cl, 0 109) je badend 110) shl cl, 2 111) add bx, cx 112) call poisk 113) menshe: mov cl, [ebx+2] 114) cmp cl, 0 115) je badend 116) shl cl, 2 117) add bx, cx 118) call poisk 119) badend: PRINT_STRING [Print1] 120) PRINT_DEC 1, dl 121) PRINT_STRING [Print3] 122) PRINT_STRING [Print2] 123) NEWLINE 124) call Dobavlenie_elementa 125) ret 126) goodend: PRINT_STRING [Print1] 127) PRINT_DEC 1, dl 128) PRINT_STRING [Print2] 129) NEWLINE 130) ret
131) Dobavlenie_elementa: lea ebx, [A] 132) lea esi, [A] 133) push ebp 134) shl ebp, 2 135) add esi, ebp 136) pop ebp 137) xor ecx, ecx 138) sub esp, 4 139) sravnenie: add esp, 4 140) mov al, [ebx] 141) cmp al, dl 142) jl elem_bolshe 143) mov cl, [ebx+1] 144) cmp cl, 0 145) je pomeshchenie 146) shl cl, 2 147) add bx, cx 148) call sravnenie 149) elem_bolshe: mov cl, [ebx+2] 150) cmp cl, 0 151) je pomeshchenie 152) shl cl, 2 153) add bx, cx 154) call sravnenie 155) pomeshchenie: mov eax, esi 156) mov ecx, ebx 157) cmp dl, [ebx] 158) jg bolshe_uzla 159) sub eax, ecx 160) shr eax, 2 161) mov [ebx+1],al 162) jmp uvelichenie_massiva 163) bolshe_uzla: sub eax, ecx 164) shr eax, 2 165) mov [ebx+2],al 166) uvelichenie_massiva: mov [esi], dl 167) mov ecx, 3 168) xor eax, eax 169) c1: inc esi 170) mov [esi], al 171) loop c1 172) inc ebp 173) PRINT_STRING [Print1] 174) PRINT_DEC 1, dl 175) PRINT_STRING [Print4] 176) NEWLINE 177) ret 178) section .data
179) A db 15, 1, 2, 0 db 10, 0, 0, 0 db 20, 0, 0, 0
180) len equ $-A 181) Pr db " ", 0 182) Print1 db " Элемент ", 0 183) Print2 db " найден", 0 184) Print3 db " не", 0 185) Print4 db " добавлен", 0 186) Print5 db " Задача выполнена", 0 4. Трассировочная таблица: Дерево: Ввод и вывод:
(0.008 сек.) |