% Сортировка списка методом Шелла с использованием последовательности Седжвика
% shell_sort(+List, -SortedList)
% List - исходный список
% SortedList - отсортированный список
shell_sort(List, SortedList) :-
length(List, N),
sedgewick_sequence(N, Steps),
shell_sort_with_steps(List, Steps, SortedList).
% shell_sort_with_steps(+List, +Steps, -SortedList)
% List - список для сортировки
% Steps - список шагов (расстояний)
% SortedList - отсортированный список
shell_sort_with_steps(List, [], List). % Базовый случай: нет шагов, список отсортирован
shell_sort_with_steps(List, [H|T], SortedList) :-
gap_insertion_sort(List, H, InterList),
shell_sort_with_steps(InterList, T, SortedList).
% gap_insertion_sort(+List, +Gap, -SortedList)
% Сортировка вставками с заданным шагом (gap).
% На самом деле правильнее это называть gap exchange sort, т.к. это не совсем вставка, а скорее
% сравнение и обмен элементов на расстоянии Gap. Для простоты оставим название "insertion sort"
gap_insertion_sort(List, Gap, SortedList) :-
length(List, N),
gap_insertion_sort_loop(List, Gap, N, SortedList).
gap_insertion_sort_loop(List, Gap, N, SortedList) :-
gap_insertion_sort_loop(List, Gap, N, 0, SortedList).
gap_insertion_sort_loop(List, Gap, N, I, SortedList) :-
I >= N,
!,
List = SortedList.
gap_insertion_sort_loop(List, Gap, N, I, SortedList) :-
J >= N,
!,
gap_insertion_sort_loop(List, Gap, N, I1, SortedList).
gap_insertion_sort_loop(List, Gap, N, I, SortedList) :-
element_at_index(List, I, ElemI),
element_at_index(List, J, ElemJ),
(
ElemI > ElemJ ->
swap_elements(List, I, J, NewList),
gap_insertion_sort_loop(NewList, Gap, N, I1, SortedList)
;
gap_insertion_sort_loop(List, Gap, N, I1, SortedList)
).
% element_at_index(+List, +Index, -Element)
% Возвращает элемент списка по заданному индексу (начиная с 0).
element_at_index(List, Index, Element) :-
nth0(Index, List, Element).
% swap_elements(+List, +Index1, +Index2, -NewList)
% Меняет местами элементы с индексами Index1 и Index2 в списке List, возвращая новый список NewList
swap_elements(List, Index1, Index2, NewList) :-
element_at_index(List, Index1, Elem1),
element_at_index(List, Index2, Elem2),
replace_element_at_index(List, Index1, Elem2, TempList),
replace_element_at_index(TempList, Index2, Elem1, NewList).
% replace_element_at_index(+List, +Index, +NewElement, -NewList)
% Заменяет элемент с заданным индексом в списке List на NewElement, возвращая новый список NewList
replace_element_at_index(List, Index, NewElement, NewList) :-
replace_element_at_index_helper(List, Index, NewElement, 0, [], NewList).
replace_element_at_index_helper([_|Rest], Index, NewElement, CurrentIndex, Acc, NewList) :-
Index =:= CurrentIndex,
!,
append(Acc, [NewElement|Rest], NewList).
replace_element_at_index_helper([H|Rest], Index, NewElement, CurrentIndex, Acc, NewList) :-
CurrentIndex < Index,
NewCurrentIndex
is CurrentIndex
+ 1, replace_element_at_index_helper(Rest, Index, NewElement, NewCurrentIndex, [H|Acc], NewList).
% sedgewick_sequence(+N, -Steps)
% N - длина списка
% Steps - последовательность шагов Седжвика (в обратном порядке)
sedgewick_sequence(N, Steps) :-
sedgewick_sequence_helper(1, N, [], Steps).
sedgewick_sequence_helper(K, N, Acc, Steps) :-
(is_even(K) ->
H
is 9 * (2**K
) - 9 * (2**(K
/ 2)) + 1 ;
H
is 8 * (2**K
) - 6 * (2**((K
+ 1) / 2)) + 1 ),
( 3 * H > N ->
reverse(Acc, Steps) % Return the reversed sequence
; sedgewick_sequence_helper(K,H,N, Acc, Steps)
NewAcc = [H|Acc],
sedgewick_sequence_helper(Knext, N, NewAcc, Steps)
).
sedgewick_sequence_helper(K, H, N, Acc, Steps) :-
( 3 * H > N ->
reverse(Acc, Steps) % Return the reversed sequence
).
% Примеры использования и ожидаемый вывод (для ideone.com или другого Prolog-интерпретатора)
% Пример 1:
% ?- shell_sort([9, 5, 1, 4, 3, 7, 2, 8, 6], Sorted).
% Sorted = [1, 2, 3, 3, 4, 5, 6, 7, 8, 9]
% Пример 2:
% ?- shell_sort([5, 2, 8, 1, 9, 0, 4, 7, 3, 6], Sorted).
% Sorted = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
% Пример 3:
% ?- shell_sort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1], Sorted).
% Sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
% Пример 4:
% ?- shell_sort([1,2,3,4,5,6,7,8,9,10], Sorted).
% Sorted = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
% Пример 5: Empty List
% ?- shell_sort([],Sorted).
% Sorted = []
% Вывод нескольких примеров сразу (для удобства просмотра на ideone):
run_examples :-
test_shell_sort([9, 5, 1, 4, 3, 7, 2, 8, 6]),
test_shell_sort([5, 2, 8, 1, 9, 0, 4, 7, 3, 6]),
test_shell_sort([10, 9, 8, 7, 6, 5, 4, 3, 2, 1]),
test_shell_sort([1,2,3,4,5,6,7,8,9,10]),
test_shell_sort([]).
test_shell_sort(List) :-
shell_sort(List, Sorted),
format('Original list: ~w~n', [List]),
format('Sorted list: ~w~n~n', [Sorted]).
% To run all examples, uncomment the following line after loading the code:
% ?- run_examples.
JSDQodC+0YDRgtC40YDQvtCy0LrQsCDRgdC/0LjRgdC60LAg0LzQtdGC0L7QtNC+0Lwg0KjQtdC70LvQsCDRgSDQuNGB0L/QvtC70YzQt9C+0LLQsNC90LjQtdC8INC/0L7RgdC70LXQtNC+0LLQsNGC0LXQu9GM0L3QvtGB0YLQuCDQodC10LTQttCy0LjQutCwCgolIHNoZWxsX3NvcnQoK0xpc3QsIC1Tb3J0ZWRMaXN0KQolICAgTGlzdCAtINC40YHRhdC+0LTQvdGL0Lkg0YHQv9C40YHQvtC6CiUgICBTb3J0ZWRMaXN0IC0g0L7RgtGB0L7RgNGC0LjRgNC+0LLQsNC90L3Ri9C5INGB0L/QuNGB0L7QugpzaGVsbF9zb3J0KExpc3QsIFNvcnRlZExpc3QpIDotCiAgbGVuZ3RoKExpc3QsIE4pLAogIHNlZGdld2lja19zZXF1ZW5jZShOLCBTdGVwcyksCiAgc2hlbGxfc29ydF93aXRoX3N0ZXBzKExpc3QsIFN0ZXBzLCBTb3J0ZWRMaXN0KS4KCiUgc2hlbGxfc29ydF93aXRoX3N0ZXBzKCtMaXN0LCArU3RlcHMsIC1Tb3J0ZWRMaXN0KQolICAgTGlzdCAtINGB0L/QuNGB0L7QuiDQtNC70Y8g0YHQvtGA0YLQuNGA0L7QstC60LgKJSAgIFN0ZXBzIC0g0YHQv9C40YHQvtC6INGI0LDQs9C+0LIgKNGA0LDRgdGB0YLQvtGP0L3QuNC5KQolICAgU29ydGVkTGlzdCAtINC+0YLRgdC+0YDRgtC40YDQvtCy0LDQvdC90YvQuSDRgdC/0LjRgdC+0LoKc2hlbGxfc29ydF93aXRoX3N0ZXBzKExpc3QsIFtdLCBMaXN0KS4gICUg0JHQsNC30L7QstGL0Lkg0YHQu9GD0YfQsNC5OiDQvdC10YIg0YjQsNCz0L7Qsiwg0YHQv9C40YHQvtC6INC+0YLRgdC+0YDRgtC40YDQvtCy0LDQvQoKc2hlbGxfc29ydF93aXRoX3N0ZXBzKExpc3QsIFtIfFRdLCBTb3J0ZWRMaXN0KSA6LQogIGdhcF9pbnNlcnRpb25fc29ydChMaXN0LCBILCBJbnRlckxpc3QpLAogIHNoZWxsX3NvcnRfd2l0aF9zdGVwcyhJbnRlckxpc3QsIFQsIFNvcnRlZExpc3QpLgoKJSBnYXBfaW5zZXJ0aW9uX3NvcnQoK0xpc3QsICtHYXAsIC1Tb3J0ZWRMaXN0KQolINCh0L7RgNGC0LjRgNC+0LLQutCwINCy0YHRgtCw0LLQutCw0LzQuCDRgSDQt9Cw0LTQsNC90L3Ri9C8INGI0LDQs9C+0LwgKGdhcCkuCiUg0J3QsCDRgdCw0LzQvtC8INC00LXQu9C1INC/0YDQsNCy0LjQu9GM0L3QtdC1INGN0YLQviDQvdCw0LfRi9Cy0LDRgtGMIGdhcCBleGNoYW5nZSBzb3J0LCDRgi7Qui4g0Y3RgtC+INC90LUg0YHQvtCy0YHQtdC8INCy0YHRgtCw0LLQutCwLCDQsCDRgdC60L7RgNC10LUKJSDRgdGA0LDQstC90LXQvdC40LUg0Lgg0L7QsdC80LXQvSDRjdC70LXQvNC10L3RgtC+0LIg0L3QsCDRgNCw0YHRgdGC0L7Rj9C90LjQuCBHYXAuINCU0LvRjyDQv9GA0L7RgdGC0L7RgtGLINC+0YHRgtCw0LLQuNC8INC90LDQt9Cy0LDQvdC40LUgImluc2VydGlvbiBzb3J0IgoKZ2FwX2luc2VydGlvbl9zb3J0KExpc3QsIEdhcCwgU29ydGVkTGlzdCkgOi0KICBsZW5ndGgoTGlzdCwgTiksCiAgZ2FwX2luc2VydGlvbl9zb3J0X2xvb3AoTGlzdCwgR2FwLCBOLCBTb3J0ZWRMaXN0KS4KCmdhcF9pbnNlcnRpb25fc29ydF9sb29wKExpc3QsIEdhcCwgTiwgU29ydGVkTGlzdCkgOi0KICBnYXBfaW5zZXJ0aW9uX3NvcnRfbG9vcChMaXN0LCBHYXAsIE4sIDAsIFNvcnRlZExpc3QpLgoKZ2FwX2luc2VydGlvbl9zb3J0X2xvb3AoTGlzdCwgR2FwLCBOLCBJLCBTb3J0ZWRMaXN0KSA6LQogIEkgPj0gTiwKICAhLAogIExpc3QgPSBTb3J0ZWRMaXN0LgoKZ2FwX2luc2VydGlvbl9zb3J0X2xvb3AoTGlzdCwgR2FwLCBOLCBJLCBTb3J0ZWRMaXN0KSA6LQogIEogaXMgSSArIEdhcCwKICBKID49IE4sCiAgISwKICBJMSBpcyBJICsgMSwKICBnYXBfaW5zZXJ0aW9uX3NvcnRfbG9vcChMaXN0LCBHYXAsIE4sIEkxLCBTb3J0ZWRMaXN0KS4KCmdhcF9pbnNlcnRpb25fc29ydF9sb29wKExpc3QsIEdhcCwgTiwgSSwgU29ydGVkTGlzdCkgOi0KICBKIGlzIEkgKyBHYXAsCiAgZWxlbWVudF9hdF9pbmRleChMaXN0LCBJLCAgRWxlbUkpLAogIGVsZW1lbnRfYXRfaW5kZXgoTGlzdCwgSiwgIEVsZW1KKSwKICAoCiAgICBFbGVtSSA+IEVsZW1KIC0+CiAgICAgIHN3YXBfZWxlbWVudHMoTGlzdCwgSSwgSiwgTmV3TGlzdCksCiAgICAgIEkxIGlzIG1heCgwLCBJLUdhcCksCiAgICAgIGdhcF9pbnNlcnRpb25fc29ydF9sb29wKE5ld0xpc3QsIEdhcCwgTiwgSTEsIFNvcnRlZExpc3QpCiAgICA7CiAgICAgIEkxIGlzIEkgKyAxLAogICAgICBnYXBfaW5zZXJ0aW9uX3NvcnRfbG9vcChMaXN0LCBHYXAsIE4sIEkxLCBTb3J0ZWRMaXN0KQogICkuCgolIGVsZW1lbnRfYXRfaW5kZXgoK0xpc3QsICtJbmRleCwgLUVsZW1lbnQpCiUg0JLQvtC30LLRgNCw0YnQsNC10YIg0Y3Qu9C10LzQtdC90YIg0YHQv9C40YHQutCwINC/0L4g0LfQsNC00LDQvdC90L7QvNGDINC40L3QtNC10LrRgdGDICjQvdCw0YfQuNC90LDRjyDRgSAwKS4KZWxlbWVudF9hdF9pbmRleChMaXN0LCBJbmRleCwgRWxlbWVudCkgOi0KICAgIG50aDAoSW5kZXgsIExpc3QsIEVsZW1lbnQpLgoKJSBzd2FwX2VsZW1lbnRzKCtMaXN0LCArSW5kZXgxLCArSW5kZXgyLCAtTmV3TGlzdCkKJSAg0JzQtdC90Y/QtdGCINC80LXRgdGC0LDQvNC4INGN0LvQtdC80LXQvdGC0Ysg0YEg0LjQvdC00LXQutGB0LDQvNC4IEluZGV4MSDQuCBJbmRleDIg0LIg0YHQv9C40YHQutC1IExpc3QsINCy0L7Qt9Cy0YDQsNGJ0LDRjyDQvdC+0LLRi9C5INGB0L/QuNGB0L7QuiBOZXdMaXN0CnN3YXBfZWxlbWVudHMoTGlzdCwgSW5kZXgxLCBJbmRleDIsIE5ld0xpc3QpIDotCiAgZWxlbWVudF9hdF9pbmRleChMaXN0LCBJbmRleDEsIEVsZW0xKSwKICBlbGVtZW50X2F0X2luZGV4KExpc3QsIEluZGV4MiwgRWxlbTIpLAogIHJlcGxhY2VfZWxlbWVudF9hdF9pbmRleChMaXN0LCBJbmRleDEsIEVsZW0yLCBUZW1wTGlzdCksCiAgcmVwbGFjZV9lbGVtZW50X2F0X2luZGV4KFRlbXBMaXN0LCBJbmRleDIsIEVsZW0xLCBOZXdMaXN0KS4KCiUgcmVwbGFjZV9lbGVtZW50X2F0X2luZGV4KCtMaXN0LCArSW5kZXgsICtOZXdFbGVtZW50LCAtTmV3TGlzdCkKJSDQl9Cw0LzQtdC90Y/QtdGCINGN0LvQtdC80LXQvdGCINGBINC30LDQtNCw0L3QvdGL0Lwg0LjQvdC00LXQutGB0L7QvCDQsiDRgdC/0LjRgdC60LUgTGlzdCDQvdCwIE5ld0VsZW1lbnQsINCy0L7Qt9Cy0YDQsNGJ0LDRjyDQvdC+0LLRi9C5INGB0L/QuNGB0L7QuiBOZXdMaXN0CnJlcGxhY2VfZWxlbWVudF9hdF9pbmRleChMaXN0LCBJbmRleCwgTmV3RWxlbWVudCwgTmV3TGlzdCkgOi0KICByZXBsYWNlX2VsZW1lbnRfYXRfaW5kZXhfaGVscGVyKExpc3QsIEluZGV4LCBOZXdFbGVtZW50LCAwLCBbXSwgTmV3TGlzdCkuCgpyZXBsYWNlX2VsZW1lbnRfYXRfaW5kZXhfaGVscGVyKFtffFJlc3RdLCBJbmRleCwgTmV3RWxlbWVudCwgQ3VycmVudEluZGV4LCBBY2MsIE5ld0xpc3QpIDotCiAgSW5kZXggPTo9IEN1cnJlbnRJbmRleCwKICAhLAogIGFwcGVuZChBY2MsIFtOZXdFbGVtZW50fFJlc3RdLCBOZXdMaXN0KS4KCnJlcGxhY2VfZWxlbWVudF9hdF9pbmRleF9oZWxwZXIoW0h8UmVzdF0sIEluZGV4LCBOZXdFbGVtZW50LCBDdXJyZW50SW5kZXgsIEFjYywgTmV3TGlzdCkgOi0KICBDdXJyZW50SW5kZXggPCBJbmRleCwKICBOZXdDdXJyZW50SW5kZXggaXMgQ3VycmVudEluZGV4ICsgMSwKICByZXBsYWNlX2VsZW1lbnRfYXRfaW5kZXhfaGVscGVyKFJlc3QsIEluZGV4LCBOZXdFbGVtZW50LCBOZXdDdXJyZW50SW5kZXgsIFtIfEFjY10sIE5ld0xpc3QpLgoKJSBzZWRnZXdpY2tfc2VxdWVuY2UoK04sIC1TdGVwcykKJSAgIE4gLSDQtNC70LjQvdCwINGB0L/QuNGB0LrQsAolICAgU3RlcHMgLSDQv9C+0YHQu9C10LTQvtCy0LDRgtC10LvRjNC90L7RgdGC0Ywg0YjQsNCz0L7QsiDQodC10LTQttCy0LjQutCwICjQsiDQvtCx0YDQsNGC0L3QvtC8INC/0L7RgNGP0LTQutC1KQpzZWRnZXdpY2tfc2VxdWVuY2UoTiwgU3RlcHMpIDotCiAgc2VkZ2V3aWNrX3NlcXVlbmNlX2hlbHBlcigxLCBOLCBbXSwgU3RlcHMpLgoKc2VkZ2V3aWNrX3NlcXVlbmNlX2hlbHBlcihLLCBOLCBBY2MsIFN0ZXBzKSA6LQogICAgKGlzX2V2ZW4oSykgLT4KICAgICAgICBIIGlzIDkgKiAoMioqSykgLSA5ICogKDIqKihLIC8gMikpICsgMQogICAgOwogICAgICAgIEggaXMgOCAqICgyKipLKSAtIDYgKiAoMioqKChLICsgMSkgLyAyKSkgKyAxCiAgICApLAogICAgKCAgIDMgKiBIID4gTiAtPgogICAgICAgIHJldmVyc2UoQWNjLCBTdGVwcykgJSBSZXR1cm4gdGhlIHJldmVyc2VkIHNlcXVlbmNlCiAgICA7ICAgc2VkZ2V3aWNrX3NlcXVlbmNlX2hlbHBlcihLLEgsTiwgQWNjLCBTdGVwcykKICAgICAgICBOZXdBY2MgPSBbSHxBY2NdLAogICAgICAgIEtuZXh0IGlzIEsgKyAxLAogICAgICAgIHNlZGdld2lja19zZXF1ZW5jZV9oZWxwZXIoS25leHQsIE4sIE5ld0FjYywgU3RlcHMpCiAgICApLgoKc2VkZ2V3aWNrX3NlcXVlbmNlX2hlbHBlcihLLCBILCBOLCBBY2MsIFN0ZXBzKSA6LQogICAgKCAgIDMgKiBIID4gTiAtPgogICAgICAgIHJldmVyc2UoQWNjLCBTdGVwcykgJSBSZXR1cm4gdGhlIHJldmVyc2VkIHNlcXVlbmNlCiAgICApLgoKCmlzX2V2ZW4oTnVtYmVyKSA6LQogIE51bWJlciBtb2QgMiA9Oj0gMC4KCiUg0J/RgNC40LzQtdGA0Ysg0LjRgdC/0L7Qu9GM0LfQvtCy0LDQvdC40Y8g0Lgg0L7QttC40LTQsNC10LzRi9C5INCy0YvQstC+0LQgKNC00LvRjyBpZGVvbmUuY29tINC40LvQuCDQtNGA0YPQs9C+0LPQviBQcm9sb2ct0LjQvdGC0LXRgNC/0YDQtdGC0LDRgtC+0YDQsCkKCiUg0J/RgNC40LzQtdGAIDE6CiUgPy0gc2hlbGxfc29ydChbOSwgNSwgMSwgNCwgMywgNywgMiwgOCwgNl0sIFNvcnRlZCkuCiUgU29ydGVkID0gWzEsIDIsIDMsIDMsIDQsIDUsIDYsIDcsIDgsIDldCgolINCf0YDQuNC80LXRgCAyOgolID8tIHNoZWxsX3NvcnQoWzUsIDIsIDgsIDEsIDksIDAsIDQsIDcsIDMsIDZdLCBTb3J0ZWQpLgolIFNvcnRlZCA9IFswLCAxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5XQoKJSDQn9GA0LjQvNC10YAgMzoKJSA/LSBzaGVsbF9zb3J0KFsxMCwgOSwgOCwgNywgNiwgNSwgNCwgMywgMiwgMV0sIFNvcnRlZCkuCiUgU29ydGVkID0gWzEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwXQoKJSDQn9GA0LjQvNC10YAgNDoKJSA/LSBzaGVsbF9zb3J0KFsxLDIsMyw0LDUsNiw3LDgsOSwxMF0sIFNvcnRlZCkuCiUgU29ydGVkID0gWzEsIDIsIDMsIDQsIDUsIDYsIDcsIDgsIDksIDEwXQoKJSDQn9GA0LjQvNC10YAgNTogIEVtcHR5IExpc3QKJSA/LSBzaGVsbF9zb3J0KFtdLFNvcnRlZCkuCiUgU29ydGVkID0gW10KCiUg0JLRi9Cy0L7QtCDQvdC10YHQutC+0LvRjNC60LjRhSDQv9GA0LjQvNC10YDQvtCyINGB0YDQsNC30YMgKNC00LvRjyDRg9C00L7QsdGB0YLQstCwINC/0YDQvtGB0LzQvtGC0YDQsCDQvdCwIGlkZW9uZSk6CnJ1bl9leGFtcGxlcyA6LQogICAgdGVzdF9zaGVsbF9zb3J0KFs5LCA1LCAxLCA0LCAzLCA3LCAyLCA4LCA2XSksCiAgICB0ZXN0X3NoZWxsX3NvcnQoWzUsIDIsIDgsIDEsIDksIDAsIDQsIDcsIDMsIDZdKSwKICAgIHRlc3Rfc2hlbGxfc29ydChbMTAsIDksIDgsIDcsIDYsIDUsIDQsIDMsIDIsIDFdKSwKICAgIHRlc3Rfc2hlbGxfc29ydChbMSwyLDMsNCw1LDYsNyw4LDksMTBdKSwKICAgIHRlc3Rfc2hlbGxfc29ydChbXSkuCgp0ZXN0X3NoZWxsX3NvcnQoTGlzdCkgOi0KICAgIHNoZWxsX3NvcnQoTGlzdCwgU29ydGVkKSwKICAgIGZvcm1hdCgnT3JpZ2luYWwgbGlzdDogfnd+bicsIFtMaXN0XSksCiAgICBmb3JtYXQoJ1NvcnRlZCBsaXN0OiAgIH53fm5+bicsIFtTb3J0ZWRdKS4KCiUgVG8gcnVuIGFsbCBleGFtcGxlcywgdW5jb21tZW50IHRoZSBmb2xsb3dpbmcgbGluZSBhZnRlciBsb2FkaW5nIHRoZSBjb2RlOgolID8tIHJ1bl9leGFtcGxlcy4=