
- •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Процедуры поиска на бинарных деревьях
- •Рекомендованная литература
Var k: integer; {Количество нулей в кортеже}
M: integer; {Количество нулей в кортеже}
I: integer;
GB: Arr;
Finish: boolean;
procedure SubSet (var LB: Arr; NM: integer; var Finish: boolean);
Var I, j, p: integer;
Z: integer; {Количество хвостовых нулей}
P: integer; {Количество хвостовых единиц, предшествующих хвостовым нулям }
begin
J := N; {Движение от конца массива LB к его началу}
while LB[J] <> 1 do J := J - 1; {Пропуск хвостовых нулей}
Z := N - J + 1; {Подсчет количества хвостовых нулей z плюс 1, т.е. Z = z+1}
P := 0;
J := J - 1;{Корректировка возможного количества 1}
while (J <> 0) and (LB[J] <> 0) do {Подсчет количества хвостовых единиц p минус 1 (т.е. P = p-1), предшествующих z хвостовым нулям}
begin
P := P + 1;
J := J - 1;
end;
if J = 0 then{Получена конечная перестановка 1 1 1 0 0}
begin
Finish := true;
Exit;
end;
{Формирование новой перестановки}
LB[J] := 1; {Размещение новой 1}
for I := 1 to Z do {Размещение группы z+1 нулей}
begin
J := J + 1;
LB[J] := 0;
end;
if P = 0 then Exit; {Если была всего одна 1}
for I := 1 to P do {Размещение группы p-1 единиц}
begin
J := J + 1;
LB [J] := 1;
end;
Exit;
end; {SubSet}
begin
Clrscr;
Write ('Введите количество членов подмножества (меньше ', N, ' ) -> ');
Readln (K);
M := N - K; {Действительное количество нулей в кортеже}
{Исходное состояние массива GB - исходный кортеж}
for I := 1 to M do GB[I] := 0;
for I := M + 1 to N do GB[I] := 1;
Write (' ');
for I := 1 to N do Write (' ', GB[I]);
Writeln;
{Генерация остальных кортежей}
Finish := false;
while true {not Finish} do
begin
SubSet (GB, M, Finish);
If Finish then Break {Exit};
Write (' ');
for I := 1 to N do Write (' ', GB[I]);
Writeln;
end;
end.
6Генерация разбиений
6.1Разбиение целых чисел
Задача разбиения целых чисел сводится к определению количества способов, с помощью которых можно записать заданное число N в виде суммы
N = a1 + a2 + ai, +… + ak,
где i, k, a1, a2, …, ai,…, ak > 0 и записи, отличающиеся только порядком слагаемых, рассматриваются как одна запись.
Пусть N =4. Тогда получим следующие разбиения
4
3 1
2 2
2 1 1
1 1 1 1
Ниже приводится текст программы DivideN, которая генерирует все перестановки числа N. Для представления разбиения числа программа использует массивы SS и RR. В массиве SS содержится набор попарно различных слагаемых, образующих число N. Эти слагаемые (элементы массива SS) упорядочены по убыванию. В массиве RR содержится количество вхождений каждого соответствующего слагаемого в число N. Например, для разбиения:
2 2 получим SS[1] = 2, а RR[1] =2;
2 1 1 получим SS[1] =2 и SS[2]= 1, а RR[1] = 1 и RR[2] = 2.
Каждое новое разбиение строится на основе предыдущего разбиения. В текущем разбиении отыскивается элемент SS[d], такой что
d = max{i: SS[i] > 1}
т.е. самый правый элемент в массиве SS больший 1. Это может быть последний или предпоследний элемент разбиения.
Случай, когда SS[d] является последним элементом разбиения. Тогда проверяется RR[d] - количество вхождений значения этого элемента в разбиение. Если значение SS[d] входит в разбиение несколько раз, т.е. RR[d] > 1, то количество его вхождений уменьшается на 1
RR[d] := RR[d] – 1
а выделенное вхождение, в зависимости от его значения, представляется с помощью комбинации
SS[d+1] и RR[d+1]
или комбинации
SS[d+1], SS[d+2] и RR[d+1], RR[d+2].
Примечание. Способ получения значений для приведенных комбинаций легко понять при рассмотрении текста приведенной ниже программы.
Пусть N = 10 и задано разбиение, где d = 2:
|
1 |
2 |
SS |
4 |
2 |
RR |
1 |
3 |
Тогда новое разбиение будет иметь вид:
|
1 |
2 |
3 |
SS |
4 |
2 |
1 |
RR |
1 |
2 |
2 |
т.е. добавилась комбинация SS[3] и RR[3]
Пусть теперь задано разбиение, где d = 2:
|
1 |
2 |
SS |
4 |
3 |
RR |
1 |
2 |
Тогда новое разбиение будет иметь вид:
|
1 |
2 |
3 |
4 |
SS |
4 |
3 |
2 |
1 |
RR |
1 |
1 |
1 |
1 |
т.е. добавилась комбинация SS[3], RR[3] и SS[4], RR[4]
Если значение SS[d] входит в разбиение один раз, т.е. RR[d] = 1, то SS[d] уменьшается на 1
SS[d] := SS[d] – 1
а RR[d] устанавливается в 1
RR[d] := 1
Здесь возникает вопрос, куда отнести оставшуюся после вычитания 1. Если до уменьшения SS[d] имело место SS[d] > 2, то формируется
SS[d+1] := 1 и RR[d+1] := 1
В противном случае
SS[d] := 1 и RR[d] := 2.
Пусть задано разбиение, где d = 2:
|
1 |
2 |
SS |
7 |
3 |
RR |
1 |
1 |
Тогда новое разбиение будет иметь вид
|
1 |
2 |
3 |
SS |
7 |
2 |
1 |
RR |
1 |
1 |
1 |
т.е. добавилась комбинация SS[3] и RR[3].
Пусть теперь задано разбиение, где d = 2:
|
1 |
2 |
SS |
8 |
2 |
RR |
1 |
1 |
Тогда новое разбиение будет иметь вид:
|
1 |
2 |
SS |
8 |
1 |
RR |
1 |
2 |
т.е. выполнена корректировка комбинации SS[3] и RR[3].
Случай, когда SS[d] является предпоследним элементом разбиения. Тогда SS[d+1] = 1, а RR[d+1] равно количеству вхождений 1 в разбиение. В этом случае запоминается содержимое т.е. сохраняется количество 1 в разбиении
Sum := RR[d+1]
а сама комбинация SS[d+1] и RR[d+1] удаляются из разбиения. Фактически задача сводится к рассмотренному выше случаю, когда SS[d] является последним элементом разбиения, но со следующими изменениями - из разбиения изымается один из элементов SS[d], а количество его вхождений в разбиение RR[d] уменьшается на 1
RR[d] := RR[d] – 1
Изъятый элемент суммируется с сохраненным количеством 1 в разбиении. Далее возможны два варианта продолжения в зависимости от полученного значения RR[d]:
если RR[d] = 0, то модифицируется комбинация
SS[d] и RR[d]
и, в зависимости от значения полученной суммы, может добавиться комбинация
SS[d+1] и RR[d+1]
если RR[d] <> 0, то модифицируется комбинация
SS[d] и RR[d]
и, в зависимости от значения полученной суммы, может добавиться комбинация
SS[d+1] и RR[d+1]
или комбинации
SS[d+1], SS[d+2] и RR[d+1], RR[d+2].
Пусть задано разбиение, где d = 2:
|
1 |
2 |
3 |
SS |
6 |
2 |
1 |
RR |
1 |
1 |
2 |
Тогда новое разбиение будет иметь вид:
|
1 |
2 |
SS |
6 |
1 |
RR |
1 |
4 |
и модифицируется комбинация SS[2] и RR[2].
Пусть задано разбиение, где d = 2:
|
1 |
2 |
3 |
SS |
5 |
4 |
1 |
RR |
1 |
1 |
1 |
Тогда новое разбиение будет иметь вид:
|
1 |
2 |
3 |
SS |
5 |
3 |
2 |
RR |
1 |
1 |
1 |
и модифицируется комбинация SS[2] и RR[2], а также заново вводится комбинация SS[3] и RR[3].
Пусть задано разбиение, где d = 2:
|
1 |
2 |
3 |
SS |
5 |
2 |
1 |
RR |
1 |
2 |
1 |
Тогда новое разбиение будет иметь вид:
|
1 |
2 |
3 |
SS |
5 |
2 |
1 |
RR |
1 |
1 |
3 |
и заново вводится комбинация SS[3] и RR[3].
В программе предусмотрены два способа вывода результата. Первый способ задается парой вызовов Output1(S) и Output1(R). В результате выводится содержимое массивов – SS и RR соответственно. Второй способ задается вызовом Output2(S, R). В результате выводится разбиение числа в виде:
N = a1 + a2 + ai, +… + ak
Текст программы приводится ниже.
program DivideN;
{Генерирует все разбиения числа N}
uses Crt;
const N = 8;
type TArr = array [1..N] of integer;