- •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Процедуры поиска на бинарных деревьях
- •Рекомендованная литература
5Генерация подмножеств
Множество всех подмножеств множества X обозначается P{X}. Каждое N-элементное множество X={x1, x2, …, xn} имеет в точности 2n подмножеств. Это можно показать следующим образом.
Сопоставим элементам множества
X={x1, x2, …, xn}
бинарную последовательность
b1, b2,…, bn
определяемую следующим образом.
Пусть задано подмножество YX. Тогда:
bi = 0 если xi Y
bi = 1 если xi Y.
Тем самым устанавливается взаимно однозначное соответствие между элементами множества всех подмножеств P{X} и всеми бинарными последовательностями длины N.
Установленная описанным выше способом последовательность
b1, b2, …, bn
становится хорошим способом машинного представления любого подмножества Y, особенно когда мощность множества X не велика и последовательность
b1, b2, …, bn
может быть представлена с помощью одного машинного слова. В современных персональных компьютерах это 32 или 64 разряда, что для большинства практических задач вполне достаточно.
Предложенное представление множества приводит к простому способу генерирования всех подмножеств. Действительно, каждая бинарная последовательность
bn-1, bn-2, …, b0
соответствует числу r из интервала 0 r 2n-1. В результате достаточно последовательно получать все числа из интервала 0 r 2n-1, а их двоичные представления дадут все подмножества N‑элементного множества.
При таком способе получения очередного подмножества два соседних подмножества могут значительно отличаться друг от друга. Например, после (n-1) элементного множества, соответствующего двоичному числу
0111…1
следует одноэлементное множество, соответствующее числу
1000…0
В некоторых случаях бывает важно, чтобы каждое последующее подмножество наименьшим образом отличалось от предыдущего подмножества. В реальных задачах, при проведении вычислений, связанных с обработкой каждого подмножества, это дает возможность использовать частичные результаты предыдущих вычислений.
5.1Генерация всех подмножеств множества
Можно предложить следующий простой способ получения подмножеств, отличающихся друг от друга одним элементом. Пусть получены все m=2k бинарные последовательности длины k. Обозначим их через:
C1, C2, …, Cm-1, Cm
Причем Ci отличается от Ci+1 в точности в одной позиции бинарной последовательности. Тогда все бинарные последовательности длины k+1 могут быть получены приписыванием справ от каждой последовательности элементов 0 или 1. То есть получим
C10, C20, …, Cm-10, Cm0, Cm1, Cm-11, …, C21, C11
Этот алгоритм имеет рекуррентный характер, так как предполагает получение всех комбинаций сначала для k=1, затем для k=2 и т.д.
Ниже приводится не рекуррентный алгоритм генерации всех подмножеств исходного множества. Идею алгоритма можно вывести из следующего примера. Пусть длина исходной последовательности B равна 4. Обозначим через i десятичный номер генерируемой последовательности. Представим очередность получения последовательностей в следующем виде:
i = 0 0 0 0 0
i = 1 1 0 0 0
i = 2 1 1 0 0
i = 3 0 1 0 0
i = 4 0 1 1 0
i = 5 1 1 1 0
i = 6 1 0 1 0
i = 7 0 0 1 0
i = 8 0 0 1 1
i = 9 1 0 1 1
i = 10 1 1 1 1
i = 11 0 1 1 1
i = 12 0 1 0 1
i = 13 1 1 0 1
i = 14 1 0 0 1
i = 15 0 0 0 1
Можно заметить следующие закономерности:
В случае перехода к последовательности с нечетным номером (i ‑нечетно) в первой позиции (p=1) последовательности B происходит смена значения на противоположное.
В случае перехода к последовательности с четным номером (I ‑ четно) позиция p последовательности, в которой значение B[p] меняется на противоположное определяется следующим образом. Номер позиции p удовлетворяет условию: 2p-1 является наибольшей степенью числа 2, на которое делится число i. Ниже для четных значений номера последовательности i приведены соответствующие значения позиции p.
I |
p |
2 |
2 |
4 |
3 |
6 |
2 |
8 |
4 |
10 |
2 |
12 |
3 |
14 |
2 |
Приведенные замечания позволяют предложить следующий простой алгоритм генерации всех подмножеств.
program AllSubSets;
{Генерирует все подмножества N - элементного множества. Каждое подмножество представляется бинарной последовательностью B[1], B[2], ..., B[N]. Каждое последующее подмножество получается из предыдущего, добавлением или удалением единственного элемента.}
uses Crt;
const N = 4;
var B: array [1..N] of integer;
procedure SubSet;
var I: integer; {Номер очередной последовательности, подлежащей генерации}
P: integer; {Позиция элемента в массиве В, значение которого будет меняться с 0 на 1 или наоборот с 1 на 0}
J, K: integer;
begin
{Массив B обрабатывается (заполняется) слева направо путем смены значений отдельных его элементов с 0 на 1 и, наоборот, с 1 на 0}
for K := 1 to N do B [K] := 0; {Пустое множество}
I := 0; {Число сгенерированных до этого момента подмножеств}
repeat
Write (' ');
for K := 1 to N do Write (' ', B[K]);
Writeln;
I := I + 1; {Номер следующей последовательности, подлежащей генерации}
P := 1; {Начальное значение позиции Р для предстоящей генерации}
J := I;
while J mod 2 = 0 do
{Определяется Р - реальная позиция элемента массива, значение которого подлежит смене. Если I нечетно, то Р = 1. Если I четно, то после завершения всех итераций J - нечетно, а Р - степень числа 2, для которой выполняется J*2P-1 = I. Т.е. Р-1 это наибольшая степень числа 2, которая делит I нацело. Например, при I = 6 получим J = 3 и P-1 = 1}
begin
J := J div 2;
P := P + 1;
end;
if P <= N then B[P] := 1 - B[P]; {смена позиции P}
until P > N;
end;
begin
Clrscr;
SubSet;
end.
