domingo, 29 de novembro de 2015

LAB 5 / CES 11

          Olá! Nesta publicação, o projeto tinha a função de avaliar a manipulação de grafos, através de algoritmos como o de Dijkstra, DFS (Depth-First Search) e de Tarjan modificado para verificar a ciclicidade de um dígrafo. A ideia seria a de fornecer a uma agência aérea: os menores caminhos (custo-mínimo) e os ciclos existentes entre aeroportos. Acompanhe a seguir:



 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #include <stdbool.h>  
 #define INFINITO 1000000  
 typedef int vertice;  
 typedef struct CelAdj CelAdj;  
 struct CelAdj  
 {  
   vertice vert;  
   int minutos;  
   CelAdj *prox;  
 };  
 typedef struct CelVert CelVert;  
 struct CelVert  
 {  
   char aeroporto[30];  
   CelAdj *listaAdj;  
 };  
 typedef struct digrafo digrafo;  
 struct digrafo  
 {  
   int nvert;  
   CelVert *vertices;  
 };  
 typedef struct node node;  
 struct node  
 {  
   int vertice;  
   node *prox;  
 };  
 typedef node *pilha;  
 typedef node *posicao;  
 void BubbleSort (digrafo *G)  
 {  
   //EXECUTA 'BUBBLE-SORT' NAS LISTAS ADJACENTES DO DIGRAFO G  
   int i, vert_aux, minutos_aux;  
   CelAdj *P;  
   bool mudou = true;  
   for(i = 0; i <= G->nvert-1; i++)  
   {  
     P = G->vertices[i].listaAdj;  
     while(mudou == true)  
     {  
       mudou = false;  
       P = G->vertices[i].listaAdj;  
       while(P->prox != NULL)  
       {  
         if(P->vert > P->prox->vert)  
         {  
           vert_aux = P->vert;  
           minutos_aux = P->minutos;  
           P->vert = P->prox->vert;  
           P->minutos = P->prox->minutos;  
           P->prox->vert = vert_aux;  
           P->prox->minutos = minutos_aux;  
           mudou = true;  
         }  
         P = P->prox;  
       }  
     }  
   }  
 }  
 int Dijkstra(digrafo G, int ref, int desc, vertice parent[], vertice dist[])  
 {  
   vertice v, w, v_aux, w_aux;  
   CelAdj *P;  
   for (w = 0; w <= G.nvert-1; w++)  
   {  
     parent[w] = -1;  
     dist[w] = INFINITO;  
   }  
   parent[ref] = ref;  
   dist[ref] = 0;  
   while (1)  
   {  
     //EXECUTA O LOOP ENQUANTO ALGUMA DISTANCIA SOFRE ALTERACAO, TODA VEZ QUE SE PERCORRE O DIGRAFO  
     int min_dist = INFINITO;  
     for (v = 0; v <= G.nvert-1; v++)  
       if (parent[v] != -1)  
         for (P = G.vertices[v].listaAdj; P != NULL; P = P->prox)  
           if (parent[P->vert] == -1 && min_dist > dist[v] + P->minutos)  
           {  
             min_dist = dist[v] + P->minutos;  
             v_aux = v;  
             w_aux = P->vert;  
           }  
     if (min_dist == INFINITO)  
       break;  
     parent[w_aux] = v_aux;  
     dist[w_aux] = min_dist;  
   }  
   return dist[desc];  
 }  
 void push (pilha *P, vertice v)  
 {  
   node *temp;  
   temp = *P;  
   *P = (node *) malloc (sizeof (node));  
   (*P)->vertice = v;  
   (*P)->prox = temp;  
 }  
 void pop (pilha *P)  
 {  
   node *temp;  
   temp = *P;  
   *P = (*P)->prox;  
   free (temp);  
 }  
 void DFS(vertice v, bool *aciclico, vertice *expl, vertice *comp, pilha *P, int *ce, int *cc, digrafo G, FILE *f_saida)  
 {  
   expl[v] = ++(*ce);  
   push(P,v);  
   CelAdj *Q;  
   for(Q = G.vertices[v].listaAdj; Q != NULL; Q = Q->prox)  
     if(expl[Q->vert] == 0) //CASO AINDA NAO TENHA SIDO EXPLORADO, ENTRA NESSE VERTICE  
       DFS(Q->vert, aciclico, expl, comp, P, ce, cc, G, f_saida);  
     else if (expl[Q->vert] < expl[v] && comp[Q->vert]==0)  
     {  
       //CASO SEJA UMA ARESTA DE RETORNO (B), MOSTRA CILICIDADE, E IMPRIME O CICLO  
       *aciclico = false;  
       int j, tamanho_pilha = 0;  
       posicao T, F;  
       T = *P;  
       while(T->prox != NULL)  
       {  
         T = T->prox;  
         tamanho_pilha++;  
       }  
       F = T;  
       while(tamanho_pilha >= 0)  
       {  
         for(j = tamanho_pilha, T = *P; j >= 1; j--)  
           T = T->prox;  
         fprintf(f_saida, "%d-", T->vertice);  
         tamanho_pilha--;  
       }  
       fprintf(f_saida, "%d\n", F->vertice);  
     }  
   pop(P);  
   comp[v] = ++(*cc);  
 }  
 void Ciclos (digrafo G, vertice *expl, vertice *comp, FILE *f_saida)  
 {  
   pilha P;  
   P = NULL;  
   bool aciclico = true;  
   int ce = 0, cc = 0;  
   vertice v;  
   for (v = 0; v <= G.nvert-1; v++)  
   {  
     expl[v] = 0;  
     comp[v] = 0;  
   }  
   for (v = 0; v <= G.nvert-1; v++)  
     if (expl[v] == 0)  
       DFS(v, &aciclico, expl, comp, &P, &ce, &cc, G, f_saida);  
 }  
 int main()  
 {  
   digrafo G;  
   FILE *f_entrada, *f_saida;  
   f_entrada = fopen("entrada.txt", "r");  
   f_saida = fopen("saida.txt", "w");  
   int i;  
   /** RECEBE OS VERTICES **/  
   char aeroporto[31], lixo;  
   fscanf(f_entrada, "%d%c", &G.nvert, &lixo);  
   G.vertices = (CelVert *)malloc(G.nvert * sizeof(CelVert));  
   for(i = 0; i <= G.nvert-1; i++)  
     G.vertices[i].listaAdj = NULL;       //ZERA TODAS AS LISTAS ADJACENTES  
   for(i = 0; i <= G.nvert-1; i++)  
   {  
     fgets(aeroporto, 31, f_entrada);  
     aeroporto[strlen(aeroporto)-1] = '\0';   //TIRA O '\N' DO FINAL DA STRING  
     strcpy(G.vertices[i].aeroporto, aeroporto); //PASSA O NOME PARA O DIGRAFO  
   }  
   /** RECEBE OS ARCOS **/  
   int quant_arcos;  
   fscanf(f_entrada, "%d", &quant_arcos);  
   int pred, suc, custo;  
   CelAdj *P;  
   for(i = 1; i <= quant_arcos; i++)  
   {  
     fscanf(f_entrada, "%d %d %d", &pred, &suc, &custo);  
     if(G.vertices[pred].listaAdj == NULL)    //INICIA A LISTA ADJACENTE DE 'PRED'  
     {  
       P = G.vertices[pred].listaAdj = (CelAdj *)malloc(sizeof(CelAdj));  
       P->vert = suc;  
       P->minutos = custo;  
       P->prox = NULL;  
     }  
     else                    //CONTINUA A LISTA ADJACENTE JA INICIADA  
     {  
       P->prox = (CelAdj *)malloc(sizeof(CelAdj));  
       P = P->prox;  
       P->vert = suc;  
       P->minutos = custo;  
       P->prox = NULL;  
     }  
   }  
   BubbleSort(&G);                 //ORDENA AS LISTAS DE ADJACENCIAS  
   fprintf(f_saida ,"Digrafo:\n");  
   for(i = 0; i <= G.nvert-1; i++)  
   {  
     fprintf(f_saida, "%d (%s):", i, G.vertices[i].aeroporto);  
     P = G.vertices[i].listaAdj;  
     while(P != NULL)  
     {  
       fprintf(f_saida, " %d(%d)", P->vert, P->minutos);  
       P = P->prox;  
     }  
     fprintf(f_saida, "\n");  
   }  
   fprintf(f_saida, "\n");  
   /** CONSULTAS DE ROTAS MINIMAS **/  
   fprintf(f_saida, "Rotas minimas:\n");  
   int c, partida, chegada, dist_esp;         //CONSULTA DE ROTAS MINIMAS  
   vertice *dist;                   //VETOR DE PONTEIROS PARA INT  
   vertice *parent;                  //VETOR DE PAIS DE UM VERTICE  
   vertice vert, filho;  
   dist = (vertice *)malloc(G.nvert * sizeof(vertice));  
   parent = (vertice *)malloc(G.nvert * sizeof(vertice));  
   fscanf(f_entrada, "%d", &c);  
   for(i = 1; i <= c; i++)               //PARA CADA 'C', EXECUTA O ALG. DIJKSTRA  
   {  
     fscanf(f_entrada, "%d %d", &partida, &chegada);  
     fprintf(f_saida, "%d a %d: ", partida, chegada);  
     if(partida == chegada)  
       fprintf(f_saida, "(0 minutos)\n");  
     else  
     {  
       dist_esp = Dijkstra(G, partida, chegada, parent, dist); //EXECUTA DIJKSTRA PARA DEFINIR 'PARENT'  
       if(dist[chegada] == INFINITO)  
         fprintf(f_saida, "sem voos\n");  
       else  
       {  
         while (partida != chegada)             //IMPRIME O CAMINHO A SER SEGUIDO  
         {  
           for(vert = chegada; vert != partida; vert = parent[vert])  
             filho = vert;  
           fprintf(f_saida, "%d-", vert);  
           partida = filho;  
         }  
         fprintf(f_saida, "%d ", chegada);  
         fprintf(f_saida, "(%d minutos)\n", dist_esp);  
       }  
     }  
   }  
   fprintf(f_saida, "\n");  
   fclose(f_entrada);  
   /** ANALISE DE TRAJETOS FECHADOS **/  
   fprintf(f_saida, "Trajetos fechados:\n");  
   vertice *expl, *comp;  
   expl = (vertice *)malloc(G.nvert * sizeof(vertice));  
   comp = (vertice *)malloc(G.nvert * sizeof(vertice));  
   Ciclos(G, expl, comp, f_saida);           //IMPRIME OS CICLOS, SE EXISTIREM  
   fclose(f_saida);  
   return 0;  
 }  

