Deja Vu #0A
30 сентября 2000

__________________________________________

(C) N.B.
__________________________________________

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

   Здесь рассматриваются только алгоритмы,
производящие сжатие без потерь, т.е. допу-
скающие восстановление  исходной  информа-
ции "байт в байт".

 Running -  Это  самый простой из  методов
            упаковки информации. Предполо-
жите, что Вы имеете строку текста,и в кон-
це строки стоит 40 пробелов. Налицо  явная
избыточность имеющейся информации. Пробле-
ма сжатия этой строки решается очень прос-
то - эти 40 пробелов ( 40 байт ) сжимаются
в 3 байта с помощью упаковки их  по методу
повторяющихся  символов  (running). Первый
байт, стоящий вместо 40 пробелов в  сжатой
строке, фактически, будет  являться пробе-
лом (последовательность была из пробелов).
Второй  байт - специальный  байт "флажка",
который указывает, что  мы  должны развер-
нуть предыдущий в строке байт в последова-
тельность при восстановлении  строки. Тре-
тий байт - байт счета (в нашем случае -это
будет 40). Как Вы сами можете видеть, дос-
таточно, чтобы любой раз, когда  мы  имеем
последовательность из более 3-х одинаковых
символов, заменять их выше описанной  пос-
ледовательностью, чтобы на выходе получить
блок информации меньший по размеру, но до-
пускающий  восстановление информации в ис-
ходном виде.
   Оставляя все сказанное  выше  истинным,
добавлю лишь то, что в данном  методе  ос-
новной проблемой является выбор того само-
го байта "флажка", так как в реальных бло-
ках  информации, как правило, используются
все 256 вариантов байта, и нет возможности
иметь 257-ой вариант - "флажок". На первый
взгляд эта проблема кажется  неразрешимой,
но к ней есть ключик, который Вы  найдете,
прочитав о кодировании с помощью алгоритма
Хаффмана ( Huffman ).

 LZW  -  История этого алгоритма начинает-
         ся с опубликования  в мае 1977 г.
Дж. Зивом (J. Ziv) и  А. Лемпелем (A. Lem-
pel) статьи в журнале "Информационные тео-
рии" под названием "IEEE Trans". В послед-
ствии,этот алгоритм был доработан Терри А.
Велчем (Terry A. Welch), и в окончательном
варианте отражен в статье "IEEE Compute" в
июне 1984. В этой статье описывались  под-
робности алгоритма и некоторые общие проб-
лемы, с которыми можно столкнуться при его
реализации. Позже  этот  алгоритм  получил
название - LZW (Lempel - Ziv - Welch).
   Алгоритм LZW представляет  собой  алго-
ритм кодирования последовательностей  нео-
динаковых символов. Возьмем, для  примера,
строку "Объект TSortedCollection  порожден
от TCollection.". Анализируя эту строку,мы
можем видеть, что слово "Collection"  пов-
торяется  дважды. В этом слове 10 символов
- 80 бит. И если мы  сможем  заменить  это
слово в выходном файле,во втором его вклю-
чении на ссылку на первое включение,то по-
лучим сжатие  информации. Если  рассматри-
вать входной блок информации  размером  не
более 64К и ограничиться  длиной  кодируе-
мой строки  в  256  символов, то, учитывая
байт "флаг", получим, что строка из 80 бит
заменяется  8+16+8 = 32 бита. Алгоритм LZW
как-бы "обучается" в процессе сжатия  фай-
ла. Если существуют повторяющиеся строки в
файле, то они будут закодированны в табли-
цу. Очевидным  преимуществом алгоритма яв-
ляется то, что нет необходимости  включать
таблицу кодировки  в  сжатый  файл. Другой
важной особенностью является то, что  сжа-
тие по алгоритму LZW является  однопроход-
ной операцией в противоположность алгорит-
му Хаффмана (Huffman), которому  требуется
два прохода.

 Huffman - Сначала  кажется, что  создание
           файла меньших  размеров из  ис-
ходного без кодировки  последовательностей
или исключения повтора байтов будет невоз-
можной задачей. Но давайте мы заставим се-
бя сделать несколько умственных  усилий  и
понять алгоритм  Хаффмана (Huffman). Поте-
ряв не так  много  времени, мы  приобретем
знания и дополнительное место на дисках.
   Сжимая файл по алгоритму Хаффмана, пер-
