Anda di halaman 1dari 27

1

1. Tcnicas de diccionario
1.1. Generalidades

Se miran tcnicas que incorporan la estructura de los datos para incrementar


la cantidad de compresin.
Estas tcnicas construyen una lista de patrones que ocurren frecuentemente
y las codifican para transmitir su ndice en la lista.
Ms tiles con fuentes que generan un nmero relativamente pequeo de
patrones muy frecuentemente.

1.2. Introduccin

Muchas aplicaciones en las que las fuentes generan patrones recurrentes


(Ej.: texto).
Hay otros patrones que casi nunca ocurren.
Aproximacin: conservar una lista o diccionario de patrones recurrentes y
cuando estos aparecen se codifican con referencia al diccionario. Si el patrn
no est en el diccionario entonces puede ser codificado usando algn otro
mtodo menos eficiente. Para que esta lista sea efectiva la clase de patrones
que ocurren frecuentemente y por tanto el tamao del diccionario debe ser
mucho ms pequeo que el nmero de todos los posibles patrones.

Ejemplo:
Suponga que tenemos un texto particular que consiste en palabras de cuatro
caracteres. Tres caracteres de las 26 letras minsculas del alfabeto ingls seguidas de una
marca de puntuacin (coma, punto, exclamacin, interrogacin, punto y coma y dos
puntos). En otras palabras, el tamao del alfabeto de entrada es 32. Si furamos a
codificar el texto fuente un carcter al tiempo, tratando cada carcter como un evento
igualmente probable, necesitaramos . Tratando todos los 324 =
1048576 patrones de cuatro caracteres como igualmente probables, tendramos un
cdigo que asignara 20 a cada patrn de cuatro caracteres.
Pongamos ahora los 256 patrones de cuatro caracteres ms probables en un
diccionario. El esquema de transmisin funciona como sigue: siempre que deseemos
enviar un patrn que exista en el diccionario enviaremos un bit bandera, digamos un 0,
seguido por un ndice de correspondiente a la entrada en el diccionario. Si el patrn
no se encuentra en el diccionario enviaremos un 1 seguido de que codifican el
patrn. Si el patrn que encontramos no est en el diccionario, nosotros enviaremos
realmente ms bits que en el esquema original, en vez de . Pero si est en el
diccionario enviaremos solo . La utilidad de nuestro esquema depender del
porcentaje de palabras que encontramos que est en el diccionario. Podemos tener una
idea acerca de la utilidad de nuestro esquema calculando el nmero promedio de bits por
patrn.
Si la probabilidad de encontrar un patrn del diccionario es , entonces el nmero
promedio de / esta dado por:
= + ( ) =

2
Para que nuestro esquema sea til, debera tener un valor inferior a . Esto sucede
cuando . . Esto no parece como un nmero muy grande. Sin embargo observe
que si todos los patrones ocurrieran en una manera igualmente probable, la probabilidad
de encontrar un patrn del diccionario sera menor que .
De acuerdo con este ejemplo si se quiere mejorar mucho el desempeo se debe aumentar
la probabilidad de que la secuencia est en el diccionario tanto como sea posible, o sea
que las entradas del diccionario deben ser cuidadosamente escogidas. Para lograr esto
se debe tener una muy buena idea del comportamiento de la fuente o de lo contrario
debemos estar en capacidad de obtener esta informacin de alguna manera.
Dependiendo de si conocemos previamente el comportamiento de la fuente o no, hay dos
maneras de construir el diccionario: si se conoce dicho comportamiento se puede
construir un diccionario esttico y de lo contrario se pude construir un diccionario
adaptativo.
1.3. Diccionario esttico
Construir un diccionario esttico es ms apropiado cuando se tiene un conocimiento a
priori del comportamiento de la fuente. Este mtodo es especialmente apropiado de usar
en aplicaciones especficas.
Ejemplo:
Compresin de los datos de estudiantes de la universidad.
Se tiene la certeza de que datos como el nombre, la identidad, etc. aparecern en todos
las fichas. Dependiendo de la ubicacin geogrfica ciertos dgitos de la tarjeta de
seguridad social son ms probables.
Los diccionarios generados para esta aplicacin no trabajaran bien en otros casos y por el
contrario podran causar una expansin en vez de una compresin.
1.3.1. Codificacin digrama
Es una tcnica que es menos especfica a una aplicacin. Esta tcnica consiste en un
diccionario formado por todas las letras del alfabeto de la fuente seguida de tantos pares
de letras (digramas) como sea posible de acomodar en el diccionario.
Ejemplo:
Construccin de un diccionario de de todos los caracteres
imprimibles. Las primeras son los caracteres imprimibles y el resto
seria los ms frecuentes.
El codificador digrama lee dos caracteres de entrada y busca el diccionario para ver si
existe la entrada en el diccionario. Si lo es se codifica el ndice correspondiente y se enva,
si no est se codifica el primer carcter del par. El segundo carcter se convierte en el
primer carcter del siguiente digrama. El codificador lee el siguiente carcter para
completar un digrama y se repite el procedimiento.

