| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- Program ShellSort;
- {Сортировка Шелла, улучшение алгоритма прямого включения, разница в том,
- что процесс сортировки бьется на T этапов, в каждом из которых делается
- один проход прямого включения, но только на элементы, отстоящие друг от
- друга на h[i] эл-тов (i in [1..T] и h[T] = 1)
- Также для алгоритма прямой вставки удобно использовать "барьеры". Дабы
- при перемещении не сверять индекс эл-та с началом массива, удобно
- расширить массив на 1 эл-т (в данном случае на h[1]) и туда писать эл-т,
- которому собираемся искать место. Таким образом размер массива будет
- [-h[1]..TotalCount]. Вследствие желания создать универсальный алгоритм
- с использованием динамических структур (нам заранее не известно T и
- соответственно h[1]) будет использоваься смещенная индексация массива
- ( A[i] -> A[h[1]+i]).
- Используются улучшения Д. Кнута:
- h[k-1] := 3*h[k]+1;
- T := LOG(N,3)-1
- PS. Надеюсь весь этот бред поможет вам разобраться в предложенном алгоритме.}
- type
- item = word;
- const
- MaxCount = 65530 div SizeOf(item); {Максимальное число эл-тов массива}
- TotalCount = 20000;
- type
- pArray = ^tArray;
- tArray = array [1..MaxCount] of Item;
- tIndex = 1..MaxCount;
- var
- T : tIndex; {Число "разбиений"}
- h : pArray;
- Fi : tIndex; {Реальный индекс первого эл-та (не барьера)}
- A : pArray;
- {--------------------------------------------------------------}
- Procedure Init; {Устанавливаются улучш. Кнута, иниц. массивы}
- var
- i : tIndex;
- begin
- T := round(Ln(TotalCount)/Ln(3)-1); {(С) Кнут}
- GetMem(h,T*SizeOf(item)); {Иниц. массив расстояний}
- h^[T] := 1;
- for i := T-1 DownTo 1 do h^[i] := 3*h^[i+1]+1;
- Fi := h^[1]; {Установим глоб. индекс "смещенного" смещения}
- GetMem(A,(TotalCount+Fi)*Sizeof(Item)); {Иницализируем осн. массив}
- {^^^ Для барьеров}
- end;{Init}
- {--------------------------------------------------------------}
- Procedure Done; {Осв. всю память}
- begin
- FreeMem(h,T*SizeOf(Item));
- FreeMem(A,TotalCount*SizeOf(Item));
- end;{Done}
- {--------------------------------------------------------------}
- Procedure SetArray; {Процедурка заполнения эл-тов массива случ. числами}
- var
- i : tIndex;
- begin
- Randomize;
- For i := 1 To TotalCount Do A^[Fi+i] := Random(65535);
- {^^^ Опять барьеры}
- end;{SetArray}
- {--------------------------------------------------------------}
- {Основная программа}
- Var
- i,j,k,m,s : tIndex;
- Times : pArray;
- x : Item;
- BEGIN
- Init;
- SetArray;
- GetMem(Times,T*SizeOF(Word));
- FillChar(Times^,T*SizeOF(Word),0);
- For m := 1 to T do
- begin
- k := h^[m]; {Расстояние между эл-тами}
- s := Fi-k; {"барьер"}
- For i := k+1 to TotalCount do
- begin
- x := A^[Fi+i]; {Эл-т, с которым работаем}
- If S=Fi then S := Fi-k;
- inc(s);
- A^[s] := x; {Установим "барьер"}
- j := i-k; {Предыдущий через расстояние}
- while A^[Fi+j] > x do
- begin
- Inc(Times^[m]);
- A^[Fi+j+k] := A^[Fi+j]; {Двигаем массив}
- dec(j,k);
- end;
- A^[Fi+j+k] := x;
- end;
- end;
- For i := 1 to TotalCount do
- begin
- if ((i-1) mod 10) = 0 then WriteLN;
- Write(A^[Fi+i]:7);
- end;
- WriteLN(#10#13'Число перестановок на каждом этапе:');
- for i := 1 to T do WriteLn(i,'(',H^[i],') -> ',Times^[i]);
- FreeMem(Times,T*SizeOF(Word));
- Done;
- END.
|