A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

Sumário Estruturas dinâmicas ligadas Conceito Estrutura de suporte

Apresentações semelhantes


Apresentação em tema: "Sumário Estruturas dinâmicas ligadas Conceito Estrutura de suporte"— Transcrição da apresentação:

1 Sumário Estruturas dinâmicas ligadas Conceito Estrutura de suporte
Operações Vantagens Desvantagens Pilha Exemplos: Inversão de uma linha de caracteres Avaliação de expressões “postfix” Programação 2007/2008 DEEC-IST

2 Estruturas dinâmicas ligadas
Motivação: Nas aulas anteriores foram apresentados exemplos de como um programa pode alocar memória dinâmica ao longo da sua execução. A utilização de memória dinâmica tem como finalidade ultrapassar a dificuldade que um programador tem na especificação da quantidade de memória que é necessária para a manipulação dos dados por um programa. Exemplos utilizados em aulas anteriores: Inversão da ordem de uma sequência de caracteres cujo comprimento não é conhecido. A estratégia seguida consistiu na utilização da função realloc. Programa agenda, em que os apontamentos estão contidos num ficheiro e o utilizador pode introduzir mais 10 apontamentos por cada utilização do programa, mas em que o comprimento de cada comentário é desconhecido antes de ser lido na sua totalidade. Neste exemplo a estratégia seguida foi a de alocar memória para um vector de apontadores, para guardar os endereços das strings (apontamentos) e posteriormente alocar memória para cada um dos apontamentos que podem estar dispersos em memória. Programação 2007/2008 DEEC-IST

3 Estruturas dinâmicas ligadas
É de salientar que o redimensionamento de vectores é uma tarefa pesada quando medida em termos de tempo de execução, isto é devido a que é necessário manter todos os elementos de um vector numa zona de memória contígua. A acção de acrescentar mais um elemento a um vector pode implicar a colocação de todos os outros elementos do vector noutra zona de memória. Como alternativa ao tipo de abordagem anterior utiliza-se o conceito de estrutura dinâmica ligada. struct fio_ligado { int comprimento; struct fio_ligado * seg; }; typedef struct fio_ligado corda; typedef struct fio_ligado { int comprimento; struct fio_ligado * seg; } corda; Programação 2007/2008 DEEC-IST

4 Estruturas dinâmicas ligadas
memória O apontador é utilizado para guardar o endereço de outra estrutura. Permite aceder ao elemento seguinte da lista. Para se aceder ao primeiro elemento da lista é necessário ter uma variável para guardar o endereço do primeiro elemento da lista. Vantagens: Utilizando técnicas apropriadas podem-se adicionar e apagar elementos sem ser necessário recolocar os outros elementos da lista noutras posições em memória RAM como acontece com o redimensionamento dos vectores. Desvantagens: O acesso a um elemento da lista tem de ser feita de forma sequencial a partir do início (cabeça ou base) da lista base dados endereço NULL Programação 2007/2008 DEEC-IST

5 Estruturas dinâmicas ligadas
As operações típicas, realizadas em estruturas ligadas são: Criar um novo elemento. Alocar memória para um novo elemento. Preencher os campos com dados. Procurar o local de inserção do novo elemento. É necessário destinguir a inserção lógica do novo elemento em relação aos outros elementos da lista, da inserção física em memória, o local físico é determinado pelo Sistema Operativo que gere a memória. Inserção do novo elemento. Consiste em aceder a um campo apontador de um elemento da lista e actualizar o apontador com o endereço do novo elemento. Apagar um elemento já existente É necessário procurá-lo, retirá-lo da lista, actualizar os apontadores de forma correcta e libertar a memória do elemento que se pretende apagar. Programação 2007/2008 DEEC-IST