3
Ejemplo:
Supongamos que tenemos una fuente con un alfabeto de cinco letras = {, , , } ,
basados en el conocimiento que tenemos acerca de la fuente, construimos el diccionario
mostrado en la tabla 1:
Cdigo Entrada Cdigo Entrada

Tabla 1: Un diccionario de muestra


Supongamos que deseamos codificar la secuencia .
En las tablas se muestran los treinta pares de caracteres ms frecuentes en un texto
en y en un programa en .
Par Conteo Par Conteo

Tabla 2: pares de caracteres que ocurren ms frecuentemente en un documento en


de caracteres
Par

Conteo

Par Conteo

4
):
.

Tabla 3: 30 pares de caracteres en una coleccin de programas en que contienen


caracteres
1.4. Diccionario adaptativo
y en y propusieron tcnicas de construccin
de diccionarios adaptativos llamadas y .
1.4.1. La aproximacin
En este caso el diccionario es una porcin de la secuencia previamente codificada. Se
utiliza una ventana deslizante (ilustracin 1) que contiene dos partes:
El buffer de bsqueda que contiene una porcin de la secuencia previamente
codificada
El buffer de que contiene la prxima porcin de la secuencia a ser
codificada.

Ilustracin 1: ventana deslizante en


Se codifica enviando una tripleta , , en donde:
Se denomina el offset y es la distancia ms larga entre los caracteres que concuerdan
entre los dos bferes.
Es el nmero de caracteres que coinciden en los dos bferes.
Es el cdigo del siguiente carcter luego del acople. Este se enva por si la longitud
de la secuencia es cero o sea que no coincide en la comparacin, es decir si es un carcter
nuevo.
Si el tamao del bfer de bsqueda es , el tamao de la ventana completa es y el
tamao del alfabeto de la fuente es , entonces el tamao para codificar la tripleta es
+ +

5
Esto se debe a que la longitud del acople puede ser superior a la ventana de bsqueda.
Ejemplo:
Suponga que se quiere codificar la secuencia

Suponga adems que la longitud de la ventana es , el tamao del buffer de bsqueda
es y que la condicin corriente es como sigue:

Para codificar la , se puede ver que no hay acople y por lo tanto se transmite la tripleta
, , ()

Ilustracin 2: codificacin del ejemplo


La siguiente a tiene acoples de longitudes , respectivamente. La longitud del
acople en este ltimo caso es y por tanto se enva la tripleta , , () , desplazando
la ventana queda as:

La tripleta en este caso toma la forma , , () .
La decodificacin:
Para ver cmo funciona la decodificacin, asumamos que se ha decodificado la secuencia
y que se recibe las tripletas , , (), , , () , , (). La
primera tripleta es fcil de decodificar; no hubo acople con la tira previamente
decodificada y el prximo smbolo es . La tira decodificada ahora es . El
primer elemento de la siguiente tripleta le dice al decodificador que mueva hacia atrs el
apuntador siete caracteres y copie cuatro caracteres desde aquel punto. El proceso de
decodificacin trabaja como se muestra en la ilustracin 3:

Ilustracin 3: decodificacin de la tripleta , , ()


Finalmente, veamos cmo se decodifica la tripleta , , (). Nos movemos atrs tres
caracteres y arrancamos a copiar. Los primeros tres caracteres que copiamos son , el
apuntador se mueve una vez ms como se muestra en la ilustracin 4, para copiar el
carcter recientemente copiado. Similarmente, copiamos el siguiente carcter .
Aunque arrancamos copiando solamente tres caracteres, terminamos copiando cinco
caracteres. Observe que el acople solo tiene que arrancar en el buffer de bsqueda, y
puede extenderse en el . En efecto, si el ultimo carcter en el
hubiera sido en lugar de seguido por varias repeticiones
adicionales de , la secuencia entera de repetidas podran haber sido codificadas
con una sola tripleta