quarta-feira, 18 de novembro de 2015

LAB4 - Trabalhando com HeapSort e MergeSort

          Olá! Neste laboratório, o que foi proposto é a leitura de elementos obtidos a partir de um documento de texto "entrada.txt" e, a partir dos algoritmos de ordenação HeapSort e MergeSort, ordená-los e escrever um novo arquivo "saida.txt", contendo esses elementos já ordenados e as unidades de tempo necessárias para executar essa operação por completo.
          Veja, abaixo, a execução do programa e o código, por completo:


 /**     GUSTAVO NAHUM ALVAREZ FERREIRA     **/  
 /**     TURMA: 19.3               **/  
 /**     LAB 4 - CES 11             **/  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <stdbool.h>  
 #include <string.h>  
 #define teto 1000000  
 ///FORAM USADAS DUAS STRUCTS: O NODE (UNIDADE DAS LISTAS LIGADAS)...  
 typedef struct node node;  
 struct node  
 {  
   int num;  
   node *prox;  
 };  
 typedef node *posicao;  
 ///...E O NODE_HEAP (UNIDADE DO VETOR, QUE CONTERÁ O TAMANHO E O PONTEIRO PARA O INÍCIO DAS LISTAS)  
 typedef struct node_heap node_heap;  
 struct node_heap  
 {  
   int tamanho;  
   node *inicio;  
 };  
 typedef node_heap *heap;  
 //RETORNA A QUANTIDADE DE SUBSEQUENCIAS MAXIMAIS DO ARQUIVO LIDO  
 int quantidadeSubsequencias ()  
 {  
   //O INT NUM_ANT FOI INICIALIZADO COM "TETO", OU SEJA, 1000000...  
   //...POIS SE DESEJA QUE PASSE NA CONDICAO "IF" NA PRIMEIRA VEZ  
   int quantidade = 0, num_atual = 0, num_ant = teto;  
   FILE *f_entrada;  
   f_entrada = fopen("entrada.txt", "r");  
   while(fscanf(f_entrada, "%d", &num_atual) != EOF)  
   {  
     if(num_atual < num_ant)  
       quantidade++;  
     num_ant = num_atual;  
   }  
   fclose(f_entrada);  
   return quantidade;  
 }  
 //LE, PELA SEGUNDA VEZ, O ARQUIVO, E MONTA AS LISTAS QUE CONTEM AS SUBSEQUENCIAS  
 void criaHeap (heap H, int quantidade)  
 {  
   int i = 0;  
   node *P;  
   int num_ant = teto, num_atual;  
   FILE *f_entrada;  
   f_entrada = fopen("entrada.txt", "r");  
   i = 0;  
   while(fscanf(f_entrada, "%d", &num_atual) != EOF)  
   {  
     if(num_atual < num_ant)  
     {  
       //CASO "NUM_ATUAL" < "NUM_ANT", AVANCA-SE NO VETOR DE "HEAP_NODE"  
       //E O ESPACO "H[i].TAMANHO" EH INICIALIZADO COM 1 (POIS, AGORA, JA  
       //EXISTE UM PRIMEIRO "NODE" ALI)  
       H[++i].inicio = (node*)malloc(sizeof(node));  
       P = H[i].inicio;  
       P->num = num_atual;  
       P->prox = NULL;  
       num_ant = num_atual;  
       H[i].tamanho = 1;  
     }  
     else  
     {  
       //CASO CONTRARIO, AVANCA-SE NA LISTA DE UM MESMO "H[i]"  
       //E, LOGO, HA UM ACRESCIMO EM "H[i].TAMANHO"  
       P->prox = (node*)malloc(sizeof(node));  
       P = P->prox;  
       P->num = num_atual;  
       P->prox = NULL;  
       num_ant = num_atual;  
       H[i].tamanho++;  
     }  
   }  
   fclose(f_entrada);  
 }  
 ///ALGORITMO "SIFT", AUXILIAR DE "HEAP-SORT"  
 void Sift(int i, int n, heap H)  
 {  
   int esq = 2*i;  
   int dir = 2*i+1;  
   int maior = i;  
   if (esq <= n && H[esq].tamanho > H[i].tamanho)  
     maior = esq;  
   if (dir <= n && H[dir].tamanho > H[maior].tamanho)  
     maior = dir;  
   if (maior != i)  
   {  
     node *aux;  
     int aux_int;  
     aux = H[i].inicio;  
     aux_int = H[i].tamanho;  
     H[i].inicio = H[maior].inicio;  
     H[i].tamanho = H[maior].tamanho;  
     H[maior].inicio = aux;  
     H[maior].tamanho = aux_int;  
     Sift(maior, n, H);  
   }  
 }  
 ///ALGORITMO "BUILD", AUXILIAR DE "HEAP-SORT"  
 void Build(heap H, int quantidade)  
 {  
   int i;  
   for (i = quantidade/2; i > 0; i--)  
     Sift(i, quantidade, H);  
 }  
 ///ALGORITMO "HEAP-SORT"  
 void HeapSort(heap H, int quantidade)  
 {  
   Build(H, quantidade);  
   int i;  
   for (i=quantidade; i>1; i--)  
   {  
     node *aux;  
     int aux_int;  
     aux = H[i].inicio;  
     aux_int = H[i].tamanho;  
     H[i].inicio = H[1].inicio;  
     H[i].tamanho = H[1].tamanho;  
     H[1].inicio = aux;  
     H[1].tamanho = aux_int;  
     Sift(1, i-1, H);  
   }  
 }  
 ///ALGORITMO "MERGE-SORT" (ADAPTADO PARA O PROBLEMA)  
 int MergeSort(heap H)  
 {  
   //VAI TOMAR AS DUAS LISTAS LIGADAS INICIADAS COM "H[1].INICIO" E "H[2].INICIO"  
   //E, COM O AUXILIO DOS PONTEIROS "P1", "P2" E "AUX", VAI INTERCALAR OS "NODES"  
   //E OS SEUS "PROX" EM ORDEM CRESCENTE  
   posicao P1, P2, aux;  
   P1 = H[1].inicio;  
   P2 = H[2].inicio;  
   int tempo = H[1].tamanho + H[2].tamanho;  
   if(P1->num < P2->num)  
   {  
     H[1].inicio = P1;  
     P1 = P1->prox;  
   }  
   else  
   {  
     H[1].inicio = P2;  
     P2 = P2->prox;  
   }  
   while(P1->prox != NULL && P2->prox != NULL)  
   {  
     if(P1->num < P2->num)  
     {  
       if(P1->prox->num < P2->num)  
         P1 = P1->prox;  
       else  
       {  
         aux = P1->prox;  
         P1->prox = P2;  
         P1 = aux;  
       }  
     }  
     else  
     {  
       if(P2->prox->num < P1->num)  
         P2 = P2->prox;  
       else  
       {  
         aux = P2->prox;  
         P2->prox = P1;  
         P2 = aux;  
       }  
     }  
   }  
   if(P1->prox == NULL)  
   {  
     while(P2->prox != NULL && P2->prox->num < P1->num)  
       P2 = P2->prox;  
     if(P2->prox == NULL)  
     {  
       if(P2->num < P1->num)  
         P2->prox = P1;  
       else  
         P1->prox = P2;  
     }  
     else if(P2->num < P1->num)  
     {  
       aux = P2->prox;  
       P2->prox = P1;  
       P1->prox = aux;  
     }  
     else  
       P1->prox = P2;  
   }  
   if(P2->prox == NULL)  
   {  
     while(P1->prox != NULL && P1->prox->num < P2->num)  
       P1 = P1->prox;  
     if(P1->prox == NULL)  
     {  
       if(P1->num < P2->num)  
         P1->prox = P2;  
       else  
         P2->prox = P1;  
     }  
     else if(P1->num < P2->num)  
     {  
       aux = P1->prox;  
       P1->prox = P2;  
       P2->prox = aux;  
     }  
     else  
       P2->prox = P1;  
   }  
   return tempo;  
 }  
 int main()  
 {  
   //RESTA, NA MAIN, CHAMAR AS FUNCOES AUXILIARES E OBTER "UNIDADES_TEMPO"  
   int i, quantidade, unidades_tempo = 0;  
   node *P;  
   heap H;  
   /**     PASSO I      **/  
   quantidade = quantidadeSubsequencias();  
   /**     PASSO II      **/  
   H = (node_heap *) malloc ((quantidade+1) * sizeof(node_heap));  
   criaHeap(H, quantidade);  
   HeapSort(H, quantidade);  
   /**     PASSO III     **/  
   while(H[2].inicio != NULL)  
   {  
     //AQUI, ENFIM, OBTEM-SE AS "UNIDADES_TEMPO"  
     unidades_tempo += MergeSort(H);  
     H[1].tamanho = H[1].tamanho + H[2].tamanho;  
     H[2].inicio = NULL;  
     H[2].tamanho = teto;  
     HeapSort(H, quantidade);  
   }  
   /**     PASSO IV      **/  
   FILE *f_saida;  
   f_saida = fopen("saida.txt", "w");  
   for(P = H[1].inicio; P != NULL; P = P->prox)  
     fprintf(f_saida, "%d\n", P->num);  
   /**     PASSO V      **/  
   fprintf(f_saida, "%d\n", unidades_tempo);  
   fclose(f_saida);  
   return 0;  
 }  