вое, что мы должны сделать - это необходи-
мо прочитать  файл полностью и подсчитать,
сколько раз встречается каждый  символ  из
расширенного  набора  ASCII. Если мы будем
учитывать все 256 символов, то для  нас не
будет  разницы  в  сжатии  текстового  или
другого файла.
   После подсчета частоты  вхождения  каж-
дого символа, необходимо просмотреть  таб-
лицу  кодов ASCII, и  сформировать  мнимую
компоновку между кодами по убыванию. Т.е.,
не меняя  местонахождение  каждого символа
из таблицы в памяти, отсортировать таблицу
ссылок на них по  убыванию. Каждую  ссылку
из последней таблицы  назовем  "узлом".  В
дальнейшем (в дереве) мы будем позже  раз-
мещать указатели, которые будут  указывать
на этот "узел". Для ясности  давайте  рас-
смотрим пример:

   Мы имеем файл длиной в 100 байт и имею-
щий 6 различных символов  в себе. Мы  под-
считали вхождение каждого  из  символов  в
файл и получили следующее:

    |-----------------|-----|-----|-----|-----|-----|-----|
    |     cимвол      |  A  |  B  |  C  |  D  |  E  |  F  |
    |-----------------|-----|-----|-----|-----|-----|-----|
    | число вхождений |  10 |  20 |  30 |  5  |  25 |  10 |
    |-----------------|-----|-----|-----|-----|-----|-----|

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

       ------------------------------------------
            cимвол       C   E   B   F   A    D  
       ------------------------------------------
        число вхождений  30  25  20  10  10   5  
       ------------------------------------------

   Мы возьмем из последней таблицы символы
с наименьшей частотой. В нашем случае -это
D (5) и какой-либо символ из F или A (10),
можно взять любой из них, например A.
   Сформируем из узлов D и A новый "узел",
частота вхождения для которого будет равна
сумме частот D и A :

Частота 30    10     5     10     20    25
Символа  C     A     D      F      B     E
                    
               ----
                 -
                 15  = 5 + 10
                 --

   Номер в рамке - сумма частот символов D
и A. Теперь мы снова ищем  два  символа  с
самыми низкими частотами вхождения. Исклю-
чая  из  просмотра  D и A  и  рассматривая
вместо них новый "узел" с суммарной часто-
той вхождения. Самая низкая частота теперь
у F и нового "узла".Снова сделаем операцию
слияния узлов:

Частота 30    10     5     10    20     25
Символа  C     A     D      F     B      E
                          
                          
                ?--      
               -15      
                 -       
                           
                      ?-- 
                  ----25- = 10 + 15
                       --

   Рассматриваем таблицу снова для следую-
щих двух символов ( B и E ). Мы продолжаем
этот режим пока все "дерево" не  сформиро-
вано, т.е. пока все не сведется  к  одному
узлу.

Частота 30    10     5     10    20    25
Символа  C     A     D      F     B     E
                                   
                                   
               ?--                
              -15                
                -                 
                                    
                     ?--       ?---
                 ----25-     -45-
                      -         -
             ?--                  
         ----55------            
              -                   
                   ------------   
                --- Root (100) ---
                    ------------

   Теперь, когда наше  дерево  создано, мы
можем кодировать файл.Мы должны всегда на-
чинать  из корня ( Root ). Кодируя  первый
символ (лист  дерева  С), мы  прослеживаем
вверх по дереву все повороты ветвей, и,ес-
ли мы делаем левый поворот, то  запоминаем
0-й бит, и аналогично 1-й бит  для правого
поворота. Так для C, мы будем идти влево к
55 ( и запомним 0 ), затем снова влево (0)
к самому символу. Код  Хаффмана для нашего
символа C - 00. Для следующего символа (А)
у нас получается -лево, право, лево, лево,
что выливается в последовательность  0100.
Выполнив  вышесказанное для всех  символов
получим:

           C = 00   ( 2 бита )
           A = 0100 ( 4 бита )
           D = 0101 ( 4 бита )
           F = 011  ( 3 бита )
           B = 10   ( 2 бита )
           E = 11   ( 2 бита )

   Каждый символ изначально  представлялся
8-ю битами ( один байт ), и т.к. мы умень-
шили число битов,необходимых для представ-
ления каждого  символа, мы, следовательно,
уменьшили размер  выходного  файла. Сжатие
складывется следующим образом:

-----------------------------------------------------------
 Частота    первоначально   уплотненные биты  уменьшено на 
