Skip to main content

Теория

Единицы измерения

Любая информация, хранящаяся на компьютере, представлена в двоичном коде. Её размер определяется кол-вом занятых бит. Бит - это наименьшая величина хранения информации, может принимать одно из двух значений: 0 или 1.

Биты объединяются в байты, в одном байте помещается 8 бит

1байт=23бит1 \text{байт}=2^3 \text{бит}

В отличие от физических величин, все производные од байта отличаются между собой не в 10310^3 раз, как килограмм и грамм, а в 2102^{10} раз.

Поэтому

1Кбайт=210байт=213бит1 \text{Кбайт}= 2^{10}\text{байт} = 2^{13}\text{бит}
1Мбайт=210Кбайт=220байт=223бит1 \text{Мбайт} = 2^{10}\text{Кбайт}=2^{20}\text{байт}=2^{23}\text{бит}

При передаче информации можно измерить её скорость vv. Она равна частному между объёмом переданной информации oo и временем её передачи tt

v=ntv = \frac{n}{t}

Если количество информации измерялось в битах, то скорость будет измерять в бит/с.

Большие числа. Что делать?

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

128=27, 256=28, 512=29, 1024=210,128 = 2^7, ~ 256 = 2^8, ~ 512 = 2^9 ,~ 1024 = 2^{10},
2048=211, 4096=212, 8192=213, 16384=214, 65536=2162048 = 2^{11}, ~4096 = 2^{12}, ~8192 = 2^{13},~ 16384 = 2^{14},~ 65536 = 2^{16}

Нужно помнить, что соотношение между единицами измерения количества информации также представляют собой степени двойки:

11 байт = 88 бит = 2323 бит,

11 Кбайт = 10241024 байта = 2102^{10} байта = 210232^{10} * 2^{3} бит = 2132^{13} бит

11 Мбайт = 10241024 Кбайта = 2102^{10} Кбайта = 2102102^{10} * 2^{10} байта = 2202^{20} байта= 220232^{20} * 2^{3} бит = 2232^{23} бит

при умножении степени при одинаковых основаниях складываются

2a2b=2a+b2^a*2^b=2^{a+b}

а при делении – вычитаются:

2a/2b=2ab2^a/2^b=2^{a-b}

Кодирование информации

При кодировании данных, т.е. переводе из понятных человеку данных в биты используется два рода кодирования: первый - это равномерный двоичный, второй - неравномерный.

Равномерный код

В программировании для хранения переменных используется так называемый равномерный двоичный код. Под каждую переменную массива выделяется одинаковое количество бит, кратное 8. Иначе говоря, под каждую переменную выделяется целое количество байт.

расстояния Хэмминга

Для двух равномерных кодов можно определить количество позиций, в которых одно кодовое слово отличается от другого. Эту величину называют расстояние Хэмминга.

Например, коды 101 и 111 имеют расстояние Хэмминга, равное одному, коды 1100 и 0110 - равное двум.

Неравномерный код

Если набор значений заранее предопределён, то каждому из них можно сопоставить свой уникальный двоичный код (последовательность бит), причём коды у значений могут иметь разную длину.

Тогда, читая биты последовательно, можно восстановить, какому значению соответствует та или иная последовательность. При этом наиболее часто встречаемым значениям мы можем связать с "короткими" последовательностями, а редко встречаемые - с "длинными". Это позволит нам ещё больше сэкономить память. На этом принципе построены многие архиваторы.

условие Фано

Правда, для однозначной интерпретации кодов, необходимо, чтобы каждый код не является такой последовательностью битов, с которой начинается какой-либо другой код. Это условие называется прямым условием Фано.

Это требование неслучайно. Если один код является началом другого, то в момент его чтения возникает неоднозначное поведение. Ведь мы читаем биты последовательно. После прочтения очередного бита программе будет неясно, что делать: толи нужно решить, что этот код закончился и надо читать следующий, толи нужно дочитать код до конца.

В задачах егэ условие Фано иногда трактуется так: все коды находятся в листьях дерева, т.е. в вершинах, из которых не выходит ни одного ребра

Например, если у нас есть четыре буквы A, B, C, D и при этом коды первых трёх мы определили так:

ABC
1011001

то код буквы D не может быть 00, потому что 00 уже содержится в коде C, 11 - недопустимо, потому что содержится в коде B

Однако, если мы поменяем все коды на трёхзначные

ABC
100110010

Тогда для D будет доступен код 00.

Подбирать вручную коды для разных элементов - довольно трудоёмкая задача. Для этого существует готовый алгоритм. Он называется Алгоритм Хаффмана.

Правда в оригинальном алгоритме символы строки сначала сортируются, а потом на их основе строится дерево декодирования. В задачах ЕГЭ даётся просто последовательность букв, и на её основе требуется построить дерево декодирования и что-то о нём сказать.

В блоке теории рассмотрим алгоритм Хаффмана полностью, а в примерах, будем использовать только ту часть, которая работает уже с отсортированными по частоте встречаемости буквами. Сам алгоритм способен работать с любыми данными, однако в случае строки - получается наиболее наглядно.

Допустим, мы хотим закодировать строку "Carpe diem, memento mori!". Если на каждый символ мы выделим по 1 байту, то вся строка при использовании равномерного двоичного кода занимала бы 25 байт или 25*8=200 бит, т.к. её длина равна 25.

Для начала посчитаем частоты всех символов:

Carpe dim,nto!
11214312411121

Напомню, дерево декодирования - это в первую очередь дерево, т.е. граф, не имеющий циклов. Помимо этого, у дерева декодирования из каждой вершины может выходить не больше двух рёбер.

Чтобы построить такое дерево, составим новую таблицу, упорядочив встречаемость по возрастанию. Дальше встречаемость будем называть просто весом.

xor

Символом

xor

обозначается пробел.

Общая идея построения дерева такая: мы берём две вершины с самым малым весом, выкидываем их из списка и добавляем новый элемент, имеющий вес, равный сумме двух выкинутых в список так, чтобы он оставался упорядоченным.

На первом шаге необходимо выкинуть символы C и A.

xor

Таким же образом соединим оставшиеся вершины с весом 1.

xor

Теперь объединим первые два элемента с весом 2

xor

Снова объединим первые два элемента весом 2

xor

И объединим оставшиеся

xor

Теперь первые два элемента имеют вес 2 и 3, объединим их в элемент весом пять и поставим в самый конец, т.к. веса остальных элементов меньше

xor

Снова объединим первые два элемента

xor

Первые два элемента имеют вес 4 и 5, при объединении они дадут вес 9, поэтому полученный новый элемент нужно будет перенести в конец списка

xor

В списке элементов осталось всего три, объединяем два первых элемента, т.к. у третьего вес больше в силу отсортированности списка

xor

После объединения осталось два элемента, их останется только собрать в единое дерево

xor

Итоговое дерево будет выглядеть так

xor

Чтобы оно стало деревом декодирования, необходимо на каждом ветвлении расставить по 0 и 1

xor

Теперь, чтобы получить код того или иного символа, нужно просто пройти от единого корня дерева (самая верхняя вершина) до нужной нам. При переходе от одной вершины к другой необходимо добавлять в код то число, которое написано на соответствующем ребре.

Например, буква e будет иметь код 100

Таким же образом определим остальные коды:

Carpe dim,nto!
1101011011101011100100011111011011000111111110010101011