Сортировка Шелла - Assembler
Формулировка задачи:
Мне нужно написать курсовую на тему сортировка Шелла
Я видел на сайте код для неё, но так и не понял как сделать её рабочей.
Есть у меня уже готовый код, с меню, красиво оформлено, только для сортировки Гнома, и никак не могу переделать её на Шелла.
Может кто шарит и поможет переделать? Я так понимаю нужно только GnomeSort поменять на алгоритм Шелла, но я так и не разобрался как
Вот код для Гнома
;--------------------------------------------------------------------- ; Підпрограма запису цілого числа з клавіатури з перевіркою на знак ;--------------------------------------------------------------------- ; Параматри ; ax - введене число ;--------------------------------------------------------------------- InputPInt proc ;збереження значень регістрів у стек push dx push bx push cx push si push di push ds push cs pop ds ;при невдалому введенні спробувати знову @@again: PRINT "==> " ;функція вводу символу з клавіатури mov ah,0ah xor di,di mov dx, offset @@buff int 21h mov dl,0ah mov ah,02 int 21h ;обробляємо значення буфера ;адрес початку строки mov si, offset @@buff+2 cmp byte ptr [si], "-" ;перевірка першого символу на мінус jnz @@ii1 jmp @@er @@ii1: xor ax, ax mov bx, 10 ;ініціалізація основи системи числення @@ii2: mov cl,[si] ;беремо символ з буферу cmp cl,0dh ;перевіряємо, чи не останній він jz @@enddecin ;якщо символ не останній, перевіряємо на правильність вводу cmp cl,'0' jl @@er cmp cl,'9' ja @@er ;перетворюємо символ в 10-ве число sub cl,'0' mul bx add ax,cx inc si jmp @@ii2 ;вивід повідомлення про помилку вводу @@er: PRINTN "Invalid number!Try again." jmp @@again @@enddecin: ;відновлюємо значення регістів cmp ax, 0 je @@er pop ds pop di pop si pop cx pop bx pop dx ret @@buff db 6,7 Dup(?) InputPInt endp ;--------------------------------------------------------------------- ;Підпрограма запису відповіді в файл ;--------------------------------------------------------------------- ;Параматри: ; нічого ;--------------------------------------------------------------------- InputToFile proc ;Відкриваємо файл mov ah,3ch xor cx, cx lea dx, fn int 21h ;При помилці відкриття виходимо jc @exit mov dscr, ax mov si, 0 ;ітератор mov di, count ;ініціалізуємо цикл @@again: cmp di, 0 je @exit ;вибираємо число з масиву xor cx,cx mov ax, array[si] add si, 2 ;якщо число відємне, то приводимо його до відповідного типу test ax, ax jns pos neg ax push ax push bx push cx push dx mov ah, 40h mov bx, dscr mov cx, 1 mov dx, offset minus int 21h pop dx pop cx pop bx pop ax ;інакше продовжуємо pos: ;перетворюємо число mov bx, 10 div10: xor dx,dx div bx push dx inc cx or ax, 0 jnz div10 mov dx, cx xor bx, bx nxt: pop ax add ax, 30h mov buf[bx], ax inc bx loop nxt ;записуємо переведене число в файл mov ah, 40h mov bx, dscr mov cx, dx lea dx, buf int 21h ;записуємо пробіл mov ah, 40h mov bx, dscr mov cx, 1 mov dx, offset space int 21h ;декрементуємо di та при необхідності повторюємо dec di jmp @@again @exit: ret InputToFile endp ;-------------------------------------------------------------------- ;Підпрограма сортування масиву DWORD алгоритмом "гнома" ;------------------------------------------------------------------- ;Параматри: ; array - покажчик на масиву ; count - кількість елементів у масиві ;-------------------------------------------------------------------- GnomeSort proc push BP mov BP, SP push BX push SI push DI ;xor si, si mov CX, count ;заносимо в ECX кількість елементів массиву xor AX, AX ;обнулюємо АХ, який буде ітератором xor si, si MainLoop: ;Якщо 'i' >= кількості елементів, то виходисо з циклу cmp AX, CX jge EndLoop ;Якщо 'i' == 0, перейти до наступного елементу cmp AX, 0 je IncreaseCounter ;Якщо array[i-1] <= array[i], це означає що массив є відсортованим, отже переводимо до наступного елементу mov BX, array[SI] mov DX, array[SI-2] cmp DX, BX jle IncreaseCounter ;Інакше міняємо місцями array[i-1] з array[i] push array[SI] push array[SI-2] pop array[SI] pop array[SI-2] ;Переходимо до попереднього елементу в масиві і декрементуємо АХ sub SI, 2 dec AX BackToMainLoop: jmp MainLoop ;Переходимо до наступного елементу в масиві і інкрементуємо АХ IncreaseCounter: inc AX add SI, 2 jmp BackToMainLoop EndLoop: ;Відновлюємо регістри pop DI pop SI pop BX pop BP GnomeSort endp ;-------------------------------------------------------------- ; Підпрограма запису цілого 10-числа з клавіатури ;-------------------------------------------------------------- ; Параматри ; ax - введене число ;-------------------------------------------------------------- InputInt proc ;збереження значень регістрів у стек push dx push bx push cx push si push di push ds push cs pop ds ;при невдалому введенні спробувати знову again: PRINT "==>" ;функція вводу символу з клавіатури mov ah,0ah xor di,di mov dx, offset buffs int 21h mov dl,0ah mov ah,02 int 21h ;обробляємо значення буфера ;адрес початку строки mov si, offset buffs+2 cmp byte ptr [si], "-" ;перевірка першого символу на мінус jnz ii1 mov di,1 inc si ii1: xor ax,ax mov bx,10 ;ініціалізація основи системи числення ii2: mov cl,[si] ;беремо символ з буферу cmp cl,0dh ;перевіряємо, чи не останній він jz enddecin ;якщо символ не останній, перевіряємо на правильність вводу cmp cl,'0' jl er cmp cl,'9' ja er ;перетворюємо символ в 10-ве число sub cl,'0' mul bx add ax,cx inc si jmp ii2 ;вивід повідомлення про помилку вводу er: PRINTN "Invalid number!Try again." jmp again ;якщо встановлений флаг, то робимо число відємним enddecin: cmp di,1 jnz ii3 neg ax ii3: ;відновлюємо значення регістів pop ds pop di pop si pop cx pop bx pop dx ret buffs db 6,7 Dup(?) InputInt endp ;-------------------------------------------------------------- ;Підпрограма виводу цілого 10-го числа ;-------------------------------------------------------------- ; Параматри: ; ах - чило для виводу ;-------------------------------------------------------------- OutInt proc ;Зберігаємо значення регістрів push ax push dx push bx push cx push ds push di push cs pop ds ;Перевіряємо число на знак test ax, ax jns oi1 mov di, 1 neg ax oi1: xor cx, cx mov bx, 10 ;основа СЧ oi2: xor dx, dx div bx add dx, '0' push dx ;зберігаємо значення в стек inc cx ;Відділяємо цифру справа поки не залишиться 0 test ax, ax jne oi2 ;Виводимо отримане значення mov ah, 2 cmp di, 1 jne oi3 ;При відємному числі виводимо знак '-' mov dl, '-' int 21h oi3: pop dx ;Виштовхеємо цифру, переводимо її в символ і виводимо int 21h loop oi3 ;повторюємо стільки разів, скільки цифр було нараховано ;Відновлюємо значення регістрів pop di pop ds pop cx pop bx pop dx pop ax ret OutInt endp ;------------------------------------------------------------- ; Підпрограма заповнення массива з клавіатури ;------------------------------------------------------------- ; Параматри: ; сх - кількість елементів у масиві ;------------------------------------------------------------- GetArray proc mov cx, count ;довжина массива mov bx, 0 ;ітератор @@1: call InputInt mov array[bx], ax add bx, 2 loop @@1 ret GetArray endp ;------------------------------------------------------------ ; Підпрограма виводу масиву на консоль ;------------------------------------------------------------ ; Параматри ; сх - довжина массива ;------------------------------------------------------------ OutArray proc cmp count, 0 je @@Exit mov cx, count ;довжина массива mov bx, 0 mov dl, ' ' @@2: mov ax, array[bx] call OutInt mov ah, 2 int 21h add bx, 2 loop @@2 @@Exit: ret OutArray endp ;----------------------------------------------------------------- ;Процедура відкриття файлу ;----------------------------------------------------------------- ;Параматри ; немає ;----------------------------------------------------------------- OpenFileRead PROC mov ah,3dh mov al,0 int 21h ret OpenFileRead ENDP ;------------------------------------------------------------- ;Процедура закриття файлу ;------------------------------------------------------------ ;Параматри: ; BX декриптор файла ;------------------------------------------------------------- CloseFile PROC mov ah,3eh int 21h ret CloseFile ENDP ;------------------------------------------------------------------ ;Процедура виходу з проограми ;------------------------------------------------------------------ ;Параматри: ; немає ;---------------------------------------------------- ExitProgramm PROC mov ah,0 mov al,2 int 10h mov ah,04Ch mov al,0h int 21h ExitProgramm ENDP ;------------------------------------------------------------------------ ;Процедура вивиду рядку символів на екран ;------------------------------------------------------------------------ ;Параматри: ; bx - символ для виводу ;------------------------------------------------------------------------ WriteStr PROC mov ah,09h int 21h ret WriteStr ENDP ;----------------------------------------------------------------------- ;функція читання з файлу ;---------------------------------------------------------------------- ReadFromFile proc ;Відкриваємо файл mov dx, offset fname call OpenFileRead mov handle, ax mov buff, 0 mov position, 0 xor si, si xor di, di @@again: ;-------------------------------------------------------------------- ;Покажчик на потрібну позицію mov bx, handle mov al, 0 mov cx, 0 mov dx, position mov ah, 42h int 21h inc position ;Зміщуємо позицію ;Читаємо з файлу mov bx, handle mov ah, 3fh mov cx, 1 ;Зчитуємо по 1 байту mov dx, offset t_buff int 21h ;Перевіряємо на кінець файлу cmp t_buff, '$' je Exit ;Перевіряємо на відємне число cmp t_buff, '-' jne @@postv mov di, 1 jmp @@again @@postv: ;Перевіряємо на пробіл cmp t_buff, ' ' jne @@cont ;Якщо пробіл, записуємо значення в масив cmp position, 3 jne @@ncount push buff pop count mov buff, 0 jmp @@again @@ncount: cmp di,1 jne @@pos mov bx, buff neg bx mov buff, bx @@pos: mov bx, buff mov array[si], bx add si, 2 ;Зміщуємо позицію mov buff, 0 xor di, di jmp @@again @@cont: xor ch, ch mov cl, t_buff ;перевіряємо на правильність вводу cmp cl,'0' jl Exit cmp cl,'9' ja Exit ;початкові установки mov bx, 10 ;ініціалізація основи системи числення ;перетворюємо символ в 10-ве число sub cl,'0' xor ch, ch mov ax, buff mul bx add ax, cx mov buff, ax jmp @@again Exit: mov bx, handle Call CloseFile jc Exit ret ReadFromFile endp
Решение задачи: «Сортировка Шелла»
textual
Листинг программы
// BaseType - любой перечисляемый тип // typedef int BaseType - пример void ShellsSort(BaseType *A, unsigned N) { unsigned i,j,k; BaseType t; for(k = N/2; k > 0; k /=2) for(i = k; i < N; i++) { t = A[i]; for(j = i; j>=k; j-=k) { if(t < A[j-k]) A[j] = A[j-k]; else break; } A[j] = t; } }
Объяснение кода листинга программы
- Входные данные:
- A - указатель на массив, который необходимо отсортировать
- N - количество элементов в массиве A
- Создаются три переменные:
- i - счётчик, который будет использоваться в двух вложенных циклах
- j - счётчик, который будет использоваться во внутреннем цикле
- k - делитель, который будет применяться к N во внутреннем цикле
- Запускается внешний цикл, который будет выполняться до тех пор, пока k не станет равным 1:
- Текущее значение k вычитается из i во внутреннем цикле
- Во внутреннем цикле происходит перебор элементов массива A, начиная с элемента с индексом j-k
- Если текущий элемент A[j-k] больше t, то A[j] присваивается значение A[j-k]
- Если текущий элемент A[j-k] меньше или равен t, то цикл прерывается
- После выхода из внутреннего цикла, A[j] присваивается значение t
- По завершении внешнего цикла, массив A будет отсортирован в порядке возрастания.
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д