6 Estruturas dinâmicas ligadas
Classificação das estruturas dinâmicas: Dependendo do modo como se inserem e retiram os elementos temos: Pilha ou Stack - Acrescentam-se elementos no topo e retiram-se elementos do topo. Fila - Acrescentam-se elementos no fim da fila e retiram-se os elementos no início da fila Lista - A inserção e a eliminação de elementos podem ser feita em qualquer ponto do encadeamento das estruturas ligadas. Dependendo do número de apontadores para a(s) ligação(ões) lógica(s): Estruturas simplesmente ligadas. (Pilha, Fila, Lista e Anel) - Cada elemento tem um apontador para o elemento seguinte. Estruturas duplamente ligadas (Listas e Anéis) - Cada elemento tem dois apontadores, um para o elemento seguinte e outro para o elemento anterior. Organizações mais sofisticadas: Conceito de árvores. Programação 2007/2008 DEEC-IST

7 Estruturas ligadas: Pilha
Considere-se o exemplo da inversão da sequência de caracteres, para o qual já foi apresentado um programa com o redimensionamento do vector. As acções que devem ser realizadas : Ler um carácter Alocar espaço para o carácter. Inserir o elemento no topo da pilha. Quanto se chegar ao fim da sequência de caracteres é necessário desempilhar os elementos, apresentando-os no ecrã. Esta acção faz com que os caracteres sejam apresentados por ordem inversa. Programação 2007/2008 DEEC-IST

8 Estruturas ligadas: Pilha
Em relação ao desenvolvimento do programa é necessário: Definir a estrutura de suporte ao conceito de pilha. typedef char TipoDADO; typedef struct Pilha_Stru { TipoDADO x; struct Pilha_Stru *prox; } TipoPilha; Definir as funções que podem manipular a pilha. Inicializar a pilha. Inserir um elemento no topo da pilha. Retirar um elemento do topo da pilha. É necessário ter uma função que permita determinar se a pilha está vazia. Programação 2007/2008 DEEC-IST

9 Estruturas ligadas: Pilha
Defina-se, primeiro o ficheiro pilha.h que contém a estrutura e os protótipos das funções. #ifndef PILHA_H /* Ficheiro: pilha.h */ #define PILHA_H #include <stdlib.h> #include <stdio.h> typedef char TipoDADO; /* Forma que permite adaptar o codigo */ typedef struct Pilha_Stru { /* a outros tipos de dados */ TipoDADO x; struct Pilha_Stru *prox; } TipoPilha; /* NOTA: No Prototipos das funcoes so e necessario o tipo */ void IniciaPilha(TipoPilha **topo); /* Passar por referencia */ int PilhaVazia(TipoPilha *topo); /* Passar por valor */ int InsereNaPilha(TipoPilha **topo, TipoDADO z); TipoDADO RetiraDaPilha(TipoPilha ** topo); TipoDADO LeDadoDoFicheiro(FILE *fp); void EscreveDadoNoFicheiro(FILE *fp, TipoDADO z); #endif Programação 2007/2008 DEEC-IST

10 Estruturas ligadas: Pilha
Ficheiro: pilha.c, tem as funções de manipulação da pilha /* Ficheiro pilha.c */ /* Contem as funcoes de manipulacao de uma pilha */ #include "pilha.h" /* | Nome: IniciaPilha | Accao: Inicializa o ponteiro da pilha */ void IniciaPilha(TipoPilha **topo) { *topo = (TipoPilha *) NULL; } Programação 2007/2008 DEEC-IST

11 Estruturas ligadas: Pilha
Ficheiro: pilha.c, (cont.) /* | Nome: PilhaVazia | Accao: Permite verificar se a pilha esta vazia | Devolve: 1 - Se a pilha esta vazia | Se a pilha nao esta vazia | NOTA: Esta funcao so pode ser utilizada apos a pilha ter | sido inicializada com a funcao IniciaPilha */ int PilhaVazia(TipoPilha *topo) { if (topo == (TipoPilha *) NULL) return 1; return 0; } Programação 2007/2008 DEEC-IST

