Предикат сортировки в Прологе

Я пытаюсь понять, как sort/2 реализована в Прологе. Я хотел бы увидеть, как это работает, но я нигде не могу найти код для этого. Кто-нибудь знает, как это реализовано?

Отвечает ли это на ваш вопрос? Сортировка списка на Прологе

MWB 11.12.2020 23:10

Я хотел бы сделать сортировку по второму элементу в порядке убывания без удаления дубликатов. На данный момент я сделал это как «sort4 (List, Sorted): - sort (2, @> =, List, Sorted)». однако мне не разрешено использовать что-либо еще, кроме sort/2, поэтому я думаю, что могу изменить исходную функцию и реализовать ее как вспомогательную функцию.

user14809607 12.12.2020 21:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
1 175
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

В SWI-Prolog sort/2 является «встроенным», поэтому он есть в C.

Файл вроде бы src/pl-lists.c из раздачи.

Вот:

https://github.com/SWI-Prolog/swipl-devel/blob/master/src/pl-list.c

В строке 543:

static
PRED_IMPL("sort", 2, sort, PL_FA_ISO)
{ PRED_LD

  return pl_nat_sort(A1, A2,
             TRUE, SORT_ASC,
             0, NULL, FALSE PASS_LD);
}

pl_nat_sort находится в том же файле

Комментарий исторически интересен:

Естественная сортировка слиянием. Код предоставлен Ричардом О'Кифом и интегрирован в SWI-Prolog Яна Вилмейкера. Приятным моментом в этом коде является что он не использует дополнительное пространство и довольно стабилен в производительности. Ричардс утверждает, что многие реализации qsort() в libc очень медленный. Это не относится к glibc 2.2, где производительность примерно так же, как предыдущая реализация на основе qsort().

Предположительно Ричард О'Киф отмечает:

Я использую вариант этого кода в утилите сортировки примерно с 1988. Он оставляет программу sort(1) в UNIX далеко позади. Как ты можешь знать, sort(1) разбивает ввод на блоки, которые помещаются в памяти, сортирует блоков с помощью qsort() и записывает блоки на диск, а затем объединяет блоки. Для файлов, помещающихся в память, выполняется вариант этого кода примерно в два раза быстрее, чем sort(1). Отчасти это лучший ввод-вывод, но отчасти просто не используя qsort().

Даюм. Это навевает воспоминания о написании алгоритмов сортировки в 89-м.

Попробуйте выполнить поиск по быстрой сортировке.

Вот одна ссылка: https://www.codepoc.io/blog/prolog/4934/prolog-program-to-sort-a-list-using-quick-sort

Вот еще один пример: -

quicksort([], []).
quicksort([X | Tail], Sorted):-
    split(X, Tail, Small, Big),
    quicksort(Small, SortedSmall),
    quicksort(Big, SortedBig),
    concatenate(SortedSmall, [X| SortedBig], Sorted).

split(X, [], [], []).
split(X, [Y| Tail], [Y | Small], Big):-
    X > Y, !,
    split(X, Tail, Small, Big).
split(X, [Y| Tail], Small, [Y | Big]):-
    split(X, Tail, Small, Big).

concatenate([],List,List).
concatenate([Item|List1],List2,[Item|List3]) :-
    concatenate(List1,List2,List3).


?-quicksort([1,7,4,3,6,5,9,8,12,1],L).
L = [1, 1, 3, 4, 5, 6, 7, 8, 9, 12]
false

Есть ли более простой способ сделать это? Я хотел бы сделать сортировку по второму элементу в порядке убывания без удаления дубликатов. На данный момент я сделал это как «sort4 (List, Sorted): - sort (2, @> =, List, Sorted)». однако мне не разрешено использовать что-либо еще, кроме sort/2, поэтому я думаю, что могу изменить исходную функцию и реализовать ее как вспомогательную функцию.

user14809607 11.12.2020 20:40
Ответ принят как подходящий

Если вы просто ищете какой-либо алгоритм сортировки, вы всегда можете использовать пузырьковую сортировку *кашель*. Это один из самых простых и неэффективных способов сортировки списка, но, в зависимости от реализации, он будет проходить через уже отсортированный список за линейное время. Пузырьковая сортировка не удаляет дубликаты. Эта реализация выполняет порядок убывания:

bubblesort(List, SortedList) :-
    bubbleit(List, List1), 
    ! ,
    bubblesort(List1, SortedList) .
bubblesort(List, List).

bubbleit([X,Y|Rest], [Y,X|Rest]) :-
    X < Y, 
    ! .
bubbleit([Z|Rest], [Z|Rest1]) :-
    bubbleit(Rest, Rest1).

?- bubblesort([1,2,5,4,7,3,2,4,1,5,3],L).
L = [7, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1].

Если вы хотите отсортировать второй элемент в списке [_,E|], измените первое bubbleit правило на

bubbleit([X,Y|Rest], [Y,X|Rest]) :-
    X = [_,XX|_],
    Y = [_,YY|_],
    XX < YY, 
    ! .

?- bubblesort([[a,3],[b,5],[c,1],[d,4]],L).
L = [[b, 5], [d, 4], [a, 3], [c, 1]].

Спасибо! Как бы это работало, если бы у вас был список списков так [[ , ], [ , ]] и вы хотели бы отсортировать по второму элементу каждого подсписка?

user14809607 14.12.2020 00:40

@fewfrg я добавил метод к ответу

DuDa 14.12.2020 09:07

@fewfrg ^^ вы можете принять ответ, щелкнув серую галочку слева от ответа под кнопками "за"/"против"

DuDa 14.12.2020 13:34

Алгоритм сортировки слиянием естественно подходит для Пролога. Не говоря уже о тривиальной реализации на языке с рекурсией и списками в качестве фундамента.

Вот игровая площадка SWI: https://swish.swi-prolog.org/p/swi-prolog-merge-sort.pl

merge_sort( [], [] ).             % The empty list is by definition ordered
merge_sort( [X], [X] ).           % So is a list of length one
merge_sort( Unsorted, Sorted ) :- % otherwise...
  partition( Unsorted, L, R ) ,   % partition the list into 2 halves
  merge_sort(L,L1),               % recursively sort the left half
  merge_sort(R,R1),               % recursively sort the right half
  merge(L1,R1,Sorted)             % merge the newly-sorted halves
    .                             % See? simple!

partition( []      , []     , []     ).   % the empty list gets partitioned into two empty lists
partition( [X]     , [X]    , []     ).   % a left of length 1 gets partitioned into itself and an empty list
partition( [X,Y|L] , [X|Xs] , [Y|Ys] ) :- % list of length 2 or more gets popped and divided between left and right halves
  partition(L,Xs,Ys)                      % with the remainder being recursively partitioned.
    .                                     % Easy!

merge( []     , []     , []     ).        % merging to empty lists is trivial
merge( []     , [Y|Ys] , [Y|Ys] ).        % merging an empty list and a non-empty list is easy
merge( [X|Xs] , []     , [X|Xs] ).        % merging a non-empty list and an empty list is easy
merge( [X|Xs] , [Y|Ys] , [Lo,Hi|Zs] ) :-  % otherwise...
  compare(X,Y,Lo,Hi),                     % compare the two terms, put them in collating sequence
  merge(Xs,Ys,Zs)                         % and recursively merge the tails
  .                                       % Easy!

compare( X , Y , X, Y ) :- X @=< Y. % if X <= Y, X is Lo, and Y is Hi
compare( X , Y , Y, X ) :- X @>  Y. % if X >  Y, Y is Lo, and X is Hi

Другие вопросы по теме