domingo, 25 de outubro de 2015

LAB 3 - CES 11

          Olá! Agora apresento o meu código para o LAB 3 de CES 11. Nele, o objetivo era o de criar um contador de palavras, a partir da implementação da estrutura de dados árvore. Para auxiliar nesse trabalho, também foi implementada uma pilha de caracteres alocada dinamicamente, facilitando a impressão das palavras. Acompanhe o vídeo abaixo e, a seguir, veja o código comentado:


 /***     ALUNO: GUSTAVO NAHUM ALVAREZ FERREIRA      ***/  
 /***     TURMA: 19.3                   ***/  
 /***     LAB 3 - CES 11                 ***/  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #include <stdbool.h>  
 #include <ctype.h>  
 /**   O MÁXIMO É REFERENTE À QUANTIDADE DE ELEMENTOS DA STRING QUE RECEBERÁ AS LINHAS DE "entrada.txt"   **/  
 #define max 100  
 /**   AS DUAS ESTRUTURAS DE DADOS USADAS NO CÓDIGO FORAM A árvore, A PARTIR DE células, E A pilha, A PARTIR DE nodes. A árvore SERÁ NECESSÁRIA AO LONGO DE TODO O CÓDIGO   **/  
 typedef struct celula celula;  
 struct celula  
 {  
   char letra;  
   int cont;  
   celula *filhos[26];  
 };  
 typedef celula *arvore;  
 typedef celula *posicao;  
 /**   A pilha SERÁ IMPORTANTE PARA AUXILIAR NA IMPRESSÃO DAS PALAVRAS CONTIDAS NA árvore   **/  
 typedef struct node node;  
 struct node  
 {  
   char elem;  
   node *prox;  
 };  
 typedef node *pilha;  
 /**   A FUNÇÃO "alocaArvore" CRIA O "NÓ-LÍDER" DA árvore, E APONTA PARA AS LETRAS INICIAIS DAS PALAVRAS. ELA SERÁ USADA NA "main", PARA ALOCAR A árvore USADA EM TODO O PROGRAMA   **/  
 void alocaArvore (arvore *A)  
 {  
   (*A) = (celula *)malloc(sizeof(celula));  
   (*A)->letra = '#';  
   (*A)->cont = 0;  
   int i;  
   for(i = 0; i <= 25; i++)  
     (*A)->filhos[i] = NULL;  
 }  
 /**   A FUNÇÃO "alocaCelula" CRIA UMA NOVA célula E INSERE A LETRA CORRESPONDENTE. ELA SERÁ USADA EM "lerArquivo", NA HORA DE INSERIR AS LETRAS DAS PALAVRAS   **/  
 void alocaCelula (celula **P, char c)  
 {  
   (*P) = (celula *)malloc(sizeof(celula));  
   (*P)->letra = c;  
   (*P)->cont = 0;  
   int i;  
   for(i = 0; i <= 25; i++)  
     (*P)->filhos[i] = NULL;  
 }  
 /**   A FUNÇÃO "numFilhos" RETORNA O VALOR NUMÉRICO CORRESPONDENTE A UMA LETRA DADA: "a" E "A" CORRESPONDEM AO "0", "b" E "B" CORRESPONDEM AO "1", ETC. ELA SERÁ IMPORTANTE PARA FACILITAR A CONVERSÃO DE MAIÚSCULAS EM MINÚSCULAS EM "lerArquivo"   **/  
 int numFilhos(char carac)  
 {  
   if(islower(carac))  
     return carac - 'a';  
   else  
     return carac - 'A';  
 }  
 /**   A FUNÇÃO "lerArquivo" DEVERÁ LER O ARQUIVO "entrada.txt" E GERAR A árvore CORRESPONDENTE. COM ESSA árvore, A FUNÇÃO "imprimirArquivo" PODERÁ IMPRIMIR AS PALAVRAS E SUAS QUANTIDADES DE APARIÇÃO EM "entrada.txt"   **/  
 void lerArquivo(FILE *f_entrada, arvore *A)  
 {  
   char string[max];  
   int i, aux;  
   posicao P;  
   P = *A;  
   while(fgets(string, max, f_entrada) != NULL)  /* RECEBE, LINHA A LINHA, O CONTEÚDO DE "entrada.txt" */  
   {  
     for(i = 0; i <= strlen(string)-1; i++)   /* ANALISA, LETRA A LETRA, O CONTEÚDO DAS LINHAS: */  
     {  
       if(isalpha(string[i]))         /* 1. SE FOR ALFA-NUMÉRICO, A LETRA VAI PARA A PRÓXIMA CÉLULA */  
       {  
         if(P->filhos[numFilhos(string[i])] == NULL)  
           alocaCelula(&P->filhos[numFilhos(string[i])], numFilhos(string[i])+'a');  
         P = P->filhos[numFilhos(string[i])];  
       }  
       else                  /* 2. SE NÃO FOR ALFA-NUMÉRICO, A CÉLULA INCREMENTA O CONTADOR... */  
       {                    /* ...E RETORNA AO TOPO DA ÁRVORE, PARA INICIAR A LEITURA DE UMA NOVA PALAVRA */  
         P->cont++;  
         P = *A;  
       }  
     }  
   }  
 }  
 /**   A FUNÇÃO "tamanhoPilha" RETORNA A QUANTIDADE DE nodes DA pilha. ELA SERÁ USADA PARA AUXILIAR A FUNÇÃO "imprimePilhaReversa"   **/  
 int tamanhoPilha(pilha P)  
 {  
   int i;  
   node *Q;  
   Q = P;  
   for (i = 0; Q != NULL; Q = Q->prox)  
     i++;  
   return i;  
 }  
 /**   A FUNÇÃO "imprimePilhaReversa" IMPRIME OS VALORES DA pilha, DO ÚLTIMO PARA O PRIMEIRO ELEMENTO. ELA SERÁ USADA NA FUNÇÃO "imprimeArquivo"   **/  
 void imprimePilhaReversa(FILE *f_saida, pilha P)  
 {  
   int i, j;  
   node *Q;  
   for(j = tamanhoPilha(P); j>= 1; j--)  
   {  
     Q = P;  
     for(i = 1; i < j; i++)  
       Q = Q->prox;  
     fprintf(f_saida, "%c", Q->elem);  
   }  
   fprintf(f_saida, "\n");  
 }  
 /**   A FUNÇÃO RECURSIVA "imprimeArquivo" TOMA A árvore PRODUZIDA EM "lerArquivo" E USA UMA PILHA QUE É ALTERADA CONTINUAMENTE. ESSA pilha SERVE PARA GUARDAR AS PALAVRAS QUE SERÃO IMPRESSAS EM "saida.txt"   **/  
 void imprimeArquivo (FILE *f_saida, posicao A, pilha *P)  
 {  
   int i;  
   for(i = 0; i <= 25; i++)    /* PERCORRERÁ OS CAMPOS filhos[i], PARA ENCONTRAR POSSÍVEIS CONTINUAÇÕES PARA AS PALAVRAS */  
   {  
     if(A->filhos[i] != NULL)  /* SE HOUVER CONTINUAÇÃO, ELA É INSERIDA NA pilha */  
     {  
       node *Q;  
       Q = (node *)malloc(sizeof(node));  
       Q->elem = A->filhos[i]->letra;  
       Q->prox = *P;  
       *P = Q;  
       if(A->filhos[i]->cont != 0) /* SE HOUVER UMA PALAVRA ATÉ ALI, ELA SERÁ IMPRESSA EM "saida.txt" */  
       {  
         fprintf(f_saida, "%d ", A->filhos[i]->cont);  
         imprimePilhaReversa(f_saida, *P);  
       }  
       imprimeArquivo(f_saida, A->filhos[i], P);  /* E, RECURSIVAMENTE, ELA FARÁ ISSO COM TODOS OS SEUS FILHOS "NÃO-NULLOS" */  
     }  
   }  
   if(*P != NULL) /* AO FINAL, DESALOCA-SE O node CORRESPONDENTE À LETRA CORRESPONDENTE A ESTE ESCOPO DA FUNÇÃO */  
   {  
     node *D;  
     D = (*P)->prox;  
     free(*P);  
     *P = D;  
   }  
 }  
 int main()  
 {  
   arvore A;  A = NULL;  alocaArvore(&A);  
   pilha P;  P = NULL;  
   FILE *f_entrada, *f_saida;  
   f_entrada = fopen("entrada.txt", "r");  
   f_saida = fopen("saida.txt", "w");  
   lerArquivo(f_entrada, &A);  
   imprimeArquivo(f_saida, A, &P);  
   fclose(f_entrada);  
   fclose(f_saida);  
   return 0;  
 }  

