
- •Var X: ссылка;
- •Var X: ссылка;
- •Var X: ссылка;
- •Процедура “Поиск по дереву с включением”.
- •Символ Код
- •Символ Код
- •Символ Частота Код
- •Метод Шелла
- •Получаем ряд приращений 1,4,13,40,121…
- •Слияние – означает объединение двух или более упорядоченных файлов в один упорядоченный файл.
- •Сортировка посредством слияния списков
Символ Код
А 010
B 100
C 000
D 111
Сообщение ABACCDA кодируется как 010100010000000111010. Однако такая кодировка была бы неэффективной, поскольку для каждого символа используются 3 бит, так что для кодировки всего сообщения требуется 21 бит. Предположим, что каждому символу назначен 2-битовый код:
Символ Код
А 00
B 01
C 10
D 11
Тогда кодировка сообщения была бы 00010010101100; требуется лишь 14 бит. Мы хотим найти код, который минимизирует длину закодированного сообщения.
Рассмотрим наш пример еще раз. Каждая из букв B и D появляется в сообщении только один раз, а буква A — три раза. Стало быть, если выбран код, в котором букве A назначена более короткая строка битов, чем буквам B и D, то длина закодированного сообщения будет меньше. Это происходит оттого, что короткий код (представляющий букву А) появляется более часто, чем длинный. В самом деле, коды могут быть назначены следующим образом:
Символ Частота Код
А 3 0
B 1 110
C 2 10
D 1 111
При использовании этого кода сообщение ABACCDA кодируется как 0110010101110, что требует лишь 13 бит. В очень длинных сообщениях, которые содержат символы, встречающиеся чрезвычайно редко, экономия существенна. Обычно коды создаются не на основе частоты вхождения символов в отдельно взятом сообщении, а на основе их частоты во всем множестве сообщений. Для каждого сообщения используется один и тот же код. Например, если сообщения состоят из английских слов, могут использоваться известные данные о частоте появления символов алфавита в английском языке.
Отметьте, что если используются коды переменной длины, то код одного символа не должен совпадать с началом кода другого символа. Такое условие должно выполняться, если раскодирование происходит слева направо. Если бы код символа x—c(x) совпадал с началом кода символа y—c(y), то, когда встречается код c(x), неясно, является ли он кодом символа x или началом кода c (y).
В нашем случае битовая строка сообщения просматривается слева направо. Если первый бит равен 0, то это символ A; в противном случае это B, С или D и проверяется следующий бит. Если второй бит равен 0, то это символ C, иначе это B или D и надо проверить третий бит. Если он равен 0, значит это B, а если 1, то D. Как только распознан первый символ, процесс повторяется для нахождения второго символа, начиная со следующего бита.
Такая операция подсказывает метод реализации оптимальной схемы кодирования, если известны частоты появления каждого символа в сообщении. Находим два символа, появляющихся наименее часто. В нашем примере это B и D. Будем различать их по последнему биту кодов: 0—В, 1—D. Соединим эти символы в единый символ BD, появление которого означает, что это либо символ B, либо символ D. Частота появления этого нового символа равна сумме частот двух составляющих символов. Стало быть, частота BD — 2. Теперь у нас есть три символа: А (частота 3), C (частота 2) и BD (частота 2). Снова выберем два символа с наименьшей частотой, т. е. C и BD. Будем различать их по последнему биту кодов: 0 — С, 1 — BD. Затем два символа объединяются в один символ CBD с частотой 4. К этому времени осталось только два символа — А и CBD. Они объединяются в один символ ACBD. Будем различать их по последнему биту кодов: 0 — А, 1 — CBD.
Символ ACBD содержит весь алфавит, ему присваивается в качестве кода пустая строка битов нулевой длины. Это означает, что вначале раскодирования до момента проверки какого-либо бита известно, что этот символ содержится в ACBD. Двум символам, составляющим ACBD (А и CBD), присваиваются соответственно коды 0 и 1: если встречается 0, значит, закодирован символ A, а если 1, то это C, B или D. Аналогично двум символам, составляющим CBD (С и BD), назначаются соответственно коды 10 и 11. Первый бит указывает, что символ входит в группу CBD, а второй позволяет отличить C и BD. Символам, составляющим BD (В и D), назначаются соответственно коды 110 и 111. Следуя этому процессу, символам, которые появляются в сообщении часто, присваиваются более короткие коды, чем тем, которые встречаются редко.
Операция объединения двух символов в один предполагает использование структуры бинарного дерева. Каждый лист представляет символ исходного алфавита. Каждый узел, не являющийся узлом, представляет соединение символов из листов — потомков данного узла. На рис. 1a приведено бинарное дерево, построенное с использованием предыдущего примера. Каждый узел содержит символ и его частоту. На рис. 1b показано бинарное дерево, построенное по данному методу для приведенной на рис. 1c таблицы символов алфавита и частот. Такие деревья называют деревьями Хаффмена, по имени изобретателя этого метода кодирования.
Как только дерево Хаффмена построено, код любого символа алфавита может быть определен просмотром дерева снизу вверх, начиная с листа, представляющего этот символ. Начальное значение кода — пустая строка. Каждый раз, когда мы поднимаемся по левой ветви, к коду слева приписывается 0; каждый раз при подъеме по правой ветви к коду приписывается 1.
b
Символ Частота Код |
Символ Частота Код |
Символ Частота Код |
A 15 111 B 6 0101 C 7 1101 |
A 12 011 B 25 10 C 4 01001 |
A 6 1100 B 1 01000 C 15 00 |
1c
Рис. 1. Деревья Хаффмена.
Отметьте, что дерево Хаффмена строго бинарное. Следовательно, если в алфавите n символов, то дерево Хаффмена (у которого n листьев) может быть представлено массивом узлов размером 2n-1. Поскольку размер памяти, требуемой под дерево, известен, она может быть выделена заранее. Отметим также, что дерево Хаффмена проходится от листьев к корню. Отсюда следует, что не требуются поля LEFT и RIGHT, и для представления структуры дерева достаточно одного поля FTHER. Знак поля FTHER может использоваться для определения, является ли узел левым или правым сыном, а абсолютное значение поля служит указателем отца узла. Левый сын имеет отрицательное значение поля FTHER, а правый — положительное.
Исходное сообщение (при наличии кодировки сообщения и дерева Хаффмена) может быть восстановлено следующим способом. Начинаем с корня дерева. Каждый раз, когда встречается 0, двигаемся по левой ветви, и каждый раз, когда встречается 1, двигаемся по правой ветви. Повторяем этот процесс до тех пор, пока не дойдем до листа. Новый символ исходного сообщения есть символ, соответствующий этому листу. Проверьте, можете ли вы раскодировать строку 1110100010111011, используя дерево Хаффмена на рис. 1b.
Сортировка. Методы вставок и обмена. Метод Шелла. Быстрая сортировка. Обменная поразрядная сортировка.