Ilustracin 4: decodificando la tripleta , , ()


Como se observa en este ejemplo el esquema es muy simple y no requiere un
conocimiento previo de la fuente. Sin embargo lo que se est asumiendo implcitamente
es que los patrones recurrentes ocurren muy cercanamente.
Variaciones
Para mejorar el algoritmo de codificacin se puede

Codificar la tripleta con longitud variable (, , , etc.)


Variar el tamao de los bferes.
Eliminar la tripleta cuando se codifica un solo carcter usando una bandera de un bit
para indicar que lo que sigue es el cdigo de un solo carcter.
Con el uso de la bandera no se necesita seguir enviando el tercer miembro de la
tripleta.
1.4.2. La aproximacin

En el algoritmo se pierde eficiencia si los patrones recurrentes no ocurren muy


cercanos, por ejemplo en este caso:

Ilustracin 5: Ejemplo de secuencia codificada ineficientemente en


En el algoritmo se elimina la necesidad del bfer de bsqueda construyendo
explcitamente un diccionario tanto en el transmisor como en el receptor.
Las entradas se codifican como una dupleta , en donde:
Es un ndice correspondiente a la entrada del diccionario que fue el acople ms largo a
la entrada, si no hay acople se enva cero.
Es el cdigo del carcter de la entrada que sigue la porcin acoplada de la entrada.
Esta dupleta se convierte en la entrada ms nueva del diccionario.
Ejemplo:
Codifiquemos la secuencia

En donde el espacio se representa por la rayada. Inicialmente el diccionario est vaco,
tal que los primeros tres smbolos encontrados son codificados con el ndice puesto en 0.
Las tres primeras salidas del codificador son , (), , (), , () y el
diccionario luce como en la tabla 4:

ndice Entrada

Tabla 4: Diccionario inicial

8
El cuarto smbolo es una b, la cual es la tercer entrada en el diccionario. Si le aadimos
el siguiente smbolo, obtenemos el patrn el cual no est en el diccionario, luego
codificamos estos dos smbolos como , , y agregamos el patrn como la cuarta
entrada en el diccionario.
Diccionario
Salida del codificador ndice Entrada
, ()

, ()

, ()

, ()

, ()

Tabla 5: Desarrollo del diccionario


El principal problema que aparece aqu es que el diccionario crece indefinidamente.
1.4.3. El algoritmo
Es una modificacin de hecha por Terry Welch en donde se elimina la
necesidad de codificar el segundo elemento de la dupleta y por lo tanto se requiere enviar
solo el ndice del diccionario inicializando este con todas las letras del alfabeto de la
fuente.
La entrada del codificador es acumulada en el patrn a medida que este es contenido
en el diccionario. Si la adicin de otra letra resulta en otro patrn que no est en
el diccionario, entonces el ndice de es transmitido al receptor y se adiciona el patrn
al diccionario.
Ejemplo:
Codifiquemos la secuencia previa usando el algoritmo

Asumiendo que el alfabeto de la fuente es: {, , , , } el diccionario luce
inicialmente como se muestra en la tabla 6:

9
ndice Entrada

Tabla 6: diccionario inicial


El codificador encuentra de primera la letra . Este patrn est en el diccionario, por lo
tanto concatenamos la siguiente letra con ella, formando el patrn . Este patrn no est
en el diccionario, as codificamos con su ndice , adicionamos el patrn como el
sexto elemento del diccionario, y comenzamos un nuevo patrn que arranca con el
carcter . Como est en el diccionario, concatenamos el siguiente elemento para
formar el patrn . Este patrn no est en el diccionario, as que codificamos el patrn
con su ndice , adicionamos el patrn al diccionario como la sptima entrada del
diccionario y arrancamos construyendo un nuevo patrn con el carcter . Continuamos
de esta manera, construyendo los patrones de letras hasta que encontramos el carcter
en el segundo . En este punto la salida del codificador consiste enteramente de
ndices del diccionario inicial, o sea . El diccionario en este punto luce como se
muestra en la tabla 7 (la entrada en el diccionario est an bajo construccin).
ndice Entrada

10

11

12

Tabla 7: construyendo el elemento del diccionario LZW



