Генерация перестановок лениво

Вы можете использовать опцию -Xlinker.

g++ -o foobar  -Xlinker -start-group  -Xlinker libA.a -Xlinker libB.a -Xlinker libC.a  -Xlinker -end-group 

ALMOST равно

g++ -o foobar  -Xlinker -start-group  -Xlinker libC.a -Xlinker libB.a -Xlinker libA.a  -Xlinker -end-group 

Осторожно!

  1. Порядок в группе важен! Вот пример: библиотека отладки имеет процедуру отладки, но библиотека без отладки имеет слабую версию. Вы должны поместить библиотеку отладки FIRST в группу или вы решите на не-отладочную версию.
  2. Вам нужно перед каждой библиотекой в ​​списке групп с -Xlinker
83
задан Brian Carper 9 December 2008 в 09:19
поделиться

5 ответов

Да, там "следующая перестановка" алгоритм, и это довольно просто также. Стандартная библиотека шаблонов (STL) C++ даже имеет функцию, вызванную next_permutation.

алгоритм на самом деле находит следующий перестановка - лексикографически следующая. Идея - это: предположите, что Вам дают последовательность, говорите "32541". Какова следующая перестановка?

, Если Вы думаете об этом, Вы будете видеть, что это "34125". И Ваши мысли были, вероятно, чем-то это: В "32 541",

  • нет никакого способа сохранить эти "32" зафиксированных и найти более позднюю перестановку в "541" часть, потому что та перестановка уже является последней для 5,4, и 1 - это отсортировано в порядке убывания.
  • , Таким образом, необходимо будет измениться "2" на что-то большее - на самом деле, на самое маленькое количество, больше, чем он в "541" часть, а именно, 4.
  • Теперь, как только Вы решили, что перестановка запустится как "34", остальная часть чисел должна быть в увеличивающемся порядке, таким образом, ответ "34125".

алгоритм должен реализовать точно что цепь рассуждений:

  1. Находят самый длинный "хвост", который заказан в порядке убывания. ("541" часть.)
  2. Изменение число незадолго до хвоста ("2") к самому маленькому количеству, больше, чем он в хвосте (4).
  3. Сортируют хвост в увеличивающемся порядке.

можно сделать (1). эффективно путем запуска в конце и движения назад, пока предыдущий элемент не меньше, чем элемент тока. Можно сделать (2). просто подкачав "4" с '2", таким образом, Вы будете иметь "34521". Как только Вы делаете это, можно избегать использования алгоритма сортировки для (3)., потому что хвост был и все еще (думайте об этом), отсортированный в порядке убывания, таким образом, он только должен быть инвертирован.

код C++ делает точно это (посмотрите на источник в /usr/include/c++/4.0.0/bits/stl_algo.h в Вашей системе или посмотрите эта статья ); должно быть просто перевести его в Ваш язык: [Считайте "BidirectionalIterator" как "указатель", если Вы незнакомы с итераторами C++. Возвраты кода false, если существует никакая следующая перестановка, т.е. мы уже в порядке убывания.]

template <class BidirectionalIterator>
bool next_permutation(BidirectionalIterator first,
                      BidirectionalIterator last) {
    if (first == last) return false;
    BidirectionalIterator i = first;
    ++i;
    if (i == last) return false;
    i = last;
    --i;
    for(;;) {
        BidirectionalIterator ii = i--;
        if (*i <*ii) {
            BidirectionalIterator j = last;
            while (!(*i <*--j));
            iter_swap(i, j);
            reverse(ii, last);
            return true;
        }
        if (i == first) {
            reverse(first, last);
            return false;
        }
    }
}

могло бы казаться, что это может взять O (n) время на перестановку, но если Вы думаете об этом более тщательно, можно доказать, что это берет O (n!) время для всех перестановок всего, поэтому только O (1) - постоянное время - на перестановку.

хорошая вещь состоит в том, что алгоритм работает, даже когда у Вас есть последовательность с повторными элементами: с, скажем, "232254421", это нашло бы хвост как "54 421", подкачало бы "2" и "4" (так "232454221"), инвертировало бы остальных, дав "232412245", который является следующей перестановкой.

135
ответ дан ChaimKut 5 November 2019 в 16:34
поделиться

Необходимо проверить статья Permutations о wikipeda. Кроме того, существует понятие Factoradic числа.

Так или иначе, математическая проблема довольно трудна.

