-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmodulo-t.c
432 lines (325 loc) · 12.7 KB
/
modulo-t.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "shafa.h"
#include "modulo-t.h"
LISTA crialista () {
return NULL;
}
LISTA inserecabeca ( LISTA L , int s , long long int f ) {
LISTA novo = malloc(sizeof(struct lista));
novo->simbolo = s;
novo->frequ = f;
novo->codSF = calloc( 256 , sizeof(char));
novo->prox = L;
return novo;
}
LISTA metenalista ( long long int arr[] , LISTA L ) {
int i;
for ( i = 255 ; i >= 0 ; i-- )
L = inserecabeca ( L , i , arr[i] ) ;
return L ;
}
char * detectfreq ( char * freq ) { // Função que lê o conteúdo do ficheiro e passa-o para um array de char(string).
char c ; // Variável que lê o conteúdo do ficheiro (valor de comparação para EOF)
char *buffer = NULL; // Variável que guardará a string.
size_t size = 0; // Variável que representa o tamanho para a string buffer.
FILE *fp = fopen(freq, "r"); // Abrir o ficheiro para leitura.
// As próximas linhas servem para a mandar o ficheiro para EOF.Isto serve para determinar o tamanho da nossa string
// e o ftell serve para nos dizer quantos caracteres o nosso ficheiro possui para dar um tamanho à string.
do {
c = fgetc(fp) ;
} while ( c != EOF ) ;
size = ftell(fp); // Tamanho da string necessário.
rewind(fp); // O ficheiro volta para o SEEK_SET,ou seja,o inicio do ficheiro,para o voltar a ler.
buffer = malloc((size + 1) * sizeof(*buffer)); // Usando o size,determinamos o tamanho da nossa string,ou então,buffer.Usamos para o malloc para alocar espaço e sizeof para determinar o tamanho de cada elemento do buffer.
size_t gg ;
gg = fread ( buffer , size , 1 , fp ) ; // A partir do nosso file,iremos ler um 1 bloco de size bytes para cada incrementação de buffer.
if ( gg == 0 ) printf ("erro: não foi possível ler o ficheiro.\n") ;
buffer[size] = '\0' ; // Colocar o último elemento ('\0') no array,para indicar o final.
// Fechar o ficheiro.
fclose(fp);
//Devolver a string.
return buffer;
}
void escreveFile ( char * freq , char * file , FileCreated ** list , int rr ) { // Função que escreve uma string num ficheiro.
FILE * fp;
if ( rr == 0 )
fp = fopen("codificacoesShannonFannon.txt.cod","w"); // Abrir o fichero para escrita(Neste caso também criamos o ficheiro se ele não existir.)
else fp = fopen("codificacoesShannonFannon.rle.cod","w");
addFilesCreated ( list , file ) ;
fputs (freq,fp); // fputs é uma função que irá colocar o conteúdo de uma string no ficheiro,neste caso,a string freq para o ficheiro fp.
fclose(fp); // Fechar o ficheiro fp.
//return (fp); // Retornar fp.
}
long long int somal ( LISTA * l , int ai , int af ) {
long long int s = 0 ;
int i ;
LISTA t = *l ;
for ( i = 0 ; i < ai ; i++ , t = t->prox ) ;
for ( ; i <= af ; i++ , t = t->prox )
s += t->frequ ;
return s ;
}
int melhordivisao ( LISTA * l , int ai , int af ) {
int dv = ai ;
int i ;
long long int g1 = 0 ;
long long int total = somal ( l , ai , af );
long long int mindif = total ;
long long int dif = total ;
do {
LISTA t = *l ;
for ( i = 0 ; i < dv ; i++ , t = t->prox ) ;
g1 = g1 + t->frequ ;
dif = llabs( 2 * g1 - total ) ;
if ( dif <= mindif ) {
dv++ ;
mindif = dif ;
}
else dif = mindif + 1 ;
} while ( dif == mindif ) ;
return ( dv - 1 ) ;
}
void addSF ( char * c , char d ) {
int i = 0 ;
for ( ; c[i] ; i++ ) ;
c = realloc ( c , (i+1)*sizeof(char) ) ;
c[i] = d ;
}
void ShannonFannon ( LISTA * l , int ai , int af ) {
int i ;
if ( ai != af ) {
int div = melhordivisao ( l , ai , af ) ;
LISTA t = *l ;
for ( i = 0 ; i < ai ; i++ , t = t->prox ) ;
for ( ; i <= div ; i++ , t = t->prox )
addSF ( t->codSF , '0' ) ;
for ( ; i <= af ; i++ , t = t->prox )
addSF ( t->codSF , '1' );
ShannonFannon ( l , ai , div ) ;
ShannonFannon ( l , div + 1 , af ) ;
}
return ;
}
/* Funde duas listas ordenadas uma com a outra, formando outra lista ordenada
Faz isso avançando em cada uma das listas e colocando elementos na lista maior */
LISTA SortedMerge ( LISTA a , LISTA b , int fl ) {
LISTA result = NULL;
// Quando uma das listas é vazia
if (a == NULL)
return (b);
else if (b == NULL)
return (a);
// Vai fundindo as listas, usando recorrência
// Escolhe o valor maior para colocar e avança nessa lista
if ( ( fl == 1 && a->frequ > b->frequ ) || ( fl == 2 && a->simbolo < b->simbolo ) ) {
result = a;
result->prox = SortedMerge ( a->prox , b , fl ) ;
}
else {
result = b;
result->prox = SortedMerge ( a , b->prox , fl ) ;
}
return result ;
}
/* Separa a lista em duas metades e retorna as duas listas usando parâmetros de referência
Se o comprimento da lista for ímpar, o nodo extra vai para a primeira lista
Usa a estratégia de avançar um apontador duas vezes mais rápido que o outro,
de modo a um chegar ao meio quando o outro chega ao fim. */
void Divisao ( LISTA source , LISTA * a , LISTA * b ) {
LISTA l2;
LISTA l1;
l1 = source;
l2 = source->prox;
// Avança 'l2' dois nodos, e avança 'l1' um nodo
while ( l2 != NULL ) {
l2 = l2->prox;
if ( l2 != NULL ) {
l1 = l1->prox;
l2 = l2->prox;
}
}
// 'l1' é antes do meio da lista, portanto divide-se em dois aí
*a = source;
*b = l1->prox;
l1->prox = NULL;
}
void MergeSort ( LISTA * L , int fl ) {
LISTA a = crialista() ;
LISTA b = crialista() ;
// Caso a lista tenha 0 ou 1 elementos, fica igual
if (( *L == NULL ) || ( (*L)->prox == NULL )) {
return ;
}
// Dividimos a lista em duas sublistas
Divisao ( *L , &a , &b ) ;
// Fazemos a MergeSort de cada uma das sublistas
MergeSort ( &a , fl ) ;
MergeSort ( &b , fl ) ;
// No fim, fundimos as duas listas ordenadas uma com a outra
*L = SortedMerge ( a , b , fl ) ;
}
long long int * freqread ( char * a ) {
long long int val = 1 ;
char * p ;
int arrobacheck = 0 ;
long long int i ;
int j ;
long long int * arr = malloc(256 * sizeof(long long int)) ;
for ( i = 0 , j = 0 ; arrobacheck != 2 ; i++ ) {
for ( ; a[i] == ';' || a[i] == '@' ; i++ , j++ ) {
if ( a[i] == '@' && arrobacheck == 1 ) arrobacheck = 2 ;
else {
if ( a[i] == '@' && arrobacheck == 0 ) arrobacheck = 1 ;
if ( a[i + 1] != ';') {
p = &a[i+1] ;
val = atoi(p);
arr[j] = val;
}
else {
arr[j] = arr[j-1];
}
}
}
}
return arr ;
}
long long int counti (long long int i , char * a ) {
int arrobacheck = 0 ;
long long int j ;
for ( j = 0 ; arrobacheck != 1 ; j++ , i++ ) {
if ( a[j] == '@')
arrobacheck = 1 ;
}
return i ;
}
int countn ( LISTA * l ) {
LISTA t = *l ;
int n = 0 ;
for ( ; (t->frequ) != 0 && n < 255 ; n++ , t = t->prox ) ;
return n;
}
void moduleTMain ( Options * opts , FileCreated ** list ) { //ff é o nome fo ficheiro .freq que usamos como argumento.
clock_t tinicio = clock();
long long int i , ii ; // índice do array frq e do final, respetivamente
char * final = malloc ( 3 * sizeof(long long int) ) ; // array que vai dar origem ao ficheiro cod final
long long int sizefi = 3 ;
long long int blocos = 0; // numero de blocos
long long int * tam_b1 = NULL ;
long long int * tam_b2 = NULL ;
int rr;
// para começar, precisamos de uma função que transforme o FILE num array de chars, exatamente igual ao FILE.
char * frq;
frq = detectfreq( opts->fileIN );
//coloca as informações iniciais no array final
final[0] = '@' ;
final[1] = frq[1] ;
final[2] = '@' ;
if ( frq[1] == 'R' ) rr = 1 ;
else rr = 0 ;
long long int * numblock = freqread (&frq[2]);
for ( ii = 3 ; frq[ii] != '@' ; ii++ ) {
if ( ii >= sizefi ) {
sizefi *= 2 ;
final = realloc ( final , sizefi * sizeof(char) ) ;
}
final[ii] = frq[ii] ;
}
if ( ii > sizefi ) {
sizefi *= 2 ;
final = realloc ( final , sizefi * sizeof(char) ) ;
}
final[ii] = '@' ;
i = ii ;
// este while serve para vermos um bloco de cada vez. Ele acaba quando temos "@0"
while ( frq[i+1] != '0' ) {
blocos++;
if (blocos == 1) {
tam_b1 = freqread(&frq[i]);
}
if (blocos == numblock[0]) {
tam_b2 = freqread(&frq[i]);
}
// avança para a informação do tamanho do bloco
i++; ii++;
// põe a informação do tamanho do bloco no array final
for ( ; frq[i] != '@' ; i++ , ii++ ) {
if ( ii > sizefi ) {
sizefi *= 2 ;
final = realloc ( final , sizefi * sizeof(char) ) ;
}
final[ii] = frq[i] ;
}
final[ii] = '@' ;
ii++;
// pegar nesta parte do array de char e transforma-la numa lista ligada de inteiros
long long int * arr ;
arr = freqread ( &frq[i] ) ;
i = counti ( i , &frq[i+1] ) ;
LISTA l = crialista() ;
l = metenalista ( arr , l ) ;
free (arr) ;
// fazer uma ordenação eficiente da lista através das frequências
MergeSort ( &l , 1 ) ;
int n ;
n = countn ( &l ) ;
// atribuir códigos Shannon-Fannon aos símbolos
ShannonFannon ( &l , 0 , n ) ;
// ordenar a lista em função dos simbolos
MergeSort ( &l , 2 ) ;
// meter os códigos SF no array final e dá free da lista
int k ; // para percorrer cada codSF, que sao arrays de chars
// perceorre a lista, colocando os codSF
while ( l->prox != NULL ) {
char * c ;
c = l->codSF ;
// percorremos o codSF de cada nodo, colocando char a char no array final
// de notar que se aquele nodo não tiver codSF, não é colocado nada
for ( k = 0 ; c[k] ; k++ , ii++ ) {
if ( ii >= sizefi ) {
sizefi *= 2 ;
final = realloc ( final , sizefi * sizeof(char) ) ;
}
final[ii] = c[k] ;
}
// liberta o nodo que já obtivemos a informação
LISTA temporaria = l ;
l = l->prox ;
free ( temporaria->codSF ) ;
free ( temporaria ) ;
// coloca o ; no final, para separar os valores, ela só não é colocada no último
if ( l != NULL ) {
if ( ii >= sizefi ) {
sizefi *= 2 ;
final = realloc ( final , sizefi * sizeof(char) ) ;
}
final[ii] = ';' ;
ii++ ;
}
}
if ( ii >= sizefi ) {
sizefi *= 2 ;
final = realloc ( final , sizefi * sizeof(char) ) ;
}
final[ii] = '@' ;
}
free (frq) ;
ii++;
final[ii] = '0';
//função que transforma o array de chars que temos num ficheiro
escreveFile ( final , opts->fileIN , list , rr ) ;
free(final) ;
clock_t tfim = clock();
float ttime ;
ttime = ((double)(tfim - tinicio)) / CLOCKS_PER_SEC * 1000 ;
if ( tam_b1 && tam_b2 ) {
if ( rr == 0 )
printf ("Inês Vicente, a93269, Tomás Francisco, a93193 MIEI/CD, 3-jan-2021\nMódulo: t (cálculo dos códigos dos símbolos)\nNúmero de blocos: %lld\nTamanho dos blocos analisados no ficheiro de símbolos: %lld/%lld bytes\nTempo de execução do módulo (milissegundos): %f\nFicheiro gerado: codificacoesShannonFannon.txt.cod \n", numblock[0] , tam_b1[0] , tam_b2[0] ,ttime ) ;
else printf ("Inês Vicente, a93269, Tomás Francisco, a93193 MIEI/CD, 3-jan-2021\nMódulo: t (cálculo dos códigos dos símbolos)\nNúmero de blocos: %lld\nTamanho dos blocos analisados no ficheiro de símbolos: %lld/%lld bytes\nTempo de execução do módulo (milissegundos): %f\nFicheiro gerado: codificacoesShannonFannon.rle.cod \n", numblock[0] , tam_b1[0] , tam_b2[0] ,ttime ) ;
} else printf ("erro: o ficheiro freq não tem nenhum bloco de codificação.\n") ;
//return cod;
}
#endif