segunda-feira, 5 de outubro de 2015

Questão 4 da prova de CES11:

typedef struct node node;
struct node{
    int num;
    node *fesq, *fdir;
};
typedef node *arvore;
arvore A;

void imprimeMultiplosde5 (arvore A)
{
    if(A != NULL)
    {
        if(A->fesq != NULL)
        {
            if(A->fesq->fesq != NULL)
            {
                if(A->num%5 == 0)
                    printf("%d\n", A->fesq->fesq->num);
            }
            if(A->fesq->fdir != NULL)
            {
                if(A->num%5 == 0)
                    printf("%d\n", A->fesq->fdir->num);
            }
            imprimeMultiplosde5(A->fesq);
        }
        if(A->fdir != NULL)
        {
            if(A->fdir->fesq != NULL)
            {
                if(A->num%5 == 0)
                    printf("%d\n", A->fdir->fesq->num);
            }
            if(A->fdir->fdir != NULL)
            {
                if(A->num%5 == 0)
                    printf("%d\n", A->fdir->fdir->num);
            }
            imprimeMultiplosde5(A->fdir);
        }
    }
}

sexta-feira, 18 de setembro de 2015

Trabalhando com listas ligadas

     Neste projeto, o objetivo foi, sobretudo, trabalhar com listas ligadas, uma primeira estrutura de armazenamento de dados. O laboratório visava ler um Dicionário com expressões típicas do cotidiano iteano, para gravar as informações em um vetor de listas ligadas através de uma função de dispersão. A função em questão foi, no caso, dada pela soma, em ASCII, dos caracteres de cada expressão a ser gravada. Tendo essas informações já gravadas no vetor, foi possível consultar expressões (função 2), inserir significados ainda não contidos na estrutura (função 3), eliminar significados com a ressalva de que, no caso de tal significado ser único, a expressão referente também deveria ser desalocada (função 4), eliminar expressões em si (função 5) e gerar uma nova base de dados, atualizada (função 6). Para ver o código em execução, assista ao vídeo abaixo.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


/********** DEFINEM-SE OS TYPEDEF'S E AS STRUCT'S **********/


typedef struct nodeSignificado nodeSignificado;
typedef struct nodeExpressao nodeExpressao;
typedef nodeExpressao *elementoVetor;
typedef nodeSignificado *acompanhanteSignificado;
typedef nodeExpressao *acompanhanteExpressao;
typedef int contador;

struct nodeSignificado
{
    char significado[50];
    nodeSignificado *prox;
};

struct nodeExpressao
{
    char expressao[50];
    nodeSignificado *listaSignificado;
    nodeExpressao *prox;
};


/********** DEFINEM-SE AS FUNCOES AUXILIARES **********/


void zerarStrings(char expr[50], char signif[50], char aux[101])
{
    /*** ZERA AS STRINGS AUXILIARES, I.E., AS CRIADAS NA MAIN ***/
    contador i;
    for(i=0; i<=49; i++)
    {
        expr[i] = '\0';
        signif[i] = '\0';
        aux[i] = '\0';
    }
    for(i=50; i<=100; i++)
        aux[i] = '\0';
}

int obterASCII(char expr[50], int N)
{
    /*** FAZ A SOMA, EM ASCII, DOS CARACTERES DAS EXPRESSOES ***/
    contador i;
    int ASCII = 0;
    for(i=0; expr[i] != '\0'; i++)
        ASCII += expr[i];
    return ASCII %= N;
}

void inserirSignificado(elementoVetor *V, char expr[50], char signif[50], int N)
{
    int ASCII = obterASCII(expr, N);
    /*** CASO AINDA ESTEJA "NOVO", ALOCARA O nodeExpressao, o nodeSignificado E SALVA OS VALORES DE expr[50] e signif[50] ***/
    if(V[ASCII] == NULL)
    {
        V[ASCII] = (nodeExpressao*) malloc (sizeof(nodeExpressao));
        strcpy(V[ASCII]->expressao, expr);
        V[ASCII]->prox = NULL;
        V[ASCII]->listaSignificado = (nodeSignificado*) malloc (sizeof(nodeSignificado));
        strcpy(V[ASCII]->listaSignificado->significado, signif);
        V[ASCII]->listaSignificado->prox = NULL;
    }
    /*** CASO A PRIMEIRA EXPRESSAO SEJA A PROCURADA ***/
    else if(strcmp(V[ASCII]->expressao, expr) == 0)
    {
        bool encontrouSignificado = false;
        acompanhanteSignificado S;
        S = V[ASCII]->listaSignificado;
        ///TESTARA OS SIGNIFICADOS TENTANDO ENCONTRA-LO
        while(S->prox != NULL)
        {
            if(strcmp(S->significado, signif) == 0)
                encontrouSignificado = true;

            S = S->prox;
        }
        ///TESTARA UMA ULTIMA TENTATIVA, JA QUE O LIMITE VAI ATE S->PROX E, LOGO, AGORA ESTA EM S
        if(encontrouSignificado == false)
        {
            ///CASO AGORA TENHA ENCONTRADO, ENTAO O SIGNIFICADO ESTA LA, E NAO SERA PRECISO FAZER NADA
            if(strcmp(S->significado, signif) == 0)
            {}
            ///CASO NAO TENHA ENCONTRADO, PRECISARA ADICIONAR ESSE SIGNIFICADO
            else
            {
                S->prox = (nodeSignificado *) malloc (sizeof (nodeSignificado));
                strcpy(S->prox->significado, signif);
                S->prox->prox = NULL;
            }
        }
    }
    /*** CASO A PRIMEIRA EXPRESSAO NAO SEJA NECESSARIAMENTE, A PROCURADA ***/
    else
    {
        bool encontrouExpressao = false;
        acompanhanteExpressao E;
        E = V[ASCII];
        /*** PROCURA A EXPRESSAO ***/
        while(E->prox != NULL) ///alteracao feita aqui..., antes era E != NULL
        {
            if(strcmp(V[ASCII]->expressao, expr) == 0)
            {
                encontrouExpressao = true;
                bool encontrouSignificado = false;
                acompanhanteSignificado S;
                S = V[ASCII]->listaSignificado;
                while(S->prox != NULL)
                {
                    if(strcmp(S->significado, signif) == 0)
                        encontrouSignificado = true;

                    S = S->prox;
                }
                if(encontrouSignificado == false)
                {
                    S = (nodeSignificado *) malloc (sizeof (nodeSignificado));
                    strcpy(S->significado, signif);
                    S->prox = NULL;
                }
            }
            E = E->prox;
        }
        /*** CASO NAO A TENHA ENCONTRADO, TESTARA UMA ULTIMA VEZ ***/
        if(encontrouExpressao == false)
        {
            if(strcmp(V[ASCII]->expressao, expr) == 0)
            {
                bool encontrouSignificado = false;
                acompanhanteSignificado S;
                S = V[ASCII]->listaSignificado;
                while(S->prox != NULL)
                {
                    if(strcmp(S->significado, signif) == 0)
                        encontrouSignificado = true;

                    S = S->prox;
                }
                if(encontrouSignificado == false)
                {
                    S = (nodeSignificado *) malloc (sizeof (nodeSignificado));
                    strcpy(S->significado, signif);
                    S->prox = NULL;
                }
            }
            else
            {
                E = (nodeExpressao*)malloc(sizeof(nodeExpressao));
                strcpy(E->expressao, expr);
                E->listaSignificado = (nodeSignificado*)malloc(sizeof(nodeSignificado));
                strcpy(E->listaSignificado->significado, signif);
                E->prox = NULL;
                E->listaSignificado->prox = NULL;
            }
        }
    }
}

