
- •1Введение
- •2Сортировки
- •2.1Сортировки массивов
- •2.2Сортировка простым включением
- •2.3Сортировка простым выбором
- •2.4Сортировка простым обменом
- •2.5Сравнение простых сортировок
- •2.6 Сортировка шелла
- •2.7Пирамидальная сортировка
- •2.8Быстрая сортировка
- •2.9Поиск медианы и квантилей
- •2.10Сравнение сортировок
- •3Поиск подстроки в строке
- •3.1Поиск в строке
- •3.2Простой поиск в строке
- •3.3Поиск в строке. Алгоритм боуера-мура
- •4Генерация перестановок
- •4.1Генерация перестановок последовательности натуральных чисел
- •4.2Генерация перестановок элементов в антилексикографическом порядке
- •4.3Генерация перестановок за одну транспозицию элементов
- •4.4Генерация перестановок за одну транспозицию соседних элементов
- •5Генерация подмножеств
- •5.1Генерация всех подмножеств множества
- •5.2Генерация m -элементных подмножеств множества натуральных чисел
- •Var m: integer; {Размер подмножества}
- •Var I, j, p: integer;
- •5.3Генрация k-компонентных выборок на множестве {0, 1}
- •Var k: integer; {Количество нулей в кортеже}
- •I: integer;
- •Var I, j, p: integer;
- •If Finish then Break {Exit};
- •6Генерация разбиений
- •6.1Разбиение целых чисел
- •Var I, j: integer;
- •Var j: integer;
- •Var I, j, k: integer;
- •Var d, l, Sum: integer;
- •6.2Разбиение множеств
- •/1, 2, 3/ И /4/ затем /1, 2/ и /3, 4/ и т.Д. }
- •I, j, k, r, s: integer;
- •If not Flag2 then
- •If Flag1 then
- •If Forvd[j] then { j движется вперед}
- •7Обходы бинарных деревьев
- •7.1Процедуры прохождения бинарных деревьев
- •8Поиск на бинарных деревьях
- •8.1Процедуры поиска на бинарных деревьях
- •Рекомендованная литература
4.2Генерация перестановок элементов в антилексикографическом порядке
Введем определение лексикографического и антилексикографического порядка перестановок из n элементов.
Лексикографический порядок перестановок.
Начнем с примера. Пусть задана последовательность из трех чисел 1, 2, 3. Для этой последовательности можно определить следующий набор перестановок:
1, 2, 3
1, 3, 2
2, 1, 3
2, 3, 1
3, 1, 2
3, 2, 1
Этот набор иллюстрирует лексикографический порядок следования перестановок.
Лексикографический порядок следования перестановок определяется на множестве всех перестановок. Для двух смежных перестановок
x1, x2, …, xn и y1, y2, …, yn
перестановка x1, x2, …, xn предшествует перестановке y1, y2, …, yn в лексикографическом порядке т. е.
x1, x2, …, xn < y1, y2, …, yn
если существует такое k>=1, когда для всех 1<=j<k выполняется xj = yj, и xk<=yk.
Так, например, для двух смежных перестановок:
1, 2, 3
1, 3, 2
при k = 2 имеет место x1 = y1 и x2 <= y2
а для двух смежных перестановок:
1, 3, 2
2, 1, 3
при k = 1 имеет место x1 <= y1.
Пусть перестановки определяются на наборе á1, 2, …, nñ. Тогда из приведенного определения можно сделать два вывода:
В первой перестановке элементы идут в возрастающей последовательности, а в последней – в убывающей последовательности.
Весь набор из n! перестановок можно разбить на n блоков, по (n-1)! перестановок в каждом. В пределах блока содержимое первой позиции каждой перестановки остается неизменным, а от блока к блоку оно последовательно возрастает.
Таким образом, в первой позиции разных блоков элементы упорядочены в лексикографическом порядке.
Если в первой позиции блока располагается элемент p набора
á1, 2,…,nñ т. е. p á1, 2, …, nñ
то последние n-1 позиция этого блока определяют последовательность перестановок набора
á1, 2, … , nñ\p
упорядоченных в лексикографическом порядке.
Для рассмотренного примера среди 3! перестановок выделяется 3 блока по 2! перестановок. В пределах каждого блока значение первой позиции неизменно, а на позициях 2 и 3 размещаются все возможные перестановки из двух оставшихся элементов.
Антилексикографический порядок перестановок.
Начнем с примера. Пусть задана та же последовательность из трех чисел X = {1, 2, 3}. Для этой последовательности можно определить следующий набор перестановок:
1, 2, 3
2, 1, 3
1, 3, 2
3, 1, 2
2, 3, 1
3, 2, 1
Антилексикографический порядок следования перестановок определяется на множестве всех перестановок. Для двух смежных перестановок
x1, x2, …, xn и y1, y2, …, yn
перестановка x1, x2, …, xn предшествует перестановке y1, y2, …, yn в антилексикографическом порядке т. е.
x1, x2, …, xn <' y1, y2, …, yn
если существует такое k<=n, когда, для всех k<j<=n выполняется xj = yj. и xk > yk.
Примечание. Фактически антилексикографический порядок следования перестановок можно рассматривать как лексикографический порядок следования перестановок при взгляде на перестановки справа налево и с поправкой на порядок следования значений в последней позиции – от большего значения к меньшему значению.
Так, например, для двух смежных перестановок:
1, 2, 3
2, 1, 3
при k = 2 имеет место x3= y3 и x2 > y2
а для двух смежных перестановок:
2, 1, 3
1, 3, 2
при k = 3 имеет место x3 > y3
Пусть перестановки определяются на наборе á1, 2, …, nñ. Тогда из приведенного определения можно сделать два вывода:
В первой перестановке элементы идут в возрастающей последовательности, а в последней – в убывающей последовательности.
Весь набор из n! перестановок можно разбить на n блоков, по (n-1)! перестановок в каждом. В пределах блока содержимое последней позиции каждой перестановки остается неизменным и от блока к блоку оно последовательно убывает.
Таким образом, в последней позиции разных блоков элементы упорядочены в антилексикографическом порядке. Если в последней позиции блока располагается элемент p набора
á1, 2, …, nñ т. е. p á1, 2, …, nñ
то первые n‑1 позиции этого блока определяют последовательность перестановок набора
á1, 2, …, nñ\p
упорядоченных в антилексикографическом порядке.
Для рассмотренного примера среди 3! перестановок выделяется 3 блока по 2! перестановок. В пределах каждого блока значение последней позиции неизменно, а на позициях 1 и 2 размещаются все возможные перестановки из двух оставшихся элементов.
Отмеченные выше свойства перестановок, упорядоченных в антилексикографическом порядке, позволяют предложить достаточно простой алгоритм генерации перестановок из n элементов.
Алгоритм генерирования перестановок, упорядоченных в антилексикографическом порядке.
Такой алгоритм технически представить легче, за счет использования рекурсии.
Введем понятие реверса последовательности элементов. Он состоит в том, что в последовательности элементов они попарно меняются местами симметрично середины последовательности. Например, дана последовательность
á1, 2, 3, 4, 5, 6, 7, 8ñ
Ее реверсом является последовательность
á8, 7, 6, 5, 4, 3, 2, 1ñ
В приводимой ниже программе реверс реализуется процедурой Reverse, содержащей один параметр M – размер массива P.
Алгоритм генерирования перестановок реализуется рекурсивным образом с помощью процедуры AntyLex, содержащей один параметр M - количество первых элементов массива P, для которых выполняется перестановка.
Пусть массив P, содержит последовательность вида:
P[1] |
P[2] |
P[3] |
|
P[m-3] |
P[m-2] |
P[m-1] |
P[m] |
a1 |
a2 |
a3 |
|
am-3 |
am-2 |
am-1 |
am |
Задачей процедуры AntyLex является генерирование всех перестановок элементов
P[1], …, P[m]
через последовательное генерирование блока всех перестановок элементов
P[1], …, P[m-1]
при фиксированном P[n] с последующей заменой элемента P[n] одним из элементов
P[1], …, P[m-1]
Замена осуществляется путем транспозиции, выполняемой по определенному закону внутри процедуры AntyLex.
Для удобства изложения будем считать, что элементы в массиве упорядочены по возрастанию, хотя в действительности алгоритм сформулирован в терминах позиций элементов массива и в нем не используется содержание этих элементов.
Рассмотрим суть алгоритма. Зафиксируем P[m] = am. Выполним процедуру AntyLex(m-1). Это приведет к генерации блока из (m-1)! перестановок вида:
a1 |
a2 |
a3 |
|
am-3 |
am-2 |
am-1 |
am |
Генерация блока из (m-1)! перестановок |
|
|
|
|
|
|
|
||
am-1 |
am-2 |
am-3 |
|
a3 |
a2 |
a1 |
am |
В последней перестановке из (m-1) элементов все элементы упорядочены по убыванию.
Затем выполним транспозиция элементов P[1] и P[m] массива.
am |
am-2 |
am-3 |
|
a3 |
a2 |
a1 |
am-1 |
Транспозиция P[1] и P[m] |
В результате на позиции P[m] располагается следующий в порядке убывания элемент массива, т. е P[m] = am-1. Этим задается старт генерации очередного блока перестановок.
В позиции P[1] в результате транспонирования располагается самый большой среди всех элементов в позициях P[1], …, P[m-1]. Если теперь выполнить реверс последовательности P[1], …, P[m-1]
a1 |
a2 |
a3 |
|
am-3 |
am-2 |
am |
am-1 |
Reverse(m-1) |
то в позициях P[1], …, P[m-1] элементы будут упорядочены по возрастанию.
Теперь все готово к генерации очередного блока из (m-1)! перестановок и снова можно применить процедуру AntyLex(m - 1). Это приведет к генерации блока перестановок вида:
a1 |
a2 |
a3 |
|
am-3 |
am-2 |
am |
am-1 |
Генерация блока из (m-1)! перестановок |
|
|
|
|
|
|
|
||
am |
am-2 |
am-3 |
|
a3 |
a2 |
a1 |
am-1 |
Вновь в последней перестановке из (m-1) элементов все элементы упорядочены по убыванию. Но теперь выполняется транспозиция элементов P[2] и P[m] массива.
am |
am-1 |
am-3 |
|
a3 |
a2 |
a1 |
am-2 |
Транспозиция P[2] и P[m] |
В результате на позиции P[m] располагается следующий в порядке убывания элемент массива, т. е P[m] = am-2.
Теперь выполняется реверс последовательности P[1], …, P[m-1]
a1 |
a2 |
a3 |
|
am-3 |
am-1 |
am |
am-2 |
Reverse(m-1) |
В результате в позициях P[1], …, P[m-1] элементы упорядочены по возрастанию. Теперь к ним снова можно применить процедуру AntyLex(m - 1).
Таким образом, после получения i-1 блока перестановок для получения i блока перестановок выполняется транспозиция элементов массива P[i] и P[m], а, затем, реверс последовательности P[1], …, P[m-1].
Этот процесс повторяется циклически так, что для получения последнего m блока перестановок выполняется транспозиция элементов массива P[m-1] и P[m], а, затем, реверс последовательности P[1], …, P[m-1].
В заключение необходимо отметить, что для получения всех перестановок из m элементов необходимо выполнить m раз процедуру AntyLex(m ‑ 1), и m-1 раз процедуру Revers(m-1).
Но все перестановки из m-1 элементов могут быть получены при наличии всех перестановок из m-2 элементов и т.д. Следовательно, процедура AntyLex является рекурсивной.
Ниже приводится текст программы генерирования перестановок, упорядоченных в антилексикографическом порядке. Программа содержит процедуру Reverse(m-1) и рекурсивную процедуру AntyLex. В программе массив, содержащий элементы перестановки, рассматривается как глобальный.
program Permutation2;
uses crt;
var
I: integer;
P: array of integer; {исходный массив}
N: integer; {размер исходного массива}
procedure Reverse (M: integer);
var I, J, Work: integer;
begin
I := 0;
J := M-1;
while I < J do
begin
Work := P[I];
P[I] := P[J];
P[J] := Work;
I := I + 1;
J := J - 1;
end;
end; {Reverse}
procedure AntyLex (M: integer);
var I, J, Work: integer;
begin
if M = 0 then
begin
for J := 0 to N-1 do Write (P[J], ' ');
Writeln;
end
else
for I := 0 to M-1 do
begin
AntyLex (M-1);
if I < M then
begin
Work := P[I];
P[I] := P[M];
P[M] := Work;
Revers (M-1);
end;
end;
end; {AntyLex}
begin
clrscr;
Write (Введите размер массива N -> );
Readln (N);
SetLength (P, N);
for I := 0 to N-1 do P [I] := I+1;
AntyLex (N);
end. {Permutation2}
К особенностям алгоритма следует отнести то, что количество транспозиций при получении очередной перестановки не является величиной постоянной. Если в некоторых случаях достаточно только одной транспозиции для получения новой перестановки, то в других случаях таких транспозиций должно быть несколько. Так каждая вторая перестановка образуется транспозицией элементов P[1] и P[2], но есть и такие перестановки, для которых требуется
(m-1) div 2 + 1
транспозицией. Но, в среднем, число транспозиций, приходящихся на одну перестановку невелико.
Однако в некоторых практических задачах было бы лучше, если бы каждая следующая перестановка получалась из предыдущей с помощью только одной транспозиции. Например, в случаях, когда с каждой перестановкой связаны определенные вычисления и существует возможность использования частичных результатов, полученных для предыдущей перестановки.