Сортировать список в схеме

Я хочу создать функцию, которая сортирует список. Например, у меня есть этот список:

x1, x2, x3 .... xn

or

1, 2, 3, 4, 5, 6

Я хочу отображать числа в следующем порядке:

x1, xn, x2, xn-1

or

1, 6, 2, 5, 3, 4

Можете ли вы помочь мне написать этот пример?


person Peter Penzov    schedule 28.05.2013    source источник


Ответы (2)


Обычно, когда мы говорим о сортировке, мы имеем в виду упорядочение элементов по какой-либо характеристике содержимого элемента, а не позиции элемента в списке. Я бы назвал вашу ситуацию перестановкой, но, возможно, некоторые люди могут оспорить и это использование. :-)

Вот как можно подойти к проблеме:

  1. Разделите список посередине (вы можете сделать это, используя черепаху и зайца, если хотите пройти по списку только один раз); назовите эти списки head и tail, если хотите.
  2. Переверните список tail и чередуйте его со списком head.

Другой подход:

  1. Переверните исходные пары списков (назовем их rev).
  2. Чередуйте исходный список с rev, отслеживая каждый раз пройденный элемент. Когда они встретятся посередине, остановитесь.

Вот демонстрация второго подхода (требуется загрузка SRFI 1) :

(define (zippy lst)
  (if (null? lst)
      '()
      (let recur ((lst lst)
                  (rev (pair-fold cons '() lst)))
        (cond ((eq? lst (car rev)) (list (car lst)))
              ((eq? (cdr lst) (car rev)) (list (car lst) (caar rev)))
              (else (cons* (car lst) (caar rev)
                           (recur (cdr lst) (cdr rev))))))))
person Chris Jester-Young    schedule 28.05.2013
comment
... и ответ Оскара Лопеса демонстрирует первый подход. :-) +1 - person Chris Jester-Young; 29.05.2013

На самом деле это не операция сортировки, а скорее перетасовка; вот еще один способ решить эту проблему. Во-первых, давайте определим процедуру interleave, которая чередует элементы из двух списков, возвращая один список:

(define (interleave l1 l2)
  (cond ((empty? l1) l2)
        ((empty? l2) l1)
        (else (cons (first l1)
                    (interleave l2 (rest l1))))))

Теперь берем исходный список и split-at посередине (эта процедура специфична для Racket); наконец, мы чередуем два получившихся списка, меняя хвост:

(define (zippy lst)
  (let-values (((head tail) (split-at lst (quotient (length lst) 2))))
    (interleave head (reverse tail))))

Вышеупомянутая реализация IMHO немного более интуитивно понятна, и если вы работаете с Racket, она не требует внешних библиотек. Он работает так, как ожидалось:

(zippy '(1 2 3 4 5 6))
=> '(1 6 2 5 3 4)
person Óscar López    schedule 28.05.2013
comment
Очень хорошо. :-) Примечания для реализации без Racket: split-at является частью SRFI 1, а let-values является частью SRFI 11. Если в вашей реализации нет SRFI 11, вы также можете легко перейти на использование receive из SRFI 8, или же вы можете напрямую использовать call-with-values, хотя последний способ менее удобен. :-) - person Chris Jester-Young; 29.05.2013
comment
Кстати, я думаю, что (/ (length lst) 2) возвращает нецелое число для списка нечетной длины, что может не понравиться split-at. (quotient (length lst) 2) может работать лучше. - person Chris Jester-Young; 29.05.2013
comment
@ChrisJester-Young, ты, конечно, прав. Исправил, спасибо! - person Óscar López; 29.05.2013
comment
Я вижу одну проблему. Как я могу отсортировать числа, если у меня такой порядок: 4, 2, 9, 3, 5, 1 Как я могу их отсортировать? - person Peter Penzov; 06.06.2013
comment
Порядок, который вы определили в вопросе, похоже, зависит от положения элементов, а не от их значений. Если значения релевантны, то сначала отсортируйте список, прежде чем передавать его в мою функцию, используйте процедуру sort - person Óscar López; 06.06.2013