void eliminarSignificado(elementoVetor *V, char expr[50], char signif[50], int N)
{
    int ASCII = obterASCII(expr, N);
    acompanhanteExpressao E;
    E = V[ASCII];
    /*** CASO A EXPRESSAO QUE CONTEM O SIGNIFICADO A SER ELIMINADO SEJA (A EXPRESSAO) LOGO A PRIMEIRA ***/
    if(strcmp(E->expressao, expr) == 0)
    {
        acompanhanteSignificado S;
        S = E->listaSignificado;
        ///CASO O SIGNIFICADO A SER ELIMINADO SEJA LOGO O PRIMEIRO
        if(strcmp(S->significado, signif) == 0)
        {
            /// CASO ESSE SIGNIFICADO SEJA UNICO
            if(S->prox == NULL)
            {
                if(V[ASCII]->prox == NULL)
                    V[ASCII] = NULL;
                else
                {
                    V[ASCII] = V[ASCII]->prox;
                    free(E);
                }
            }
            /// CASO ESSE SIGNIFICADO SEJA O PRIMEIRO, MAS NAO SEJA O UNICO QUE A EXPRESSAO APRESENTA
            else
            {
                E->listaSignificado = E->listaSignificado->prox;
                S->prox = NULL;
                free(S);
            }
        }
        /// CASO O SIGNIFICADO DA EXPRESSAO NAO SEJA O PRIMEIRO
        while(S->prox->prox != NULL)
        {
            if(strcmp(S->significado, signif) == 0)
            {
                acompanhanteSignificado T;
                T = S;
                S = S->prox;
                free(T);
            }
            else
                S = S->prox;
        }
        /// SE ESSE SIGNIFICADO FOR O PENULTIMO
        if(strcmp(S->significado, signif) == 0)
        {
            acompanhanteSignificado T;
            T = S;
            S = S->prox;
            free(T);
        }
        /// SE ESSE SIGNIFICADO FOR O ULTIMO
        else if(strcmp(S->prox->significado, signif) == 0)
        {
            acompanhanteSignificado T;
            T = S->prox;
            S->prox = S->prox->prox; //NULL
            free(T);
        }
    }
    /*** CASO A EXPRESSAO NAO SEJA, NECESSARIAMENTE, A PRIMEIRA ***/
    else
    {
        bool encontrouExpressao = false;
        while((E->prox != NULL) && (encontrouExpressao == false))
        {
            if(strcmp(E->expressao, expr) == 0)
                encontrouExpressao = true;
            else
                E = E->prox;
        }
        if(encontrouExpressao == true)
        {
            acompanhanteExpressao F;
            F = E;
            acompanhanteSignificado S;
            S = E->listaSignificado;
            if(strcmp(S->significado, signif) == 0)
            {
                ///CASO SEJA O PRIMEIRO E UNICO SIGNIFICADO, PRECISARA DESALOCAR A EXPRESSAO, TAMBEM
                if(S->prox == NULL)
                {
                    E = E->prox;
                    free(F->listaSignificado);
                    free(F);
                }
                else
                {
                    E->listaSignificado = E->listaSignificado->prox;
                    free(S);
                }
            }
            while(S->prox != NULL)
            {
                if(strcmp(S->significado, signif) == 0)
                {
                    acompanhanteSignificado T;
                    T = S;
                    S = S->prox;
                    free(T);
                }
                else
                    S = S->prox;
            }
            if(strcmp(S->significado, signif) == 0)
            {
                acompanhanteSignificado T;
                T = S;
                S = S->prox;
                free(T);
            }
            else if(strcmp(S->prox->significado, signif) == 0)
            {
                acompanhanteSignificado T;
                T = S->prox;
                S->prox = S->prox->prox;
                free(T);
            }
        }
    }
}

void eliminarExpressao(elementoVetor *V, char expr[50], int N)
{
    int ASCII = obterASCII(expr, N);
    acompanhanteExpressao E, F;
    E = F = V[ASCII];
    /*** CASO A EXPRESSAO A SER ELIMINADA FOR A PRIMEIRA ***/
    if(strcmp(E->expressao, expr) == 0)
    {
        if(E->prox == NULL)
        {
            if(V[ASCII]->prox == NULL)
                V[ASCII] = NULL;
            else
            {
                V[ASCII] = V[ASCII]->prox;
                free(E);
            }
        }
        else
        {
            E = E->prox;
            F->prox = NULL;
            free(F);
        }
    }
    else
    {
        bool encontrouExpressao = false;
        while((E->prox != NULL)&&(encontrouExpressao == false))
        {
            if(strcmp(E->expressao, expr) == 0)
                encontrouExpressao = true;
            else
                E = E->prox;
        }
        if(encontrouExpressao == false)
        {
            if(strcmp(E->expressao, expr) == 0)
                encontrouExpressao = true;
        }
        if(encontrouExpressao == true)
        {
            acompanhanteSignificado S, T;
            S = T = E->listaSignificado;
            while(S != NULL)
            {
                T = S;
                S = S->prox;
                free(T);
            }
            F = E;
            E = E->prox;
            free(F);
        }
    }
}