El siguiente smbolo en la secuencia es . Concatenando este a , obtenemos el patrn
. Este patrn ya existe en el diccionario (tem 6), as nosotros leemos el siguiente
smbolo, el cual es . Concatenando este carcter a , obtenemos el patrn . Este
patrn no existe en el diccionario, entonces lo incluimos como la entrada al
diccionario, y arrancamos un nuevo patrn con el smbolo . Tambin codificamos
con su valor de ndice . Observe que despus de una serie de entradas de dos letras,
ahora tenemos una entrada de tres letras. A medida que la codificacin progresa, la
longitud de las entradas contina incrementndose. Mientras ms largas sean las entradas
indica que el diccionario est capturando ms de la estructura de la secuencia. El

10
diccionario al final del proceso de codificacin se muestra en la tabla 8. Observe que la
todas las entradas de la doce a la tienen una longitud de o de cuatro letras. Luego
encontramos el patrn por primera vez y caemos a un patrn de dos letras por tres
entradas ms, despus de lo cual regresamos a entradas de longitud en incremento.
La secuencia de salida del codificador es


ndice Entrada ndice Entrada

Tabla 8: Ejemplo de Codificacin


A medida que el diccionario crece o sea que las entradas son ms largas indica que el
diccionario est capturando ms de la estructura en la secuencia.
Ejemplo: El algoritmo de decodificacin
En este ejemplo tomaremos la salida del codificador del ejemplo previo y lo
decodificaremos usando el algoritmo . La secuencia de salida del codificador en el
ejemplo previo fue .
Esta es la entrada a la entrada del decodificador. El decodificador arranca con el mismo
diccionario inicial de la tabla . El valor del ndice corresponde a la letra , as
decodificamos como el primer elemento de nuestra secuencia. Al mismo tiempo, para
replicar el procedimiento de construccin del diccionario en el codificador, comenzamos
la construccin del siguiente elemento del diccionario. Arrancamos con la letra . Este
patrn existe en el diccionario as no lo adicionamos al diccionario, y continuamos con el
proceso de decodificacin. La siguiente entrada del decodificador es el , el cual es el
ndice de la letra correspondiente . Decodificamos una y la concatenamos con nuestro
patrn corriente para forma el patrn . Como este patrn no est en el diccionario, lo
adicionamos como el sexto elemento del diccionario y arrancamos un nuevo patrn
comenzando con la letra . Las siguientes cuatro entradas corresponden con las
letras , y generan las entradas al diccionario , , . El diccionario luce
como se muestra en la tabla 9, donde la entrada est bajo construccin.

11
ndice Entrada

Tabla 9: Construyendo la entrada del diccionario mientras se decodifica.


La siguiente entrada es , el cual es el ndice correspondiente al patrn . Luego,
decodificamos una y una . Primero concatenamos al patrn existente, el cual es ,
y formamos el patrn . Como este patrn no existe en el diccionario se convierte en la
entrada . El nuevo patrn ahora arranca con la letra . Habamos decodificado
previamente la letra , la cual concatenamos ahora con para obtener el patrn . Este
patrn est contenido en el diccionario, luego decodificamos la siguiente entrada, la cual
es . Esta corresponde a la entrada en el diccionario. Decodificamos la primera y la
concatenamos con el patrn para obtener el patrn . Este patrn no existe en el
diccionario, as lo adicionamos con la entrada en el diccionario y arrancamos un nuevo
patrn con la letra . Decodificando la segunda y concatenndola al nuevo patrn
conseguimos el patrn . Este patrn existe en diccionarioEl problema que resulta
ac es cuando aparecen secuencias que se repiten permanentemente.
Hay una situacin particular donde el mtodo de decodificacin del algoritmo
descrito antes no funciona. Suponga que tenemos una fuente con un alfabeto = {, },
y que queremos codificar la secuencia que comienza en El
procedimiento de codificacin es aun el mismo. Comenzamos con el diccionario inicial
mostrado en la tabla 10:
ndice Entrada

Tabla 10: Diccionario inicial para la secuencia


El proceso termina con el diccionario final de la tabla 11:
ndice Entrada

12

Tabla 11: Diccionario final para la secuencia


En este caso en el proceso de decodificacin hay que usar entradas del diccionario que
an no han sido construidas y por lo tanto es imposible decodificar.
El proceso de compresin en es el siguiente:

El proceso de descompresin es el siguiente:

Un algoritmo en :
/**********************************************************************
** Copyright (c) 1989 Mark R. Nelson
**
** LZW data compression/expansion demonstration program.
**

13
** April 13, 1989
**
** Minor mods made 7/19/2006 to conform with ANSI-C - prototypes, casting,
** and argument agreement.
**********************************************************************
*********/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#define BITS 12

/* Setting the number of bits to 12, 13*/

#define HASHING_SHIFT (BITS-8)

/* or 14 affects several constants.

*/

#define MAX_VALUE (1 << BITS) - 1 /* Note that MS-DOS machines need to */


#define MAX_CODE MAX_VALUE - 1

/* compile their code in large model if*/

/* 14 bits are selected.

*/

#if BITS == 14
#define TABLE_SIZE 18041
#endif
#if BITS == 13

/* The string table size needs to be a */

/* prime number that is somewhat larger*/


/* than 2**BITS.

*/

#define TABLE_SIZE 9029


#endif
#if BITS <= 12
#define TABLE_SIZE 5021
#endif
void *malloc();
int *code_value;

/* This is the code value array

*/

14
unsigned int *prefix_code;

/* This array holds the prefix codes */

unsigned char *append_character; /* This array holds the appended chars */


unsigned char decode_stack[4000]; /* This array holds the decoded string */
/*
* Forward declarations
*/
void compress(FILE *input,FILE *output);
void expand(FILE *input,FILE *output);
int find_match(int hash_prefix,unsigned int hash_character);
void output_code(FILE *output,unsigned int code);
unsigned int input_code(FILE *input);
unsigned char *decode_string(unsigned char *buffer,unsigned int code);
/**********************************************************************
** This program gets a file name from the command line. It compresses the
** file, placing its output in a file named test.lzw. It then expands
** test.lzw into test.out. Test.out should then be an exact duplicate of
** the input file.
**********************************************************************
***/
main (int argc, char *argv[])
{
FILE *input_file;
FILE *output_file;
FILE *lzw_file;
char input_file_name[81];
clrscr();

15
/*
** The three buffers are needed for the compression phase.
*/
code_value=(int*)malloc(TABLE_SIZE*sizeof(int));
prefix_code=(unsigned int *)malloc(TABLE_SIZE*sizeof(unsigned int));
append_character=(unsigned char *)malloc(TABLE_SIZE*sizeof(unsigned char));
if (code_value==NULL || prefix_code==NULL || append_character==NULL)
{
printf("Fatal error allocating table space!\n");
getch();
exit(-1);
}
/*
** Get the file name, open it up, and open up the lzw output file.
*/
if (argc>1)
strcpy(input_file_name,argv[1]);
else
{
gotoxy(10,10);
printf("Por favor ingrese el nombre del archivo: ");
scanf("%s",input_file_name);
}
input_file=fopen(input_file_name,"rb");
lzw_file=fopen("comp.txt","wb");

16
if (input_file==NULL || lzw_file==NULL)
{
printf("Fatal error opening files.\n");
getch();
exit(-1);
};
/*
** Compress the file.
*/
compress(input_file,lzw_file);
fclose(input_file);
fclose(lzw_file);
free(code_value);
/*
** Now open the files for the expansion.
*/
lzw_file=fopen("comp.txt","rb");
output_file=fopen("out.txt","wb");
if (lzw_file==NULL || output_file==NULL)
{
printf("Fatal error opening files.\n");
getch();
exit(-2);
};
/*

17
** Expand the file.
*/
expand(lzw_file,output_file);
fclose(lzw_file);
fclose(output_file);
free(prefix_code);
free(append_character);
getch();
}
/*
** This is the compression routine. The code should be a fairly close
** match to the algorithm accompanying the article.
**
*/
void compress(FILE *input,FILE *output)
{
unsigned int next_code;
unsigned int character;
unsigned int string_code;
unsigned int index;
int i;
next_code=256;

/* Next code is the next available string code*/

for (i=0;i<TABLE_SIZE;i++) /* Clear out the string table before starting */


code_value[i]=-1;
i=0;

18
gotoxy(10,13);
printf("Comprimiendo...\n");
getch();
string_code=getc(input);

/* Get the first code

*/

/*
** This is the main loop where it all happens. This loop runs util all of
** the input has been exhausted. Note that it stops adding codes to the
** table after all of the possible codes have been defined.
*/
while ((character=getc(input)) != (unsigned)EOF)
{
if (++i==1000)
{

/* Print a * every 1000

*/

/* input characters. This */


i=0;

/* is just a pacifier.

*/

printf("*");
}
index=find_match(string_code,character);/* See if the string is in */
if (code_value[index] != -1)

/* the table. If it is, */

string_code=code_value[index];
else
{

/* get the code value. If */

/* the string is not in the*/


/* table, try to add it. */

if (next_code <= MAX_CODE)


{
code_value[index]=next_code++;
prefix_code[index]=string_code;

19
append_character[index]=character;
}
output_code(output,string_code); /* When a string is found */
string_code=character;
}
}

/* that is not in the table*/

/* I output the last string*/


/* after adding the new one*/

/*
** End of the main loop.
*/
output_code(output,string_code); /* Output the last code

*/

output_code(output,MAX_VALUE); /* Output the end of buffer code


output_code(output,0);

/* This code flushes the output buffer*/

printf("\n");
}
/*
** This is the hashing routine. It tries to find a match for the prefix+char
** string in the string table. If it finds it, the index is returned. If
** the string is not found, the first available index in the string table is
** returned instead.
*/
int find_match(int hash_prefix,unsigned int hash_character)
{
int index;
int offset;
index = (hash_character << HASHING_SHIFT) ^ hash_prefix;

*/

20
if (index == 0)
offset = 1;
else
offset = TABLE_SIZE - index;
while (1)
{
if (code_value[index] == -1)
return(index);
if (prefix_code[index] == hash_prefix &&
append_character[index] == hash_character)
return(index);
index -= offset;
if (index < 0)
index += TABLE_SIZE;
}
}
/*
** This is the expansion routine. It takes an LZW format file, and expands
** it to an output file. The code here should be a fairly close match to
** the algorithm in the accompanying article.
*/
void expand(FILE *input,FILE *output)
{
unsigned int next_code;
unsigned int new_code;

21
unsigned int old_code;
int character;
int counter;
unsigned char *string;
next_code=256;
counter=0;

/* This is the next available code to define */


/* Counter is used as a pacifier.

*/

gotoxy(10,16);
printf("Descomprimiendo...\n");
old_code=input_code(input); /* Read in the first code, initialize the */
character=old_code;

/* character variable, and send the first */

putc(old_code,output);

/* code to the output file

*/

/*
** This is the main expansion loop. It reads in characters from the LZW file
** until it sees the special code used to inidicate the end of the data.
*/
while ((new_code=input_code(input)) != (MAX_VALUE))
{
if (++counter==1000) /* This section of code prints out
{

*/

/* an asterisk every 1000 characters */


counter=0;

/* It is just a pacifier.

*/

printf("*");
}
/*
** This code checks for the special
STRING+CHARACTER+STRING+CHARACTER+STRING
** case which generates an undefined code. It handles it by decoding

22
** the last code, and adding a single character to the end of the decode string.
*/
if (new_code>=next_code)
{
*decode_stack=character;
string=decode_string(decode_stack+1,old_code);
}
/*
** Otherwise we do a straight decode of the new code.
*/
else
string=decode_string(decode_stack,new_code);
/*
** Now we output the decoded string in reverse order.
*/
character=*string;
while (string >= decode_stack)
putc(*string--,output);
/*
** Finally, if possible, add a new code to the string table.
*/
if (next_code <= MAX_CODE)
{
prefix_code[next_code]=old_code;
append_character[next_code]=character;

23
next_code++;
}
old_code=new_code;
}
printf("\n");
}
/*
** This routine simply decodes a string from the string table, storing
** it in a buffer. The buffer can then be output in reverse order by
** the expansion program.
*/
unsigned char *decode_string(unsigned char *buffer,unsigned int code)
{
int i;
i=0;
while (code > 255)
{
*buffer++ = append_character[code];
code=prefix_code[code];
if (i++>=MAX_CODE)
{
printf("Fatal error during code expansion.\n");
exit(-3);
}
}

24
*buffer=code;
return(buffer);
}
/*
** The following two routines are used to output variable length
** codes. They are written strictly for clarity, and are not
** particularyl efficient.
*/
unsigned int input_code(FILE *input)
{
unsigned int return_value;
static int input_bit_count=0;
static unsigned long input_bit_buffer=0L;
while (input_bit_count <= 24)
{
input_bit_buffer |=
(unsigned long) getc(input) << (24-input_bit_count);
input_bit_count += 8;
}
return_value=input_bit_buffer >> (32-BITS);
input_bit_buffer <<= BITS;
input_bit_count -= BITS;
return(return_value);
}
void output_code(FILE *output,unsigned int code)