12 Estruturas ligadas: Pilha
Ficheiro: pilha.c, (cont.) memória /* | Nome: InsereNaPilha | Accao: Acrescenta mais um elemento a pilha | recebe o dado a armazenar e aloca memoria | para o dado | Devolve: 0 - se erro | se sucesso */ int InsereNaPilha(TipoPilha **topo, TipoDADO z) { TipoPilha *ap; /* Aloca memoria */ ap = (TipoPilha *)calloc(1, sizeof(TipoPilha)); if (ap == (TipoPilha *)NULL) { return (0); } ap->x = z; /* preenche o campo de dados */ ap->prox = *topo; /* Faz a ligacao logica */ *topo = ap; /* Actualiza o ponteiro da pilha */ return 1; ap topo dados endereço NULL dados endereço Programação 2007/2008 DEEC-IST

13 Estruturas ligadas: Pilha
Ficheiro: pilha.c, (cont.) memória topo dados endereço NULL /* | Nome: RetiraDaPilha | Accao: Retira o elemento que está no topo da pilha | e liberta a memoria | Devolve: O dado que estava armazenado no topo da pilha | Nota: Esta funcao so deve ser chamada se a pilha nao estiver | vazia. */ TipoDADO RetiraDaPilha(TipoPilha **topo) { TipoPilha *ap; TipoDADO z; ap = *topo; /* Obtem o endereco da memoria a libertar */ z = ap->x; *topo = ap->prox; free(ap); return z; } ap Programação 2007/2008 DEEC-IST

14 Estruturas ligadas: Pilha
Ficheiro: pilha.c, (cont.) /* | Nome: LeDadoDoFicheiro | Accao: Le o dado do ficheiro, apontado por fp | Devolve: Devolve o dado que foi lido */ TipoDADO LeDadoDoFicheiro(FILE *fp) { TipoDADO z; z = getc(fp); return z; } | Nome: EscreveDadoNoFicheiro | Accao: Escreve o dado z no ficheiro apontado por dp | Devolve: void void EscreveDadoNoFicheiro(FILE *fp, TipoDADO z) { putc(z, fp); Programação 2007/2008 DEEC-IST

15 Estruturas ligadas: Pilha
Ficheiro: main.c. #include <stdio.h> #include "pilha.h" int main( void ) { TipoDADO c; TipoPilha *topo_pilha; IniciaPilha(&topo_pilha); printf("Utilizacao de uma pilha para inverter uma sequencia de caracteres \n"); printf("\nEscreva uma frase \n"); do { c = LeDadoDoFicheiro(stdin); InsereNaPilha(&topo_pilha, c); }while (c != '\n'); while (!PilhaVazia(topo_pilha)) { c = RetiraDaPilha(&topo_pilha); EscreveDadoNoFicheiro(stdout, c); } printf("\n Fim do programa \n."); return 0; Programação 2007/2008 DEEC-IST

16 Pilha: Avaliação de expressões “postfix”
Exemplo importante de aplicação da pilha: As pilhas são muito utilizadas pelos compiladores para a avaliação de expressões como 3 * 5, ou 12 % 8. As expressões acima descritas são facilmente avaliadas pelos humanos. Essas expressões têm o nome de “infix” devido a que os operadores estão entre os operandos. Os computadores “gostam” de avaliar expressões em que os operadores aparecem no lado direito dos operandos, 3 5 * , ou 12 8 %. Estas expressões têm o nome de “postfix” ou RPN (“Reverse Polish Notation”) As pilhas são utilizadas para: Converter uma expressão da forma “infix” para “postfix” Avaliar uma expressão que já se encontre na forma “postfix” Programação 2007/2008 DEEC-IST

17 Pilha: Avaliação de expressões “postfix”
Exemplo: Considere a expressão na notação “infix” seguinte: (3 + 7) * / 3 Após o processo de conversão (que envolve a utilização de pilhas), a expressão assume a forma “postfix” seguinte * 8 3 / - No processo de avaliação da expressão “postfix”, é realizada a leitura dos elementos da expressão da esquerda para a direita utilizando as regras seguintes: Se o carácter corrente é um algarismo (ou número) então deve ser colocado no topo da pilha (push em linguagem anglo-saxónica). Se o carácter corrente é um operador (binário) então , devem ser lidos os dois primeiros elementos da pilha (duas operações de pop) deve ser realizada a operação e o resultado deve ser guardado no topo da pilha Se se chegou ao fim da expressão então deve ser realizada a operação de push da pilha, esse valor corresponde ao resultado da expressão. Programação 2007/2008 DEEC-IST

18 Pilha: Avaliação de expressões “postfix”
Exemplo: Evolução da pilha (“stack”) vazio 3 7 + 10 2 * 20 8 / - 18 Elemento Stack push pop Pop resultado t Programação 2007/2008 DEEC-IST

19 Pilha: Avaliação de expressões “postfix”
Ficheiro: main.c. /* Pilha avaliacao de expressoes postfix*/ #include <stdio.h> #include <string.h> #include "pilha.h" #define MAXD 150 int main( void ) { char elemento[MAXD]; TipoPilha *topo_pilha; /* O TipoDADO deve ser modificado em pilha.h */ /* de acordo com a dados que sao manipulados */ TipoDADO operando, operando1, operando2, resparcial; char operador; int erro = 0; IniciaPilha(&topo_pilha); Programação 2007/2008 DEEC-IST

20 Pilha: Avaliação de expressões “postfix”
Ficheiro: main.c, (cont.) printf("Introduza a expressao em notacao postfix \n"); printf(" um elemento por linha\n"); printf("Carregue em Enter para terminar.\n"); fgets(elemento, MAXD,stdin); while (elemento[0] != '\n') { if (sscanf(elemento, "%d", &operando) == 1) { InsereNaPilha(&topo_pilha, operando); } else { switch(elemento[0]) { case '+': case '-': case '*': case '/': operador = elemento[0] ; if (ElementosNaPilha(topo_pilha) < 2) { fprintf(stderr, "Stack com poucos operandos\n"); erro = 2; Programação 2007/2008 DEEC-IST

21 Pilha: Avaliação de expressões “postfix”
Ficheiro: main.c, (cont.) break; default: fprintf(stderr, "Erro de sintaxe\n"); operador = '!'; erro = 1; } if (!erro) { operando2 = RetiraDaPilha(&topo_pilha); operando1 = RetiraDaPilha(&topo_pilha); switch (operador) { case '+': resparcial = operando1 + operando2; case '-': resparcial = operando1 - operando2; case '*': resparcial = operando1 * operando2; Programação 2007/2008 DEEC-IST

22 Pilha: Avaliação de expressões “postfix”
Ficheiro: main.c, (cont.) case '/': resparcial = operando1 / operando2; break; } printf("Resultado Parcial = %d\n", resparcial); InsereNaPilha(&topo_pilha, resparcial); fgets(elemento, MAXD,stdin); if (erro) ApagaPilha(&topo_pilha); printf("\n Fim do programa \n."); return 0; Programação 2007/2008 DEEC-IST

23 Pilha: Avaliação de expressões “postfix”
Atenção, em relação ao código é necessário: Modificar o ficheiro pilha.h alterando o TipoDADO de char para int. É necessário desenvolver duas funções com os protótipos void ApagaPilha(TipoPilha **topo); Permite libertar a memória da pilha se ocorreu algum erro de sintaxe na expressão postfix int ElementosNaPilha(TipoPilha *topo); Permite contar e devolver o número de elementos que estão armazenados na pilha. No processo de desenvolvimento do programa deve-se: Em primeiro lugar deve ser compilado o ficheiro pilha.c gcc -g -Wall -ansi -pedantic -c pilha.c Em segundo lugar deve ser compilado o ficheiro main.c Finalmente após a depuração do código de ambos os ficheiros, deve ser criado o ficheiro executável utilizando os ficheiros pilha.o e main.o gcc pilha.o main.o -o postfix Programação 2007/2008 DEEC-IST

24 Programação 2007/2008 DEEC-IST


Carregar ppt "Sumário Estruturas dinâmicas ligadas Conceito Estrutura de suporte"

Apresentações semelhantes


Anúncios Google