-----------------------------------------------------------
  C 30      30 x 8 = 240      30 x 2 = 60          180     
  A 10      10 x 8 =  80      10 x 3 = 30           50     
  D 5        5 x 8 =  40       5 x 4 = 20           20       F 10      10 x 8 =  80      10 x 4 = 40           40     
  B 20      20 x 8 = 160      20 x 2 = 40          120     
  E 25      25 x 8 = 200      25 x 2 = 50          150     
-----------------------------------------------------------

   Первоначальный размер файла: 100 байт -
800 бит;
   Размер сжатого файла:30 байт - 240 бит;

   240 - 30% из 800, так что мы сжали этот
файл на 70%.

   Все это довольно хорошо,но неприятность
находится в том факте,что для восстановле-
ния первоначального файла, мы должны иметь
декодирующее дерево, так как деревья будут
различны для разных файлов. Следовательно,
мы должны сохранять дерево вместе  с  фай-
лом. Это превращается в итоге в увеличение
размеров выходного файла.
   В  нашей  методике сжатия и каждом узле
находятся 4 байта указателя,поэтому полная
таблица для 256 байт будет  приблизительно
1 Кбайт длиной.

   Таблица в нашем примере  имеет  5 узлов
плюс 6 вершин (где и находятся наши симво-
лы), всего 11. 4  байта  11 раз - 44. Если
мы добавим после небольшое количество бай-
тов для  сохранения места узла и некоторую
другую статистику -наша таблица будет при-
близительно 50 байтов длины.
   Добавив к 30 байтам  сжатой  информации
50  байтов  таблицы - получаем, что  общая
длина архивного файла вырастет до 80 байт.
Учитывая, что первоначальная длина файла в
рассматриваемом примере была 100 байт - мы
получили 20% сжатие информации.
   Не плохо. То что мы  действительно  вы-
полнили - трансляция символьного ASCII на-
бора в наш новый набор, требующий  меньшее
количество знаков по сравнению с стандарт-
ным.
   Что мы можем получить на этом пути?
   Рассмотрим максимум,  который мы  можем
получить для различных разрядных  комбина-
ций в оптимальном дереве, которое является
несимметричным.
   Мы получим, что можно иметь только:
          4 - 2 разрядных кода;
          8 - 3 разрядных кодов;
         16 - 4 разрядных кодов;
         32 - 5 разрядных кодов;
         64 - 6 разрядных кодов;
        128 - 7 разрядных кодов;

   Необходимо еще два 8-разрядных кода.

          4 - 2 разрядных кода;
          8 - 3 разрядных кодов;
         16 - 4 разрядных кодов;
         32 - 5 разрядных кодов;
         64 - 6 разрядных кодов;
        128 - 7 разрядных кодов;
                 --------
                   254

   Итак, мы имеем итог  из  256  различных
комбинаций,которыми можно кодировать байт.
Из этих комбинаций лишь 2 по длинне  равны
8 битам.
   Если мы сложим число битов, которые это
представляют, то в итоге получим  1554 бит
или 195 байтов. Так, в максимуме, мы сжали
256 байт к 195 или 33%, таким образом мак-
симально  идеализированный  Huffman  может
достигать сжатия в 33%, когда используется
на уровне байта.
   Все эти подсчеты производились  для  не
префиксных кодов Хаффмана, т.е. кодов, ко-
торые  нельзя идентифицировать однозначно.
Например,код A - 01011 и код B - 0101. Ес-
ли мы будем получать эти  коды побитно,то,
получив биты 0101, мы  не  сможем  сказать
какой код мы получили - A или B, т.к. сле-
дующий бит может быть как началом  следую-
щего кода, так и продолжением предыдущего.
   Необходимо добавить, что ключем к пост-
роению префиксных кодов служит обычное би-
нарное дерево, и,если внимательно рассмот-
реть предыдущий пример с построением дере-
ва, можно убедиться,что все получаемые ко-
ды там префиксные.
   И последнее примечание - алгоритм  Хаф-
фмана требует читать входной файл  дважды,
один раз считая частоты вхождения символов
и другой  раз, производя, непосредственно,
кодирование.

P.S. О "ключике", дающем  дорогу алгоритму
     Running. Прочитав обзорную информацию
     о Huffman-кодировании, подумайте  над
     тем, что на нашем бинарном дереве мо-
     жет быть и 257 листиков.
------------------------------------------



Other articles:


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Similar articles:
kodit Who's there? - Guru meditates: optimization programs for execution time and size.
Advertising - the motor trade.
Tips - the lexicon of good manners. The problems of etiquette.
Studies - Playback software tool from the editors of digitized music.

В этот день...   23 November