25
{
static int output_bit_count=0;
static unsigned long output_bit_buffer=0L;
output_bit_buffer |= (unsigned long) code << (32-BITS-output_bit_count);
output_bit_count += BITS;
while (output_bit_count >= 8)
{
putc(output_bit_buffer >> 24,output);
output_bit_buffer <<= 8;
output_bit_count -= 8;
}
}
Aplicaciones:
a. Compresor de archivos de
En este caso el tamao del diccionario es adaptativo y se arranca con . Una vez que
el diccionario se llena se dobla el tamao del diccionario de manera recursiva hasta que
se logra un tamao dado por siendo el tamao del cdigo de palabra que puede
estar entre .
Cuando se alcanza el tope del diccionario se vuelve una tcnica de
diccionario esttico. En este punto se monitorea la rata de compresin y si esta cae por
debajo de un umbral el diccionario es borrado y se recomienza la construccin.
b. Compresin de imgenes formato de intercambio de grficos ()
Fue desarrollado por la empresa para codificar
imgenes grficas.
La imagen comprimida se almacena con un primer byte que indica el mnimo nmero de
de la imagen original.
El nmero binario se define como el cdigo claro ( ) para resetear todos
los parmetros de compresin y descomprensin.

26
El tamao inicial del diccionario es . Cuando este se llena se dobla el tamao hasta
que se logra un tamao mximo de y luego de esto el algoritmo se comporta como
un algoritmo de diccionario esttico.
Las palabras de cdigo se almacenan en bloques de caracteres de cada uno y el
tamao mximo es de .
Cada bloque es precedido por un encabezado que contiene el tamao del bloque.
El bloque es terminado con un terminador de bloque que consiste de .
El fin de la imagen comprimida es denotado por un cdigo de fin de informacin con
valor 2 +1. Esta palabra de cdigo debe aparecer antes del terminador de bloque

