MEDIANTE ORDENAMIENTO REVERSI

Anuncio
UNIVERSIDAD
AUTÓNOMA
METROPOLITANA
UNIDAD
IZTAPALAPA
P R ~ Y E C TTERMINAL
O
&
6
6
L/
C
MEDIANTE
~ ~ ~ ORDENAMIENTO
~ ~ ~ ~
''
REVERSIBLE
PROFESOR:
OSCARYÁÑEz SUÁREZ
ALUMNO:
LIMÓNGÓMEZZAHIDGABRIEL
'
FECHA:25 DE JULIO
DE 2000
ó
~
COMPRESION MEDIANTE ORDENAMIENTO REVERSIBLE
Existen archivos que por el tipo de información que poseen, éstos ocupan mucho
espacio en disco y que algunas veces, éstos no son utilizados frecuentemente, por lo que
sólo están ocupando demasiado espacio en disco. Para reducir el tamaño del archivo y
por ende, el espacio que ocupa en disco, puede utilizarse una propiedad que utilizan la
mayoría de los algoritmos para comprimir archivos y que se llama redundancia, esto es,
que en un archivo puede encontrarse repetidas algunas o demasiadas veces, un mismo
símbolo ó cadenas de éstos símbolos y que contando la frecuencia y posición en donde
se hallaba el símbolo o la cadena de símbolos, puede codificarse la información para que
el archivo resultante sea de menor tamaño en comparación con el original sin que ocurra
pérdida de información, ya que el tipo de información puede o no exigir q,ue sea
mantenida la información original sin alteraciones.
El propósito de este proyecto es de implementar un algoritmo compresor de archivos
que maximiza la propiedad de redundancia de un tipo específico de archivos,
concretamente archivos que guardan información de señales electrocardiográficais. , que
como se conoce éstas poseen mucha redundancia, cualidad que es aprovechada
aplicando un primer algoritmo llamado Block Sorting Lossless (Ordenamiento de
Bloques Sin Pérdidas) cuya función es la de aumentar la redundancia del archivo
reordenando la cadena o archivo aumentando su redundancia para después ser pasado a
un segundo algoritmo llamado Move-To-Front para aumentar símbolos que al
comprimirlos ocupen el menor espacio posible, y por último, el tercer algoritmo que es
en sí el verdadero compresor, el algoritmo de Huffinan, las dos etapas anteriores son de
preprocesamiento para aumentar la redundancia y maximizar la razón de compresión de
Hut'fman, este algoritmo debe trabajar también a una velocidad razonable, ya que hay un
compromiso de velocidad-razón de conipresión que debe al menos ser similar a los
compresores conocidos comúnmente.
Obviamente, el compresor debe tener su contraparte, el descompresor, que aplica las
tres etapas anteriores en orden inverso y que procesan inversamente la información,
hasta obtener la información exactamente igual a la original.
Aunque éste programa está hecho específicamente para comprimir señales
electrocardiográficas, también podría ser utilizado para comprimir otros tipos de
archivos.
El algoritmo aquí utilizado se divide básicamente en tres fases:
I . Un algoritmo de transformación reversible llamado block-sorting-lossless para
generar redundancia, o sea, reordenar los símbolos para agruparlos en cadenas del
mismo símbolo en el archivo.
2.- Un algoritmo llamado move-to-front que agrega más redundancia al archivo.
3.- Un tercer algoritmo que utiliza el algoritmo de compresión de Huffman.
El orden en que se aplican los algoritmos para comprimir es el mismo anteriormente
descrito y, como es de suponerse, existe la contraparte de cada fase del algoritmo,
encargada de recuperar el archivo original y que su orden de aplicación, es el inverso de
la compresión.
A continuación, se describe la manera en cómo trabaja cada fase del algoritmo de
compresión:
La primera fase de transformación reversible lee un archivo en modo binario y lo
guarda en una cadena “X’de tamaño N en donde cada elemento es un byte para ser
procesado, a continuación, se crea una matriz de tamaño NxN en donde cada renglón es
la rotación cíclica hacia la izquierda de un elemento de la cadena “X’, posteriormente se
procede a ordenar los renglones de la matriz numéricamente en orden ascendente desde
el renglón O hasta el renglón N-1 basándose en el primer elemento de cada renglón y
siguiendo después con el segundo elemento y así sucesivamente hasta que la matriz
quede totalmente ordenada, una vez hecho esto, se procede a buscar el renglón cuyos
elementos coincidan exactamente con la. cadena original “X’ y el número de renglón en
donde se encontró la coincidencia se marca como el índice “I”, finalmente el elemento
que esta fase va a mandar a la siguiente es la cadena generada con la última columna de
la matriz NxN más el índice “I”, como este programa está hecho en WIN32 (32bits), el
índice “I” tiene un tamaño de 4 bytes que son añadidos al final de la cadena resukmte.
El siguiente ejemplo usa una cadena ‘“X” de 16 símbolos ó elementos que son los
siguientes:
Matriz de NxN con lo corrimientos circulares a la izquierda:
Una vez hechos los corrimientos se procede a ordenar los renglones empezando por el
primer símbolo ó columna de cada renglón y así sucesivamente.
A
Hecho esto, se procede a obtener la nueva cadena ordenada tomhdola de la última
columna de la matriz NxN final empezando por el renglón cero hasta el último renglón,
por l o que nos queda:
Puede notarse de la cadena obtenida que algunos símbolos que antes estaban diispersos
ahora fueron agrupados en cadenas del mismo símbolo, como ocurre con el 42 ó con los
ceros, de este modo se le aumenta redundancia a la cadena.
Ahora, para poder recuperar la cadena original se necesita obtener un elemento llamado
índice “I”, este es el número de renglón en el cual quedó numerado la cadena original en
la matriz final, o sea en este caso el índice es “1l”, y es afladido al final de l a cadena
ordenada para después poder ser recuperado y ejecutar el ordenamiento inverso.
I Indiice “I” 1
rh-7
Prima elemento a buscar
en el buffer auxiliar
La segunda fase (move-to-front) utiliza un buffer auxiliar que contiene los
símbolos utilizados en la cadena (0-255) ordenados inicialmente:
4
Elemento encontrado
para empezar se obtiene el primer símbolo de la cadena “X’y ese elemento se busca en
el buffer auxiliar y la posición en donde se encontró se guarda en una nueva cadena
llamada “S” generada del mismo tamaño de “X’,
el símbolo encontrado se pasa al tope
del buffer recorriéndose los otros símbolos hacia abajo:
I
Elemento al tope de buffer y se recorren los símbolos
I
Se guarda la posición
donde se encontró
posteriormente se pasa ai siguiente elemento de la cadena “X’ y si éste resulta igual al
símbolo anterior, lo que se hace es que se agrega un cero en la posición correspondiente
en la nueva cadena “S” y el buffer no se altera, cuando el símbolo a buscar ha cambiado
entonces se repite el procedimiento anteriormente descrito, se busca el símbolo en el
buffer auxiliar y la posición donde se encontró es guardada en la nueva cadena “S”, el
símbolo buscado se pone al principio del buffer y los demás símbolos se recorren hacia
abajo, si el símbolo a buscar se repite se colocan un cero en la nueva cadena “S” y así se
continúa hasta llegar al tin de la cadena “X’,
al finalizar el elemento que se pisa a la
etapa fmal es la cadena “S” (se le agrega al final un byte de protección, el 253 que es
eliminado en la descompresión).
h
La tercera fase usa el algoritmo de compresión de Huffinan y la cadena “S”, primero
guarda en el archivo resultante el conteo de bytes, o sea, el tamaño de la cadena “S”,
después lee toda la cadena y cuenta el número de veces que se repiten cada uno de los
símbolos presentes, guarda el conteo de símbolos existentes y crea un arreglo de
frecuencias de cada símbolo que también guarda en el archivo resultante, posteriormente
empieza a construir el árbol de Huffman usando el arreglo de frecuencias, va creando
nodos padre en los que en los nodos hijos guarda los símbolos u otros nodos con menor
o misma frecuencia y en el nodo padre resultante la suma de las frecuencias de los hijos,
así continúa hasta haber cubierto todos los símbolos presentes en la cadena terminando
en el nodo raíz del árbol, así pues los símbolos más cercanos a la raíz son los símbolos
que más se repiten y en las hojas los símbolos que menos se repiten, hecho esto
comienza la compresión en sí, lee el primer elemento de la cadena “S” y lo busca en el
árbol de Huffman comenzando desde la raíz, al ir recorriendo las ramas se van creando
nuevos bytes donde por cada nodo atravesado se agrega ya sea un bit 1ó un bit O al byte
nuevo y cuando se juntan 8 bits, esos bits son escritos al archivo de salida como blytes, la
compresión resulta por el hecho de que el elemento más frecuente en la cadena es
representado por uno o dos bits, el segundo, por tres bits, etc., consiguiendo una
reducción en el número de bits utilizados y por consiguiente, se reduce el tamaño del
archivo.
Ilustrando el ejemplo obtendríamos:
Conteo de bytes (bytectr) = 21.
Conteo de frecuencias o símbolos (freqctr) = 11
__-
Símbolo
O _1
___.___
2
3
___16
29
42
Frecuencia
Codificación
8
3
2
1
1
1
1
0010
001 1
0100
-_
0101
L
7
El árbol quedaría:
Si buscáramos el número
16 al recorrer el árbol
quedaría la secuencia de
bits O011
raíz
1 0
; -$- - - - - [
1 0
Si guardáramos la cadena “S” sin comprimir el espacio que ocuparía es:
(21 bytes) x (8 bits) = 168 bits
Si usamos el compresor el espacio ocupado sería:
(2x8)+(3~3)+(
4~1)+(4~1)+(4x1)+(4~1)+(4x1)+(4x1)+(4x1)+(4x1)+(3x2)
= 63 bits
= 8 byes
o sea lo comprime al 37.5 YOdel tamaño original.
Y
Ahora se describe cómo trabaja el algoritmo de descompresión:
El descompresor aplica en forma y orden inverso las tres etapas usadas en la
compresión.
Primeramente el descompresor de Huffman, recupera el conteo de bytes, el conteo de
frecuencias y el arreglo de frecuencias para reconstruir el árbol de Huffman, después
empieza a leer bit por bit del archivo y recorre el árbol de Huffman, cuando llej,’a a un
nodo hoja, el símbolo que contiene es recuperado y colocado en un arreglo nuevo
llamado “S”, continúa así hasta que el archivo es descomprimido.
El árbol reconstruido quedaría:
raíz
I
con la secuencia de bits
1001 el número hallado
sería el 255
o
La segunda fase es la de Move-To-Front inversa, en la cual el funcionamiento es casi
idéntico a su modo normal, tenemos el mismo buffer con los 256 símbolos ordenados,
entonces tomamos el primer elemento de la cadena descomprimida y buscamos esa
posición en el buffer, el número que se halle en esa posición es colocado en el tope del
buffer y además en una nueva cadena llamada “L“ que va a ser el resultado de esta fase,
posteriormente pasamos con el segundo elemento de la cadena descomprimida y si éste
resulta ser un cero, se repite el mismo número que antes se había colocado en lai nueva
cadena y así sucesivamente hasta que terminen los ceros, cuando el número cambia de
cero, se repite el procedimiento anterior hasta acabar con la cadena descomprimida (el
símbolo de protección 255 es eliminado en este paso).
Por último para terminar el procedimiento y hacer la recuperación del archivo
original aplicamos a la cadena el algoritmo block-sorting-lossless inverso,
en esta fase recuperamos del fin de la cadena el índice I que fue añadido al momento de
ordenar ya que posteriormente va a ser utilizado, se crean dos nuevas cadenas, una
llamada “i” que va a estar numerada desde el O hasta N-I tamaño de la cadena “L” y otra
llamada “S” que va contener ya la cadena original,
-.
I
~
. .
. ..
I
Posición
. .... -en
.. ..“L‘
- .una vez hecho esto mediante el algoritmo de ordenamiento “qsort” ordenamos 1aL cadena
“i” en base a “L”y el resultado del ordenamiento lo guardamos en “i“,
1
enbasea“L”
in
finalmente para generar la cadena original tomamos el índice “I” recuperado
anteriormente y buscamos esa posición en la cadena “L” ordenada y el número
contenido en esa posición va a ser el primer elemento de la cadena “S”, después
buscamos en la cadena ‘‘2’ esa misma posición y el número que contiene se convierte en
el nuevo índice y pasamos a buscar esa posición en “L” y el número que contiene es el
siguiente elemento de “S” y buscamos esa misma posición en “i” y el número que
contiene se convierte en el nuevo índice y así continuamos sucesivamente hasta
recuperar toda la cadena original.
lndice
.c
En este ejemplo el índice es 11, y el elemento colocado en la posición de la cadena “L”
ordenada es 42 que se convierte en el primer elemento de “S”, después el símbolo en esa
misma posición pero en la cadena “i” ordenada es 2, este pasa a convertirse en el nuevo
índice, vemos que en la posición 2 de “L” hay un cero, éste se convierte en el segundo
símbolo de “S”, y en esa misma posición pero en “i” está el 6, éste es el nuevo índice,
repitiendo el método hasta llegar nuevamente al índice inicial 11nos queda la cadena
final “S” que comparándola con la cadena original “X’ vemos que es la misma.
11
RESULTADOS.
Aplicando el programa obtenido a dos archivos muestra de ECG ambulatorio y
comparando los resultados con otros dos compresores, uno es el algoritmo de Huffman
puro sin el preprocesamiento y el otro es el programa WINZIP que usa el algoriitmo de
Lempel y Ziv (Este algoritmo codifica los datos en una pasada y permite compresión
más grande que la codificación de Huffman con menos cómputos, es un algoritmo de
longitud variable y fija. Analiza secuencialmente la salida de una fuente discreia hacia
frases de longitud variable, divide la cadena fuente en frases que no habían aparecido
antes (excepto por la última). Las frases son almacenadas en un diccionario como son
construidas, las localidades en el diccionario son numeradas consecutivamente. La
palabra de código para cada Frase es entonces construida al listar las localidades del
diccionario (en binario) que igualan la nueva frase en casi todo a la última localidad
(prefijo); después del análisis secuencial, cada prefijo de cada frase aparece más
próximo en el análisis. El valor del último bit es entonces agregado al prefijo).
Se obtuvieron los siguientes resultados:
Para el archivo ECG1.BIN
154029
112105
p?Gy2ZSOOUT
225000__
WinZip-
.
.
__
Para el archivo ECG2.BIN
-
Programa Utilizado
BSL
.
Huffman Puro
WinZip
.
.
~ a m a i i oInicial-
225000
225000
225000
Tamaño Final
.
.
.
.
.
.
85069
148966
108197
48
17
//UNIVERSIDAD AUTONOMA METROPOLITANA
//PROYECTO TERMINAL I1
//PROYECTO: COMPRESION MEDIANTE ORDENAMIENTO REVERSIBLE
//PROFESOR: OSCAR YAñIEZ SUAREZ
//ALUMNO:
ZAHID GABRIEL LIMON GOMEZ
#include
#include
#include
#include
#include
#include
#include
<io.h>
<dos.h>
<conio.h>
<stdio.h>
<stdlib.h>
<string.h>
"htree.h"
cOMp32.c * * * * * * * * * * * * * * * /
compresor 32 bits* * * * + * * * * i t * * /
/It************
/*******ti*
.
A
static void compress(F1LE *fo, struct htree *h, struct htree "child);
static void outbit(F1tE *fo, int bit);
unsigned char *L, *x;
long length;
void Carga-buffer(FiLE *fi,long *i)
long k;
fseek ( fi,OL,O) ;
fread(x, 1, length, fi)r
/ / carga el archivo en el buffer
fclose(fi1;
for (k=O; k<length; k++)
* (itk)=k;
/ / numera el arreglo de posiciones progresivamente
x
'.1\
MOVE TO FRONT N O W
void MTF(unsigned char *p, unsigned char * S I
/t***t**itC***l******~****~~*
*******t***i***t*t***t*/
(
long k, r;
unsigned char w=O, pos;
printf("Rea1izando MOVE TO FRONT normal... \t");
for (r=O;r<256;r++)
(
,,'-
.
//inicializo arreglo de simbolos de 256 simbolos
* (p+r)=w;
W++;
f
for(k=O;k<lengtht4;k++)
(
//recorre el arreglo L
for(wx0; * (Ltk)!E* (p+wl; w++) //busca elemento en arreglo de simbolos
11
.*
pos=w;
.-
while (w!=O)
(
//guardo la posicion donde se encontro
* (p+w)=*(p+w-1); //recorro hacia abajo los simbolos
W--;
1
*p=* (Ltk);
//pongo el simbolo a la cabeza del arreglo
* (stk)-pos;
//pongo la posicion en el arreglo resultante s
while(* (Ltk)==*(Ltktl)) //verifico si el elemento se repite
t
//consecutivamente, si es asi, coloco ceros en el
k++;
//arreglo resultante
(s+k)=O;
1
1
1
printf ("Ok!\n");
RUTINA DE COMp-CION
/****t*t*****
t
DE QSORT DE BSL
.......................
int comparar( const void *argl, const void *arg2)
long nl,n2,n3,k;
int sal=O;
nl=length-*(long *)argl;
n2=length-* (long *)arg2;
if (nl<n2)
(
n3=nZ-nl;
I
.
- .,
.
66
for(k=O; k<nl
(
c..
.
1
sal==O ;k++)
sal= *(x+(*(long *)argl+k)) - *(x+(*(long *)arg2+k));
1
for(k=O; k<n3
*-
&6
sal==O; k+t)
sal= *(x+k)
' l
1
-
*(x+(*(long *)arg2)+nl+k);
if (sal==O)
(
,^
for(k=O; k<*(iong *)arg2
t
* .I
1
1
1
sal=
/ / (nl>n2)
(
n3=nl-n2;
forlk=O; k<n2
h6
sal==O; k+t)
* (xtn3ck) - * (xtk);
)
else
66
sal==O; k+t)
..*
I
--
mi
.
.
a
-
Sal= *(,+(*(long
1
if (sal==O)
*)argl+k))
-
*(x+(*(long *)argZ+k));
{
for(k=O; k<n3
(
1
&&
sal==O; k++)
sal= * (x+( * (long
* ) argll+nZ+k)
- * (x+k);
if (sal==O)
for(k=O; k<*(long *)argl
sal= *(x+k)
1
-
&&
sal==O; k++)
+(x+n3+k);
)
1
1
return(sa1);
1
BLOCK-SORTING LOSSLESS NORMAL
/******t**t***tCf*******
**ti***********+**/
void BSL(1ong *i)
f
long y, pos, k;
long *I;
//elemento a buscar para encontrar el indice
pos = length-1;
printf ("Quicksort.. \t\t")i //ordeno i en base a x
/*
./
.
..................................................................
qsort ( (long * ) i, (size-t)length, sizeof (*i), comparar);
e-
/ * ..................................................................
,c
I
r)_
printf ("Ok!\n");
printf ("Calculando L..
. \t");
I=(L+length);
*1=0;
//asigno a I la direccion donde se va a copiar
for (k = O; k < length ; k++)
//carga el buffer L ordenado
I
y=(* (i+k)+length-1)%length;
* (L+k)=*(x+(yclength)%length);
if (y==pos)
//busca el indice I
[ *I=k; 1
//guarda el indice al final de L
I
printf ("Ok!\n");
MAIN
/*t***********i*tt*********t***l*f
*t**********t******tt********i***/
static char out8;
static int ct8;
c
./
void main(int argc, char *argv[l)
{
FILE *fi;
//apuntador a archivo
FILE *fo;
*-
,l
,-
,-
int
comparar(const void *argl, const void *arg2);
unsigned char *p, * s i
long *i;
long k;
int c;
BYTECOUNTER bytectr a
int freqctr = O;
O;
I".
if (argc < 3 )
(
1
printf("\nusar: comp32 infile outfile");
exit (1);
if ((fi = fopen(argv[l], "rb"))
==
NULL)
(
.-.
I
printf ("\no se puede abrir % s " , argvill) ;
exit (1);
fseek(fi, OL, SEEK-END);
length = ftell(fi1 ;
printf ("El tamaflo del archivo %s es %u bytes\n",argv[ll ,length);
if ((fo = fopen(argv[2], "wb")) == NULL)
(
1
printf ("\no se puede abrir %s", argv[21) ;
fcloseífi);
exit ( 1 );
//buffer de datos
x=(unsigned char *)malloc(length*sizeof(unsigned char));
L=(unsigned char *)malloc((lengtht4)*sizeof(unsignedchar));
//buffer
final, indice I al final
s=(unsigned char *)malloc((lengtht5)*sizeof(unsigned char)) ;
p=(unsigned char *)malloc(256*sizeof(unsignedchar));
//buffer de MTF
//buffer de posiciones
i=(long *)malloc(length*sizeof(longi);
'+.
I-
C
"
I
.*.
printf("Leyend0 archivo. ..\t");
//carga el buffer con el archivo
Cargabuffer(fi,i);
printf ("Ok!\n");
/ / RUTINA BLOCK-SORTING LOSSLESS NORMAL
BSt(i);
MTF(p,s) ;
/ / RUTINA MOVE TO FRONT
* (s+(length+4))=255;
/*----------------------
COMPRESOR DE WF-
------------------------*/
/*--- lee el archivo de.entrada y cuenta la frecuencia de caracteres ---*/
printf ("Comprimiendo...\t");
while( bytectr < (length+5)
I
c
c
= * (s+bytectr);
&= 255;
)
/ / lee un caracter del buffer
/ / busca si el simbolo ya esta incluido
if (ht[cl.cnt == O)
4
/ / contador de los simbolos existentes
/ / guarda el nuevo simbolo
freqctr++;
ht[c] .ch = c;
1
ht [c].cnt++;
bytectr++;
/ / incrementa la frecuencia del simbolo
/ / contador de bytes leidos
/* _____-escribe la cuenta de bytes al archivo de salida --------*/
fwrite (Sbytectr, sizeof bytectr, 1, fo);
/*-----
escribe el conteo de frecuencia al archivo se salida -----*/
fwrite(&freqctr, sizeof freqctr,
.._
fo);
escribe el arreglo de frecuencias al archivo de salida ----*/
/*----
"..
I,
for (c = O; c < 256; c++)
(
.
Y
if (ht[cl .cnt > O )
t
I
^
.
r
.
,
1
1
fwrite(&ht[cl .ch, sizeof (char), 1, fo);
fwrite(&ht[cl .cnt, sizeof (BYTECOUNTER), 1, fo);
-7,
/*----------------
construye el arbol de huffman
----------------- * /
c
1
buildtree ( )
;
comprime el archivo
/*--------------------k=O;
while ( k < (length+5) )
c = *(s+k);
compress(fo, ht + (c
k++ i
&
_____-_____-____-_--__
*/
255), NULL);
I
if (ct8 < 8)
out6 = (out8 << (8-ct6)); //termina de recorrer los bits a
1
//la izquierda
fputc(out8, f0);
.-.e
printf("\nEl tamaflo del archivo % s es %u bytes\n",argv[2l,ftell(fo));
printf ("Comprimido al %u %\n', (ftell(fo)*lOO)/length);
fclose (fi);
fclose(fo);
/t----------------------------------------------------------------*/
1
c
.,-,
//termina MAIN ( )
;
comprime un valor de caracter a una cadena de bits ------*/
/*-----static void compress(F1LE 'fo, struct htree *h, struct htree *child)
(
if (h->parent != NüLL)
compress (fo, h->parent, h) ;
.-
, I-
if (child)
t
if (child == h->right)
outbit (fo, O ) ;
1
1
else if (child == h->left)
outbit (fo, 1) ;
reune y escribe bits al archivo comprimido de salida -----*/
static void outbit(F1LE ‘fo, int bit)
/c-----
t
if (ct8 == 8 )
t
fputc (OUt8, f0);
Ct8 = o;
1
out8 = (out8 << 1)
ct8++;
””\
I
-
...
^
I bit;
//UNIVERSIDAD AUTONOMA METROPOLITANA
//PROYECTO TERMINAL I1
//PROYECTO: COMPRESION MEDIANTE ORDENAMIENTO REVERSIBLE
//PROFESOR: OSCAR YAí?EZ SUAñEZ
//ALUMNO: ZAHID GABRIEL LIMON GOMEZ
, ,-
#include
#include
#include
#include
#include
#include
#include
<io.h>
<dos.h>
<conio.h>
<stdio.h>
<stdlib.h>
<string.h>
"htree.h"
/*fi****iiif*****
~cmp32.c* * * * * * * f t * l * * * t * * * /
/*******+* DESCOMPRESOR 32 bits *********/
L
".
unsigned char *L;
long length;
static int decompress(F1LE *fi, struct htree *root);
MOVE TO FRONT INVERSA
void MTFI(unsigned char *p,unsigned char * s )
/t*****iCtt*ltt*t**t***fti**tf
<
I
.
(
******i*tt****+t**f**/
unsigned char w=O;
long k;
printf("Realizand0 MOVE TO FRONT inversa... \t");
for (k=O;k<256;k++)
//inicializo arreglo de simbolos de 256 simbolos
(
1
+ (P+W)
'w;
w++ ;
for(k=O;k<length+4;k++) //recorre el arreglo s para generar los valores
w=* (stk);
*(Ltk)=*(p+w);
a-
//obtengo el primer elemento de posicion
//leo el simbolo y lo coloco en L
while(w!=O)
,.-
* (p+w)=* (p+w-l); //recorro hacia abajo los simbolos
w--;
)
*p=* (Ltk);
//pongo el simbolo a la cabeza del arreglo
c
while(*(s+k+l)==O) //verifico si se repiten ceros consecutivamente
i
/ / si es asi, coloco el mismo numero
(L+k+l)=* (Ltk);
//en el arreglo resultante
k++;
I
I-
,-.
/I-
,e.
1
1
printf ("Ok!\n");
/ * * * * * * * * * * * * + RUTINA DE COMPARACION DE QSORT DE BSLI ******************/
I
.-
int compara2( const void *argl, const void *arg2)
int sal;
sal= *(L+(*(long *)argl)) - +(L+(*(long *)arg2));
if (sal==O)
(
1
if(
(*(long *)argl)
I sal=ll; 1
else
{ sal=-ll; 1
>
(*(long *)arg2)
)
return(sa1) ;
1
I
BLOCK-SORTING LOSSLESS INVERSA
/***t*****il*if***t
*.
I
***tft**i********+**t/
void BSLI (unsigned char *s,long *i)
long pos,k;
long *I;
//numera los bytes en i
for (k=O; k<length; k++)
* (i+k)=k;
printf("Reca1culando i...\t"); //ordena sobre el arreglo i
//en base al arreglo L
/*
.....................................................................
qsort((1ong
/*
*)
~/
i, (size-tllength, sizeof(*i), compara2);
.....................................................................
~/
printf ("Ok!\n");
I=L+length;
pos=*1;
r-
//apunto al final del arreglo para recuperar el indice I
//recupero el indice
printf ("CalculandoS..
I.".
. \t");
for (k=O; k<length; k++)
I
pos=* (i+pos);
* (s+k)=*(L+pos);
1
printf ("Ok!\n"):
,A-
,-
...
)
//recupero la cadena original en s
//empezando por el indice
MAIN
/~**t*********C*t***ft*********ii*
*t**tt*fl**t******f**t****ft********/
void main(int argc, char *argv[l)
I
FILE *fi, *fo;
unsigned char c:
BYTECOUNTER bytectr;
int freqctr;
unsigned char *p, * s i
long *i;
long k=O;
if (argc <
3)
{
.4,
1
printf("\nusar: dcomp32 infile outfile");
exit(1);
if ((fi = fopen(argv[ll, "rb")) == NULL)
(
1
printf ("\no se puede abrir %s", argv[ll);
exit (1);
if ((fo = fopen(argv[21, "wb"))
(
1
==
NULL)
printf ("\no se puede abrir Bs", argvC21);
fclose(fi) ;
exit (1);
/c-------------------
DESCWPF(ESOR DE W F W
...
printf("Descomprirniendo
/*-------------------
....................
*/
\t");
lee el conteo de bytes
------------------ * /
fread(&bytectr, sizeof bytectr, 1, fi);
fread(&freqctr, sizeof freqctr, 1, fi);
length=bytectr-5;
P".
c
L=(unsigned char *)rnalloc((lengtht4)*sizeof(unsignedchar));
//buffer final,
indice I al final
s=(unsigned char *)malloc((length+5)*sizeof(unsignedchar));
//buffer de MTF
p=(unsigned char *)malloc(256*sizeof(unsignedchar));
//buffer de posiciones
i=(long ')malloc(length*sizeof(long));
/*-----------------
lee el conteo de frecuencias --------------*/
I-
*
".
.I
while (freqctr--)
t
fread(&c, sizeof (char), 1, fi);
ht[cl .ch = c;
fread(&ht icl .cnt, sizeof (BYTECOUNTER), 1, fi);
/*---------------buildtree ( ) ;
-------------- * /
------------------ * /
construye el arbol de huffman
/*-------------------
descomprime el archivo
while (bytectr--)
i
c=decompress (fi, root);
* (s+k)=c;
ktt;
1
printf ("\nReorganizando... \t\n");
/ / RUTINA MOVE TO FRONT INVERSA
/ / RUTINA BLOCK-SORTING LOSSLESS INVERSA
MTFI (ptS ) ;
BSLI ! s , i);
fwrite(s, 1, length, fo);
r.
I
*.
..*
printf ("\nArchivo descomprimido. \t\n");
fclose (fo);
fclose(fi1;
1
//termina MAINO;
static int in8;
static int ct8 = 8;
/*------------
lee un bit a la vez desde el archivo -----------*/
static int inbit(F1LE *fi)
(
int obit;
if (ct8 == 8)
!
in8 = fgetc(fi1;
ct8 = O;
" .*
1
1
obit = in8 h
in8 <<= 1;
ct8tt;
return obit;
/*-----
0x80;
descomprime los bits de archivo hacia caracteres ------*/
I^
.".
static int decompress(F1LE *fi, struct htree *h)
(
while (h->right != NULL)
*_ 9
4 4
if !inbit (fi))
h = h->left;
else
h = h->right;
return h->ch;
-
#include <stdio.h>
#include <stdlib.h>
#include "htree.h"
struct htree htI5121;
struct htree *root;
/*-- construye un arbol de Huffman desde un arreglo de frecuencia --*/
void buildtree (void)
t
int treect
int i;
=
256;
/*---- construye el arbol de Huffman -----*/
while (1)
t
struct htree *hl
=
NULL, *h2
=
NULL;
encuentra l a s dos frecuencias mas pequenas ----*/
for(i=O; i < treect; i++)
/I----
if (ht+i != hl)
t
if (ht[il.cnt > O
(
6&
ht[il .parent == NULL)
if (hl == NULL I I ht[il .cnt < hl-xnt)
t
if (h2 == NULL I1 hl->cnt < hZ->cnt)
h2 =hl;
hl = ht+i;
1
1
1
t
else if (h2 == NULL I I ht[il .cnt < hZ->cnt)
h2 = htti;
1
if (h2 == NULL)
root =hl;
break;
1
/*---------combina dos nodos y lo agrega ------------*/
hl->parent = ht+treect;
h2->parent = ht+treect;
ht[treectl.cnt = hl->cnt t h2->cnt;
ht[treectl.right = hl;
ht [treect].left = h2;
treectt+;
1
)
.
.,
*%
I
I
.
..
.-.
/*-----------_------------typedef long BYTECOUNTER;
1;
*x,
void buildtree(void):
r-
."*
e-
..-.
c
,-
I*
__________________________
*/
/*-------------------Huffman tree structure ----------------*/
struct htree (
unsigned char ch:
//valor del caracter
BYTECOUNTER cnt;
//frecuencia del caracter
struct htree *parent; //apuntador a nodo padre
struct htree +right; //apuntador a nodo hijo derecho
struct htree *left;
//apuntador a nodo hijo izquierdo
extern struct htree ht[l;
extern struct htree *rooti
a..
htree h
CONCLUSIONES
Revisando los resultados obtenidos puede verse que para los dos archivos muestra el
algoritmo que mejor comprimió fue el del proyecto terminal (BSL) ya que tuvo ai menos
un 10% de mayor compresión que el programa que le siguió, el de WINZIP, y al final el
algoritmo de Huffman puro, esto se debe a que en el BSL se le agregaron dos etapas de
preprocesamiento, destinadas a aumentar la redundancia que ya de por sí tienen estos
tipos de archivos, la velocidad de compresión fue similar a la de los otros programas,
únicamente se noto una disminución de la velocidad con el compresor BSL dado que el
programa simula la generación de la matriz NxN y su posterior ordenamiento usando el
algoritmo quicksort que tiene un desempeño O(n log n), pero en la descompresión
aunque se vueleve a utilizar el quicksort no se ve esa disminución de la velocidad, esto
podría mejorarse usando otro algoritmo que trabaje mejor que quicksort pero aúin así el
resultado fue como el que se esperaba, mayor factor de compresión que otros programas
a una velocidad razonable, por l o que creo que el objetivo de este proyecto fue
alcanzado satisfactoriamente.
REFERENCLAS
Dr. Dobb‘s Journal, February 199l .
Burrows, M.and Wheeler, D.J. (1994) “A Block-sorting Lossless Data Compression
Algorithm”, Digital Systems Research Center Research Report 124.
ALUMNO
ASESOR
Descargar