/*** MAIN ***/
int main()
{
    /*** ABRE OS ARQUIVOS DE ENTRADA E SAIDA ***/
    FILE *arqEntrada, *arqSaida;
    arqEntrada = fopen("entrada.txt", "r");
    arqSaida = fopen("saida.txt", "w");

    /*** VARIAVEIS DO PROGRAMA ***/
    char expr[50], signif[50], aux[101], *pch, lixo;
    int N, qtdOperac, codOperac;
    contador i, j;

    /*** ALOCAR VETOR ***/
    fscanf(arqEntrada, "%d", &N);
    nodeExpressao **V;
    V = (elementoVetor*) malloc (N * sizeof (elementoVetor*));

    /*** APONTAR OS ELEMENTOS DO VETOR PARA NULL ***/
    for(i=0; i<=N-1; i++)
        V[i] = NULL;

    /*** LOOP PRINCIPAL ***/
    fscanf(arqEntrada, "%d", &qtdOperac);
    for(i=1; i<=qtdOperac; i++)
    {
        zerarStrings(expr, signif, aux);
        fscanf(arqEntrada, "%d%c", &codOperac, &lixo);
        switch(codOperac)
        {
        /*** ABRE A ESTRUTURA DE DADOS E INSERE OS DADOS NO VETOR ***/
        case 1:
        {
            FILE *arqLeitura;
            arqLeitura = fopen("DicionITA.txt", "r");
            while(fgets(aux, 101, arqLeitura) != NULL)
            {
                aux[strlen(aux)-1] = '\0';
                pch = strtok(aux, "|");
                strcpy(expr, pch);
                pch = strtok(NULL, "|");
                strcpy(signif, pch);
                inserirSignificado(V, expr, signif, N);
                zerarStrings(expr, signif, aux);
            }
            fclose(arqLeitura);
        }
        break;
        /*** CONSULTA UMA EXPRESSAO PELOS SEUS SIGNIFICADOS ***/
        case 2:
        {
            fgets(expr, 50, arqEntrada);
            expr[strlen(expr)-1] = '\0';
            int ASCII = obterASCII(expr, N);
            acompanhanteExpressao E;
            E = V[ASCII];
            bool encontrouExpressao = false;
            while((E != NULL) && (encontrouExpressao == false))
            {
                if(strcmp(E->expressao, expr) == 0)
                    encontrouExpressao = true;
                else
                    E = E->prox;
            }
            if(encontrouExpressao == true)
            {
                acompanhanteSignificado S;
                S = V[ASCII]->listaSignificado;
                while(S != NULL)
                {
                    fprintf(arqSaida, "%s\n", S->significado);
                    S = S->prox;
                }
                fprintf(arqSaida, "\n");
            }
            else
                fprintf(arqSaida, "nada consta\n\n");
        }
        break;
        /*** ACRESCENTA, CASO AINDA NAO ESTEJA PRESENTE, UM SIGNIFICADO A ALGUMA EXPRESSAO ***/
        case 3:
        {
            fgets(aux, 101, arqEntrada);
            aux[strlen(aux)-1] = '\0';
            pch = strtok(aux, "|");
            strcpy(expr, pch);
            pch = strtok(NULL, "|");
            strcpy(signif, pch);
            inserirSignificado(V, expr, signif, N);
        }
        break;
        /*** ELIMINA UM SIGNIFICADO, CASO ESTEJA PRESENTE ***/
        case 4:
        {
            fgets(aux, 101, arqEntrada);
            aux[strlen(aux)-1] = '\0';
            char *pch;
            pch = strtok(aux, "|");
            strcpy(expr, pch);
            pch = strtok(NULL, "|");
            strcpy(signif, pch);
            eliminarSignificado(V, expr, signif, N);
        }
        break;
        /*** ELIMINA UMA EXPRESSAO, CASO ESTEJA PRESENTE ***/
        case 5:
        {
            fgets(expr, 50, arqEntrada);
            expr[strlen(expr)-1] = '\0';
            eliminarExpressao(V, expr, N);
        }
        break;
        /*** PRODUZ A NOVA ESTRUTURA DE DADOS ***/
        case 6:
        {
            FILE *DicionITA;
            DicionITA = fopen("Dicionario.txt", "w");
            acompanhanteExpressao E = V[0];
            acompanhanteSignificado S = V[0]->listaSignificado;

            for(j=0; j <= N-1; j++)
            {
                if(V[j] != NULL)
                {
                    E = V[j];
                    S = V[j]->listaSignificado;
                    while(E != NULL)
                    {
                        while(S != NULL)
                        {
                            fprintf(DicionITA, "%s|%s\n", E->expressao, S->significado);
                            S = S->prox;
                        }
                        E = E->prox;
                    }
                }
            }
            fprintf(DicionITA, "\n");
            fclose(DicionITA);
        }
        break;
        default:
        {
            fprintf(arqSaida,"ERRO\n\n");
            return 0;
        }
        break;
        }
    }
    fclose(arqEntrada);
    fclose(arqSaida);
    return 0;
}

segunda-feira, 31 de agosto de 2015

Operações com matrizes de inteiros em linguagem C

          Nesta primeira postagem, apresentarei meu código feito em linguagem C, projetado para reconhecer arquivos em .txt contendo matrizes e, em posse delas, realizar as operações: encontrar o maior elemento, determinar a matriz transposta, realizar o produto entre duas matrizes e, por fim, calcular o determinante de uma matriz através da Regra de Laplace.
          Com essa atividade de programação, solicitada em meu curso de Laboratório de Estruturas de Dados e Algoritmos (CES-11), pude fortalecer a minha habilidade para pensar e implementar soluções para problemas através de caminhos recursivos; além disso, foi possível recordar as aplicações de alocação dinâmica de matrizes, quebra de problemas em funções e, por fim, operações com arquivos.

Veja, a seguir, um vídeo demonstrativo da execução de meu programa:



Segue, abaixo, todo o código produzido, "LAB1.c":

#include <stdio.h>
#include <stdlib.h>

typedef int *vetor;
typedef vetor *matriz;

int testador(matriz M, int n, int i, int j, int max){
    //testa os elementos da matriz M e os compara com o maior obtido ate entao (max), retornando o maior inteiro
    //n: ordem da matriz
    //i e j: parametros de cada elemento da matriz (elemento M[i][j])
        //percorre as linhas da esquerda para a direita:
    if(i < n-1){
        if(M[i][j] > max)
            return testador(M, n, i+1, j, M[i][j]);
            return testador(M, n, i+1, j, max);
    }
        //quando chega ao final de uma linha (M[i][j] = M[n-1][j]):
    else if((i == n-1) && (j < n-1)){
        if(M[i][j] > max)
            return testador (M, n, 0, j+1, M[i][j]);
            return testador (M, n, 0, j+1, max);
    }
        //quando chega ao final da matriz (M[i][j] = M[n-1][n-1]):
    else{
        if(M[i][j] > max)
            return M[i][j];
        else
            return max;
    }
}//func. testador()

int retornarMaiorElemento(matriz M, int n){
    int max = M[0][0];
        //os parametros i e j da func. testador comecam zerados
    return testador (M, n, 0, 0, max);
}//FUNC. retornarMaiorElemento()

void DeixarMatrizPronta(matriz A, int n, int i){
    //A FUNC. alocarMatriz() aloca o vetor de ponteiros, que eh apontado por **A;
    //A func. DeixarMatrizPronta() alocara, entao, a matriz em si, apontada pelos ponteiros do vetor:
    if (i <= n-1){
        A[i] = (int *) malloc (n * sizeof (int));
        DeixarMatrizPronta (A, n, i+1);
    }
}//func. DeixarMatrizPronta()

matriz alocarMatriz(int n){
    matriz A;
    A = (vetor *) malloc (n * sizeof (vetor));
    DeixarMatrizPronta (A, n, 0);
    return A;
}//FUNC. alocarMatriz()

void desalocacao(matriz A, int n, int i){
    //desalocara as linhas da matriz, comecando pela ultima
    if (i >= 0){
        free(A[i]);
        desalocacao(A, n, i-1);
    }
}//func. desalocacao()

void desalocarMatriz(matriz A, int n){
    //desalocara o vetor de ponteiros
    desalocacao (A, n, n-1);
    free(A);
}//FUNC. desalocarMatriz()

void transpor (matriz M, matriz A, int n, int i, int j){
    A[j][i] = M[i][j];
    if (i < n-1)
        i++;
    else if((i == n-1) && (j < n-1)){
        i = 0;
        j++;
    }
    else if((i == n-1) && (j==n-1))
        return;
    transpor(M, A, n, i, j);

}//func. transpor()

matriz criarTransposta(matriz M, int n){
    matriz T;
    T = alocarMatriz (n);
    transpor(M, T, n, 0, 0);
    return T;
}//FUNC. criarTransposta()

void ZerarMatriz(matriz A, int i, int j, int n){
    //func. com o objetivo de zerar a matriz A para poder receber o produto das matrizes M1 e M2
    A[i][j] = 0;
    if(i < n-1)
        i++;
    else if((i == n-1) && (j < n-1)){
        i = 0;
        j++;
    }
    else if((i == n-1) && (j == n-1))
        return;
    ZerarMatriz(A, i, j, n);
}//func. ZerarMatriz()

void efetuarProduto(matriz P, matriz M1, matriz M2, int i, int j, int k, int n){
    //O algoritmo segue o procedimento escrito como nos somatorios:
    P[i][k] += M1[i][j] * M2[j][k];
    if(j < n-1)
        j++;
    else if((j == n-1) && (k < n-1)){
        j = 0;
        k++;
    }
    else if((j == n-1) && (k == n-1) && (i < n-1)){
        j = 0;
        k = 0;
        i++;
    }
    else if((j == n-1) && (k == n-1) && (i == n-1)){
        return;
    }
    efetuarProduto (P, M1, M2, i, j, k, n);
}//func. efetuarProduto()

matriz calcularProduto(matriz M1, matriz M2, int n){
    matriz P;
    P = alocarMatriz(n);
    ZerarMatriz(P, 0, 0, n);
    efetuarProduto(P, M1, M2, 0, 0, 0, n);
    return P;
}//FUNC. calcularProduto()

void preencherMatriz(matriz X, matriz M, int j, int p, int q, int n){
    //preenche X com os valores de M tirando-se a linha 0 e a coluna j (da Regra de Laplace)
    if(p > 0){
        if(q < j)
            X[p-1][q] = M [p][q];
        else if(q > j)
            X[p-1][q-1] = M[p][q];
    }
    if(p < n-1)
        preencherMatriz(X, M, j, p+1, q, n);
    else if((p == n-1) && (q < n-1))
        preencherMatriz(X, M, j, 0, q+1, n);
    else if((p == n-1) && (q == n-1))
        return;
}//func. preencherMatriz()

int calcularDeterminante (matriz M, int n){
    //Regra de Laplace
    if(n==1)
        return M[0][0];
    else{
        int j, Det = 0, cofator;
        matriz X;
        X = alocarMatriz(n-1);
        for(j=0; j <= n-1; j++){
            //preencherMatriz eh a func. que torna X o Menor Complementar de A, de indices 0 e j:
            preencherMatriz(X, M, j, 0, 0, n);
            //O cofator eh definido pelo produto do det. do Menor Complementar (Det X) por (-1)^(0+j):
            if  (j%2 == 0)
                cofator = calcularDeterminante(X, n-1);
            else if (j%2 == 1)
                cofator = (-1) * calcularDeterminante(X, n-1);
            Det += M[0][j] * cofator;
        }
        desalocarMatriz(X, n-1);
        return Det;
    }
}//FUNC. calcularDeterminante()

int main(){
    FILE *f1, *f2;
    f1 = fopen("entrada.txt", "r");/*O arquivo "entrada.txt" sera criado pelo programa "Gerar matrizes pseudo-aleatorias.exe"*/
    f2 = fopen("saida.txt", "w");
    int i, j, k, Operacao, Ordem, Quantidade_de_operacoes;
    fscanf(f1, "%d", &Quantidade_de_operacoes);
    for(i=1; i<=Quantidade_de_operacoes; i++){
        fscanf(f1, "%d", &Operacao);
        fscanf(f1, "%d", &Ordem);
        switch(Operacao){
            case 1:{//FUNC. retornarMaiorElemento()
                matriz A;
                A = alocarMatriz(Ordem);
                for(j=0; j< Ordem; j++)
                    for(k=0; k< Ordem; k++)
                        fscanf(f1, " %d", &A[j][k]);
                fprintf(f2, "%3d\n\n",retornarMaiorElemento(A, Ordem));/*ja imprime direto o valor da FUNC.*/
                desalocarMatriz(A, Ordem);
            }break;
            case 2:{//FUNC. criarTransposta()
                matriz A, T;
                A = alocarMatriz(Ordem);
                for(j=0; j< Ordem; j++)
                    for(k=0; k< Ordem; k++)
                        fscanf(f1, "%d", &A[j][k]);
                T = criarTransposta(A, Ordem);/*T recebe os valores de At*/
                for(j=0; j < Ordem; j++){
                    for(k=0; k<Ordem; k++)
                        fprintf(f2, "%3d", T[j][k]);
                    fprintf(f2, "\n");
                }
                fprintf(f2, "\n");
                desalocarMatriz(A, Ordem);
                desalocarMatriz(T, Ordem);
            }break;
            case 3:{//FUNC. calcularProduto()
                matriz A, B, P;
                A = alocarMatriz(Ordem);
                B = alocarMatriz(Ordem);
                for(j=0; j< Ordem; j++)
                    for(k=0; k< Ordem; k++)
                        fscanf(f1, "%d", &A[j][k]);
                for(j=0; j< Ordem; j++)
                    for(k=0; k< Ordem; k++)
                        fscanf(f1, "%d", &B[j][k]);
                P = calcularProduto(A, B, Ordem);/*OBS: a FUNC. ja aloca espaco para P*/
                for(j=0; j < Ordem; j++)
                {
                    for(k=0; k<Ordem; k++)
                         fprintf(f2, "%6d", P[j][k]);
                    fprintf(f2, "\n");
                }
                fprintf(f2, "\n");
                desalocarMatriz(A, Ordem);
                desalocarMatriz(B, Ordem);
                desalocarMatriz(P, Ordem);
            }break;
            case 4:{//FUNC. calcularDeterminante
                matriz A;
                A = alocarMatriz(Ordem);
                for(j = 0; j < Ordem; j++)
                    for(k = 0; k < Ordem; k++)
                        fscanf(f1, "%d", &A[j][k]);
                fprintf(f2, " %d\n\n", calcularDeterminante(A, Ordem));/*ja imprime direto o valor da FUNC.*/
                desalocarMatriz(A, Ordem);
            }break;
        }
    }
    fclose(f1);
    fclose(f2);
    return 0;
}