Ilustracin 6: imgenes de prueba para el algoritmo


Imagen

Tierra
Omaha

Codificacin aritmtica de los


valores de los pixeles

Codificacin aritmtica de las


diferencias entre pixeles

Tabla 11: comparacin de con la codificacin aritmtica


Se observa que en imgenes que no presentan muchos patrones repetitivos la rata de
compresin no es muy alta y pueden ser preferibles otros mtodos.

27
c. Compresin sobre mdems .
Esta recomendacin est hecha para transmisin a travs de una red telefnica junto con
procedimientos de correccin de errores. Se usa en conexin de computadores con
usuarios remotos a travs de mdems. Tiene dos modos: modo transparente y modo
comprimido.
En el modo transparente se transmite sin comprimir en el caso de que no haya secuencias
repetitivas y por lo tanto se presente expansin en vez de compresin. Esto implica que
la recomendacin sugiera que se chequee peridicamente para observar si se da tal
situacin.
En el modo comprimido se usa un diccionario de tamao variable con un tamao inicial
que se negocia al momento de establecer el enlace entre el transmisor y el receptor.
La recomendacin . sugiere un tamao de y un mnimo de .
Se reservan tres entradas del diccionario para caracteres de control
Cdigo Nombre
Descripcin


Tabla 12: palabras de control en modo comprimido
Cuando el nmero de entradas supera un umbral pre acordado el codificador enva el
y el tamao de la palabra se incrementa en , al mismo tiempo se dobla el
valor de .
Cuando todas las entradas se llenan el algoritmo inicia un procedimiento de . La
localizacin de la primera entrada del diccionario se mantiene en una variable .
Arrancando de Un contador se incrementa hasta que el algoritmo encuentra una
entrada del diccionario que no es prefijo de cualquier otra entrada del diccionario, lo que
significa que este patrn no se ha vuelto a encontrar desde que se cre, adems debido a
la manera como fue localizado, entre patrones de esta clase este patrn ha estado alrededor
del ms largo. Este procedimiento de habilita al algoritmo para podar () el
diccionario de tiras que pueden haber sido encontradas en el pasado pero no han sido
encontradas recientemente en una base continua. De esta manera el diccionario se acopla
siempre a las estadsticas corrientes de la fuente.

Anda mungkin juga menyukai