В C# можно использовать iterator и остановить алгоритм перестановки с помощью yield. Проблема с этим состоит в том, что Вы не можете пойти назад и вперед или использовать index.

3
ответ дан Bogdan Maxim 5 November 2019 в 16:34
поделиться

Предположение, что мы говорим о лексикографическом порядке по переставляемым значениям, существует два общих подхода, которые можно использовать:

  1. преобразовывают одну перестановку элементов к следующей перестановке (как отправленный ShreevatsaR), или
  2. непосредственно вычисляют n th перестановка, при подсчете n от 0 вверх.

Для тех (как я;-), кто не говорит C++ как собственные компоненты, приблизьтесь 1, может быть реализован от следующего псевдокода, приняв основанную на нуле индексацию массива с индексным нулем на "левом" (заменяющий некоторой другой структурой, такой как список, "оставлен как осуществление";-):

1. scan the array from right-to-left (indices descending from N-1 to 0)
1.1. if the current element is less than its right-hand neighbor,
     call the current element the pivot,
     and stop scanning
1.2. if the left end is reached without finding a pivot,
     reverse the array and return
     (the permutation was the lexicographically last, so its time to start over)
2. scan the array from right-to-left again,
   to find the rightmost element larger than the pivot
   (call that one the successor)
3. swap the pivot and the successor
4. reverse the portion of the array to the right of where the pivot was found
5. return

Вот пример, запускающийся с текущей перестановки CADB:

1. scanning from the right finds A as the pivot in position 1
2. scanning again finds B as the successor in position 3
3. swapping pivot and successor gives CBDA
4. reversing everything following position 1 (i.e. positions 2..3) gives CBAD
5. CBAD is the next permutation after CADB

Для второго подхода (прямое вычисление n th перестановка), помните, что существует N! перестановки N элементы. Поэтому, если Вы переставляете N элементы, первое (N-1)!, перестановки должны начаться с самого маленького элемента, следующее (N-1)!, перестановки должны начаться со второго самого маленького и так далее. Это приводит к следующему рекурсивному подходу (снова в псевдокоде, нумеруя перестановки и положения от 0):

To find permutation x of array A, where A has N elements:
0. if A has one element, return it
1. set p to ( x / (N-1)! ) mod N
2. the desired permutation will be A[p] followed by
   permutation ( x mod (N-1)! )
   of the elements remaining in A after position p is removed

Так, например, 13-я перестановка ABCD найдена следующим образом:

perm 13 of ABCD: {p = (13 / 3!) mod 4 = (13 / 6) mod 4 = 2; ABCD[2] = C}
C followed by perm 1 of ABD {because 13 mod 3! = 13 mod 6 = 1}
  perm 1 of ABD: {p = (1 / 2!) mod 3 = (1 / 2) mod 2 = 0; ABD[0] = A}
  A followed by perm 1 of BD {because 1 mod 2! = 1 mod 2 = 1}
    perm 1 of BD: {p = (1 / 1!) mod 2 = (1 / 1) mod 2 = 1; BD[1] = D}
    D followed by perm 0 of B {because 1 mod 1! = 1 mod 1 = 0}
      B (because there's only one element)
    DB
  ADB
CADB

Кстати, "удаление" элементов может быть представлено параллельным массивом булевских переменных, который указывает, какие элементы все еще доступны, таким образом, не необходимо создать новый массив на каждом рекурсивном вызове.

Так, для итерации через перестановки ABCD, просто количество от 0 до 23 (4!-1), и непосредственно вычисляют соответствующую перестановку.

41
ответ дан joel.neely 5 November 2019 в 16:34
поделиться

функция перестановок в clojure.contrib.lazy_seqs уже утверждает, что сделала просто это.

2
ответ дан 5 November 2019 в 16:34
поделиться

Больше примеров алгоритмов перестановки для генерации их.

Источник: http://www.ddj.com/architect/201200326

  1. Использование Алгоритм Флирта, который является тем известных самых быстрых.
  2. Использование Алгоритм к порядку Lexographic.
  3. Использование nonlexographic, но работает быстрее, чем объект 2.

1.


PROGRAM TestFikePerm;
CONST marksize = 5;
VAR
    marks : ARRAY [1..marksize] OF INTEGER;
    ii : INTEGER;
    permcount : INTEGER;

PROCEDURE WriteArray;
VAR i : INTEGER;
BEGIN
FOR i := 1 TO marksize
DO Write ;
WriteLn;
permcount := permcount + 1;
END;

PROCEDURE FikePerm ;
{Outputs permutations in nonlexicographic order.  This is Fike.s algorithm}
{ with tuning by J.S. Rohl.  The array marks[1..marksizn] is global.  The   }
{ procedure WriteArray is global and displays the results.  This must be}
{ evoked with FikePerm(2) in the calling procedure.}
VAR
    dn, dk, temp : INTEGER;
BEGIN
IF 
THEN BEGIN { swap the pair }
    WriteArray;
    temp :=marks[marksize];
    FOR dn :=  DOWNTO 1
    DO BEGIN
        marks[marksize] := marks[dn];
        marks [dn] := temp;
        WriteArray;
        marks[dn] := marks[marksize]
        END;
    marks[marksize] := temp;
    END {of bottom level sequence }
ELSE BEGIN
    FikePerm;
    temp := marks[k];
    FOR dk :=  DOWNTO 1
    DO BEGIN
        marks[k] := marks[dk];
        marks[dk][ := temp;
        FikePerm;
        marks[dk] := marks[k];
        END; { of loop on dk }
    marks[k] := temp;l
    END { of sequence for other levels }
END; { of FikePerm procedure }

BEGIN { Main }
FOR ii := 1 TO marksize
DO marks[ii] := ii;
permcount := 0;
WriteLn ;
WrieLn;
FikePerm ; { It always starts with 2 }
WriteLn ;
ReadLn;
END.

2.


PROGRAM TestLexPerms;
CONST marksize = 5;
VAR
    marks : ARRAY [1..marksize] OF INTEGER;
    ii : INTEGER;
    permcount : INTEGER;

PROCEDURE WriteArray; VAR i : INTEGER; BEGIN FOR i := 1 TO marksize DO Write ; permcount := permcount + 1; WriteLn; END;

PROCEDURE LexPerm ; { Outputs permutations in lexicographic order. The array marks is global } { and has n or fewer marks. The procedure WriteArray () is global and } { displays the results. } VAR work : INTEGER: mp, hlen, i : INTEGER; BEGIN IF THEN BEGIN { Swap the pair } work := marks[1]; marks[1] := marks[2]; marks[2] := work; WriteArray ; END ELSE BEGIN FOR mp := DOWNTO 1 DO BEGIN LexPerm<>; hlen := DIV 2; FOR i := 1 TO hlen DO BEGIN { Another swap } work := marks[i]; marks[i] := marks[n - i]; marks[n - i] := work END; work := marks[n]; { More swapping } marks[n[ := marks[mp]; marks[mp] := work; WriteArray; END; LexPerm<> END; END;

BEGIN { Main } FOR ii := 1 TO marksize DO marks[ii] := ii; permcount := 1; { The starting position is permutation } WriteLn < Starting position: >; WriteLn LexPerm ; WriteLn < PermCount is , permcount>; ReadLn; END.

3.


PROGRAM TestAllPerms;
CONST marksize = 5;
VAR
    marks : ARRAY [1..marksize] of INTEGER;
    ii : INTEGER;
    permcount : INTEGER;

PROCEDURE WriteArray; VAR i : INTEGER; BEGIN FOR i := 1 TO marksize DO Write ; WriteLn; permcount := permcount + 1; END;

PROCEDURE AllPerm (n : INTEGER); { Outputs permutations in nonlexicographic order. The array marks is } { global and has n or few marks. The procedure WriteArray is global and } { displays the results. } VAR work : INTEGER; mp, swaptemp : INTEGER; BEGIN IF THEN BEGIN { Swap the pair } work := marks[1]; marks[1] := marks[2]; marks[2] := work; WriteArray; END ELSE BEGIN FOR mp := DOWNTO 1 DO BEGIN ALLPerm<< n - 1>>; IF > THEN swaptemp := 1 ELSE swaptemp := mp; work := marks[n]; marks[n] := marks[swaptemp}; marks[swaptemp} := work; WriteArray; AllPerm< n-1 >; END; END;

BEGIN { Main } FOR ii := 1 TO marksize DO marks[ii] := ii permcount :=1; WriteLn < Starting position; >; WriteLn; Allperm < marksize>; WriteLn < Perm count is , permcount>; ReadLn; END.

3
ответ дан Carlos Eduardo Olivieri 5 November 2019 в 16:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: