Upload
buimien
View
215
Download
0
Embed Size (px)
Citation preview
AED (IST/DEEC) 60
Tipos abstractos [1]• Balanço dos tipos de dados no C (básicos, estruturados, dinâmicos e
composições)– Vantagens:
• muito próximos dos tipos das linguagem máquina (Bit,Word)• manipulação eficiente
– Inconvenientes:• Porque os algoritmos são expressos por instruções simples (=, if, do,...)
– resultam muitas vezes em falhas de implementação– tipo de linguagem muito afastada do raciocínio dos analistas
• Mesmo que o algoritmo seja igual, a alteração do tipo de dados obriga a modificar o código (exemplo: se nas listas da aula anterior for alterado o tipo do campo item, de int para char, a função newElement temde ser modificada)
• Solução: usar abstracções que permitem descrever o problema, deixando os detalhes de implementação para depois!
AED (IST/DEEC) 61
Tipos abstractos [2]
• Um tipo abstracto é• um tipo genérico de dados, dos quais não se conhece os valores• uma interface que define os acessos e as operações sobre os dados• O conjunto das propriedades algébricas da interface, que delimitam as
possíveis implementações.
• A implementação transcreve o tipo abstracto, codificando os programas que efectuam as operações definidas na interface (satisfazendo as propriedades).
• O uso permite compilar a implementação, instanciando o tipo genérico para um dos tipos de C
Um programa que usa um tipo abstracto é um cliente. O cliente não tem acesso à implementação.
AED (IST/DEEC) 62
Tipos abstractos [3]Exemplo dos passos no desenvolvimento de um programa1. Análise:
1. [Especificação] entram números codificados, sendo depois devolvidos o valor decifrados.
2. [Tipo abstracto de dados] operações: entrada e remoção de elementos de uma lista genérica, cifra e descodificação.
2. Implementação:– Opção A: Tipo de dados por tabela, com índice para o primeiro índice livre– Opção B: Tipo de dados por lista simplesmente ligada– Cifra/descodificação por chave pública
3. Uso– (Opção B) O tipo de dados é uma lista simplesmente ligada de inteiros.
4. Compilação– 0’s e 1’s, do processador
AED (IST/DEEC) 63
ContentoresMuitos tipos abstractos representam contentores. Os contentores
servem para armazenar um conjunto de items: listas, pilhas, anéis, tabelas de dispersão (‘‘hash-tables’’), ...
Para definir um tipo abstracto para um contentor deve-se:1. Definir a interface do tipo abstracto em função do tipo Item.
A interface inclui o ficheiro “Item.h” (que contém a definição do tipo),
2. Definir a implementação,3. Cada cliente cria um ficheiro “Item.h”, consoante as suas
necessidades.4. Compilar
AED (IST/DEEC) 64
Exemplo: Pilha [1]Operações abstractas
- inicialização.
- limpeza da pilha.
- colocação de um elemento na pilha.
- remoção de um elemento (o último colocado).
- indica se pilha está vazia.
Usando a mesma interface, podem ser definidas várias implementações ...
Pilha.htypedef enum {FALSE,TRUE} BOOL;void Init(unsigned pNumb);/*parâmetro é comprimento máximo*/int Empty();void Push(Item pI);Item Pop();BOOL IsEmpty();
AED (IST/DEEC) 65
Exemplo: Pilha [2]Algumas propriedades algébricas da pilha
TODO n: IsEmpty(Init(n))=TRUE ; pilha é sempre inicializada vazia
TODO i: IsEmpty(Push(i))=FALSE ; depois de inserido um elemento,
; nunca a pilha fica vazia*/
TODO i: Pop(Push(i))=i ; elemento removido da pilha é sempre o último
; a ser inserido
Para os mais curiosos, apenas! Na definição algébrica da pilha, ela própria é um tipo genérico Stack. A interface e as propriedades são um pouco diferentes.
A implementação é um pouco mais complexa, pelo que não é considerada aqui.
• Stack Init(int pNumb)• Stack Push(Stack pStk, int pNumb)• Stack Pop(Stack pStk)• int Top(Stack)
•TODO i,p: Top(Push(p,i))=i•TODO i,p: Pop(Push(p,i))=p ; push seguido de
; pop mantém pilha
AED (IST/DEEC) 66
Exemplo: Pilha [3]
Pilha.c#include “Item.h” /* aqui o cliente define
os dados */#include “Pilha.h”static Item *gP;static int gN; /*primeiro índice livre*/
void Init(unsigned pSize) {gP = (Item *)malloc(pSize*sizeof(Item));gN = 0; }
void Push(Item pI) {gP[gN++] = pI; }
BOOL IsEmpty() {return gN==0? TRUE : FALSE; }
...
Implementação do tipo pilha usando uma tabela
Vantagens:
• Simplicidade.
Desvantagens:
• Tamanho máximo limitado à partida.
i1i2
gN=2
Push(i3)
i1
i3i2
gN=3
AED (IST/DEEC) 67
Exemplo: Pilha [4]
Pilha.c#include “Item.h”#include “Pilha.h”typedef struct pilha {Item item;struct pilha *next;
} pilha;static pilha *gP;
void Init(unsigned pNumb) {gP = NULL; }
void Push(Item pI) {pilha *Top = (pilha *)malloc(sizeof(pilha));Top->item = pI; Top->next = gP;gP = Top;}
BOOL IsEmpty() {return gP==NULL? TRUE : FALSE; } ...
Implementação do tipo pilha usando uma listaVantagens:
• Cresce à medida que novos elementos são postos na pilha.• Decresce quando se removem elementos.
Desvantagens:
• Ocupa mais memória (para os apontadores).• Mais lento (gestão da memória).
Push(i3)
i2 i1
i2 i1i3
gP
gP
AED (IST/DEEC) 68
Exemplo: Pilha [5]Utilização do tipo abstracto pilha por clientes
Vários clientes podem dar definições diferentes para o tipo Item de modo a usar, por exemplo:
• Uma pilha de alunos
Item.htypedef struct {
unsigned numero;enum {LEEC,LEIC,LERCI} curso;char *nome;
} Item;
• Uma pilha de inteiros
Item.htypedef int Item;
AED (IST/DEEC) 69
Exemplo: Pilha [6]Intstack.c (cliente 1):#include “Item.h”#include “Pilha.h”main() {
Item Val=100;Init(19);Push(Val); }
Alunos.c (cliente 2):#include “Item.h”#include “Pilha.h”Item InicializarAluno(char *pName,int pNumb){
...}main(){
Item Aluno;init(0);Aluno=InicializarAluno(“José”,44562);Push(Aluno);}
Atenção! O ficheiro “Item.h” é incluído antes do ficheiro “Pilha.h” de modo a definir o tipo Item referido neste ficheiro.
AED (IST/DEEC) 70
Exemplo: Pilha [7]• Comparando os dois clientes, as diferenças resumem-se a:
• Ficheiro de definições Item.h• Programa principal
Os tipos de dados abstractos permitem reutilizar funções (a nível de programas fonte).
Atenção: não é o mesmo que a reutilização de bibliotecas (‘‘library’’) objecto, nestas os tipos de dados não podem ser definidos pelos clientes.
AED (IST/DEEC) 71
Exemplo: Pilha [8]Exemplo de aplicação do tipo abstracto de pilha: pretende-se validar expressões
aritméticas em notação pós-fixada (considerados apenas operadores soma e multiplicação).
Explicação: Os operadores aritméticos binários, são colocados segundo a notação:– In-fixada: entre os operandos (usada pelos humanos, mas obriga a definir prioridades-
multiplicação maior que soma, e usar parêntesis para tornear as prioridades.Ex: 2 + 3 *4 [resultado 14], (2 +3)*4 [resultado 20]
– Pós-fixada: depois dos operandos (usada pelos computadores, cálculo efectuado logo que se encontra o operador o que evita definição de prioridades e parêntesis)
Ex: 2 3 4 * + [resultado 14], 2 3 + 4 * [resultado 20]Método de cálculo de 2 3 4 * +(a) inserir 2 na pilha(b) inserir 3 na pilha(c) inserir 4 na pilha(d) detectada a multiplicação, retirar os dois operandos da pilha «4»,«3» e inserir o resultado «12»(e) detectada a soma, retirar os dois operandos da pilha «2»,«12» e inserir o resultado «14»(f) Só há um operando na pilha: a expressão 2 3 4 * + é válida!
AED (IST/DEEC) 72
Exemplo: Pilha [9]#include <stdio.h>#include <string.h>#include “Item.h” /* O cliente usa pilha de inteiros */ #include “Pilha.h”
main(int pArgc, char **pArgv) {int Idx, Res, Dim = pArgc-1;
Init(Dim);for (Idx = 1; Idx <= Dim; Idx ++) {
if (!strcmp(pArgv[Idx],”+”)) Push(Pop() + Pop());else if (!strcmp(pArgv[Idx],”*”)) Push(Pop() * Pop());else Push(atoi(pArgv[Idx]));
}Res = Pop();if (IsEmpty()) printf(“Valido com resultado=%d\n”, Res);else printf(“Expressao invalida!\n”); }
AED (IST/DEEC) 73
Implementações
• O cliente não depende da implementação.• O cliente não tem de saber como a pilha foi implementada.• Escolha-se a implementação na altura da edição de ligações
(‘‘link’’) do programa.• A escolha deve ser feita em função da aplicação. • Em muitos casos as diferenças estão na gestão da memória:
– Uma gestão mais rígida (baseada em tabelas) tem o defeito que é preciso conhecer o tamanho máximo à partida. O espaço ocupado em memória corresponde sempre ao tamanho máximo.
– Uma gestão mais flexível (baseada em listas, por exemplo) tem o defeito de ser menos eficiente (tempo de computação) mas permite o tratamento de problemas maiores devido a uma gestão mais apertada da memória.
AED (IST/DEEC) 74
• Tipos abstractos
• Contentores
• Pilhas– Implementação em tabela
– Implementação em lista
• Critérios para escolha da implementação
Síntese da Aula 4 de Tipologia e Operações
AED (IST/DEEC) 75
Tipos de 1ª classe
Os tipos abstractos que já vimos têm um defeito:• Só pode existir uma única instância do tipo por programa.
(definida como variável estática na parte da implementação)
O ideal seria poder usar os tipos abstractos da uma maneirasemelhante aos tipos básicos (int, float, char etc..). Def: Um tipo de 1ª classe é um tipo para o qual pode haver muitas
instâncias que podem ser atribuídas a variáveis do programa. Os tipos de 1ª classe podem ser usados nas declarações como os tipos básicos.
AED (IST/DEEC) 76
Exemplo: tipo complexo [1]
O tipo de 1ª classe complexo é definido pela interface:
Complex.h:
typedef struct{float Re; float Im;} Complex;
Complex ComplexInit(float pRe, float pIm);float Re(Complex pC);float Im(Complex pC);Complex mult(Complex pC1, Complex pC2);
O ficheiro Complex.c contém a implementação...
AED (IST/DEEC) 77
Exemplo: tipo complexo [2]#include “Complex.h”Complex ComplexInit(float pRe, float pIm) {
Complex Res;Res.Re = pRe; Res.Im = pIm; return Res;}
float Re (Complex pC) { return pC.Re; }float Im (Complex pC) { return pC.Im; }
Complex mult(Complex pC1, Complex pC2) {return ComplexInit(Re(pC1)* Re(pC2)– Im(pC1)* Im(pC2),
Re(pC1)* Im(pC2)+ Im(pC1)* Re(pC2));}
AED (IST/DEEC) 78
Exemplo: tipo complexo [3]O programa cliente calcula as raízes complexas da equação zN = 1. As raízes são dadas pela fórmula : cos(2πk/N) + i sin(2πk/N).#include <math.h>#include “Complex.h”main (int pArgc, char **pArgv) {
int Idx1, Idx2, pN = atoi(pArgv[1]);Complex t, x;printf(“raízes para N=%d\n”, pN);for (Idx1=0; Idx1 < pN; Idx1++) {
float r = 2.0 * M_PI * Idx1 / pN;t = ComplexInit(cos(r), sin(r));printf(“Z%d: %6.3f %6.3f\t“, Idx1, Re(t), Im(t));for (x=t, Idx2=0; Idx2 < pN-1; Idx2++) x = mult(t,x);printf(“Z%d^%d = %6.3f %6.3f\n”, Idx1, pN, Re(x),Im(x));}
}
Compilação requer biblioteca de funções matemáticas: usargcc –o roots roots.c Complex.c -lm
AED (IST/DEEC) 79
Exemplo: tipo complexo [4]
Neste exemplo, podemos observar que:• O tipo Complex é usado como se fosse um tipo predefinido,• Certas linguagens de programação (por exemplo o Java)
permitem a definição de operadores (+,-,*,/, etc...) para tipos novos. (No Java podíamos ter definido um novo * em vez de mult).
• Apesar de o cliente ser independente da implementação, tem acesso à forma como foi implementado o tipo (a definição do tipo está visível na interface)
→ perigo potencial ...
AED (IST/DEEC) 80
Exemplo: tipo complexo [5]
Se o cliente tiver acesso à definição do tipo:• Tem a possibilidade de aceder directamente aos campos da
estrutura:– Pode usar t.Re em vez de Re(t).
• Os programas clientes tornam-se dependentes da implementação.– se a implementação for alterada (usando, por exemplo a notação polar ou
angular para os complexos), é necessário alterar todos os ficheiros clientes.
A solução consiste em esconder a definição do tipo.
AED (IST/DEEC) 81
Complexos, 2ª versão [1]
• A interface passa a ser:
typedef struct complex *Complex;
Complex ComplexInit(float pRe, float pIm);float Re(Complex pC);float Im(Complex pC);Complex mult(Complex pC1, Complex pC2);
A diferença reside na definição do tipo Complex como apontador para uma estrutura. A estrutura não está definida neste ficheiro.
AED (IST/DEEC) 82
Complexos, 2ª versão [2]
A implementação é alterada:• A estrutura complex é definida:
struct complex { float Re; float Im; };• A memória deve ser alocada na função init:
Complex ComplexInit (float pRe, float pIm) {Complex Res =(Complex)malloc(sizeof(struct complex));Res->Re = pRe; Res->Im = pIm; return Res;
}• O tipo Complex é um apontador portanto os acessos aos campos é
feito com -> em vez do ponto.
AED (IST/DEEC) 83
Complexos, 2ª versão [3]
• O cliente não precisa de ser alterado.Resumindo:• O tipo é escondido usando um apontador (Complexo é um
ponteiro)• O tipo é definido na implementação.
Não era possível implementar esta solução sem recorrer a um apontador. O apontador permite criar um tipo sem especificar os pormenores. O compilador pode compilar um programa (interface + cliente) porque o tipo Complexo tem um tamanho definido : 32bits.
AED (IST/DEEC) 84
Exemplo: Filas [1]Def: Na fila, ou FIFO-First In/First Out, o primeiro elemento a sair é o primeiro elemento entrado. Em relação às pilhas, as alterações relevantes são:
• A inserção de um elemento é feita no fim da lista.
• Passa a haver dois ponteiros, um para o início da lista (para retirar elementos) outro para o fim da lista (para inserir elementos).
Fila.h:
typedef struct fila *F;void FilaDump(F); F FilaInit(int);int FilaEmpty(F);void FilaPut(F, Item);Item FilaGet(F);
AED (IST/DEEC) 85
Exemplo: Filas [2]Implementação Fila.c (usando uma lista):#include <stdlib.h>#include <stdio.h>#include “Item.h”#include “Fila.h”
Item.h define o tipo de dado contido na fila. A fila é implementada usando uma lista:
typedef struct _element { Item item; struct _element * next;
} element;
A estrutura fila usada na interface é definida:struct fila { element * primeiro; element * ultimo; };
AED (IST/DEEC) 86
Exemplo: Filas [3]
A função new serve para alocar e inicializar um novo elemento na lista:
element *FilaNew(Item vItem, element *pNext) {element *x = (element *) malloc(sizeof (element));x->item = vItem; x->next = pNext; return x;
}
Função de inicialização de uma fila. Dado que está implementada com uma lista, não estamos limitados no número de elementos.
F FilaInit(int maxN) {F pFila = (F) malloc(sizeof(struct fila));pFila->primeiro = NULL; return pFila;
}
AED (IST/DEEC) 87
Exemplo: Filas (4)Função que coloca um item na fila:void FilaPut(F pFila, Item vI) {
if (pFila->primeiro == NULL) { /* a fila está vazia */pFila->ultimo = FilaNew(vI, pFila->primeiro);pFila->primeiro = pFila->ultimo; return; }
/* o item é colocado no fim da lista */pFila->ultimo->next = FilaNew(vI, NULL);pFila->ultimo = pFila->ultimo->next;}
Fila após inicialização
0primeiro ultimo
Fila com 1 elemento
primeiro ultimo0
item
next
Fila com 2 elementos
primeiro ultimo0
AED (IST/DEEC) 88
Exemplo: Filas [5]
A função get remove o primeiro elemento da fila:
Item FilaGet(F pFila) {Item item = pFila->primeiro->item;element *elem = pFila->primeiro->next;free(pFila->primeiro); pFila->primeiro = elem;return item;
} A medida que os elementos são removidos da lista, a memória é
libertada.
AED (IST/DEEC) 89
• Tipos abstractos de 1ª classe
• Exemplo para Complexos
• Exemplo para Filas
Síntese da Aula 5 de Tipologia e Operações
AED (IST/DEEC) 90
Contentores
• O exemplo do tipo fila demonstra a possibilidade de criar tipos de 1ª classe para novos contentores.
• Os contentores criados até agora dependem de um tipo Itemque representa o tipo de dados que se quer armazenar no contentor
• Um defeito desta abordagem é que num programa o tipo Itemsó pode ser definido uma única vez.
• Em consequência não podemos ter no mesmo programa, uma fila de inteiros e uma fila de elementos de tipo «aluno».
AED (IST/DEEC) 91
Items
• A solução consiste, como no caso dos tipos de 1ª classe, em usar um ponteiro de modo a não especificar o tipo dos items.
• O tipo Item é definido por:typedef void * Item;O tipo void * corresponde a um apontador para um objecto cujo tipo é
desconhecido.
• Vamos agora, criar filas de vários tipos.
AED (IST/DEEC) 92
Filas de complexos
Para criar filas de complexos, o cliente pode usar o tipo Complexjá definido:
F pFilaC = FilaInit(10); /* declaração da fila *//* declaração de um complexo: */Complex z = ComplexInit(1,1); Para colocar o complexo na fila:FilaPut(pFilaC, (Item) z);A variável z é um apontador, o cast permite evitar obter warnings do
compilador. Para remover um elemento da fila:z = (Complex) FilaGet(pFilaC);Portanto, é preciso: • converter os Item para Complex quando ler da fila • converter os Complex para Item quando escrever para a fila
AED (IST/DEEC) 93
Filas de matrizes [1]Para definir filas de matrizes, temos de definir primeiro um tipo
abstracto Matrix:Interface: Matrix.htypedef struct _matrix * Matrix;Matrix MatrixNew(int, int);Matrix MatrixMult(Matrix, Matrix);float MatrixElement(Matrix,int,int);etc...Implementation: Matrix.ctypedef struct _matrix {
float ** valores;int cols; int rows;
} matrix;
AED (IST/DEEC) 94
Filas de matrizes [2]Matrix NewMatrix(int pRows, int pCols) {
int Idx;Matrix Mat = (Matrix) malloc(sizeof(matrix));Mat->valores = (float **) malloc(pRows * sizeof (float *));for (Idx =0; Idx < pRows; Idx++)Mat->valores[Idx] = (float *) malloc(pCols * sizeof(float));
Mat->rows=pRows; Mat->cols=pCols; return Mat;}
Matrix MatrixMult(Matrix pA, Matrix pB) {Matrix Res = NewMatrix(Rows(pA), Cols(pB));int IdxI,IdxJ,IdxK;...return Res;
}
AED (IST/DEEC) 95
Filas de matrizes [3]float MatrixElement(Matrix pA, int pI, int pJ) {
return pA->valores[pI][pJ];}Uma vez o tipo Matrix definido, o cliente pode criar uma fila de matrizes:F pFilaM = FilaInit(10);Matrix m = NewMatrix(10,10);Colocar m na fila:FilaPut(pFilaM,(Item) m);Para remover uma matriz da fila:Matrix a = (Matrix) FilaGet(pFilaM);• As filas de matrizes e as filas de complexos podem coexistir no mesmo
programa. • O Item aponta para um complexo ou para uma matriz.
AED (IST/DEEC) 96
Listas duplamente ligadas [1]As filas duplamente ligadas são usadas quando é preciso percorrer a lista do
início até ao fim e do fim até ao início.A interface dlist.h:
typedef struct dlist * Dl;Dl NewDList();Dl AddAtEnd(Item, Dl);Dl AddAtHead(Item, Dl);Dl Concat(Dl,Dl);Item First(Dl);Item Last(Dl);Item Next(Dl);Item Previous(Dl);Item Nth(Dl, int n);Item Find(Item, Dl, int test(Item,Item));void Apply( void f(Item), Dl);
AED (IST/DEEC) 97
A lista vazia é representada por um ponteiro nulo:Dl NewDlist() {
return (Dl) NULL; }
Implementação: dlist.c.Definição do tipo dlist:
typedef struct _dlist { Item item; struct _dlist * next; struct _dlist * previous;
} dlist;
A inserção de um item no início da lista éfeito pela função seguinte:
Dl AddAtHead(Item item, Dl list) {
Dl n = malloc(sizeof(dlist)); n->previous = NULL;n->item = item;if (list != NULL) {
n->next = list; list->previous = n;
}return n;
}
Listas duplamente ligadas [2]
AED (IST/DEEC) 98
Listas duplamente ligadas [3]A função AddAtEnd acrescenta um elemento ao fim da lista:Dl last(Dl l) {
Dl ultimo = l;while (ultimo->next != NULL)
ultimo = ultimo->next;return ultimo;
}Dl AddAtEnd(Item i, Dl list) {
Dl ultimo = last(list);ultimo->next = malloc(sizeof(dlist));ultimo->next->item = i;ultimo->next->previous = ultimo;ultimo->next->next = NULL;return list;
}
AED (IST/DEEC) 99
Listas duplamente ligadas [4]Para concatenar duas listas:Dl Concat(Dl l1,Dl l2) {
Dl l3 = last(l1);l3->next = l2; l2->previous = l3;return l1;
}Vários acessores:Item First(Dl l) { return l->item; }Item Last(Dl l) { return last(l)->item; }Item Next(Dl l) { return l->next->item; } Item Previous(Dl l) { return l->previous->item; }Nth devolve o nésimo item da lista:Item Nth(Dl l, int n) {
int i;for (i=0; i<n; i++) l = l-> next; return l->item;
}
AED (IST/DEEC) 100
Listas duplamente ligadas [5]
A função Find ilustra a utilidade de passar funções em argumento:Item Find(Item i, Dl l, int test(Item,Item)) {
while (!(test(i,l->item)) &&l->next != NULL) l = l->next;
if (l->next == NULL)if (test(i,l->item))
return l->item;else return (Item)NULL;
return l->item;}O terceiro argumento da função é uma função de comparação entre
2 items. O utilizador escreve a função de teste em conformidade com o objectivo da procura.
AED (IST/DEEC) 101
Listas duplamente ligadas [6]
• A função Apply recebe em argumento uma função que admite como argumento um item.
• Aplica a função f a todos os elementos da lista.• A vantagem para o cliente é que não tem de escrever muitos dos
ciclos que iteram sobre a lista.
void Apply( void f(Item), Dl l) {while (l != NULL) {
(f)(l->item);l = l-> next;
}}
AED (IST/DEEC) 102
Listas duplamente ligadas [7]O cliente pode usar, por exemplo listas de alunos.Primeiro deve-se definir um tipo abstracto para o aluno:typedef struct _aluno *Aluno; /* na interface */Implementado por:typedef struct _aluno { char *nome; int num; } aluno;
O tipo abstracto aluno define a função de igualdade:int AlunoIgual(Item i1, Item i2) {
return (Num((Aluno) i1) == Num((Aluno) i2));}Onde Num é definido por:int Num (Aluno a) { return a->num; };
AED (IST/DEEC) 103
Listas duplamente ligadas [8]
A procura na lista de alunos pode ser feita assim:Aluno Procura(int num, Dl l_alunos) {
Aluno a = NovoAluno(“”,num);return Find(a, l_alunos, AlunoIgual);
}
Onde NovoAluno é um construtor:Aluno NovoAluno(char * nome, int num) {
Aluno a = malloc(sizeof(aluno));a->nome = nome; a->num = num;return a;
}
AED (IST/DEEC) 104
Listas duplamente ligadas [9]
Para imprimir no écran todos os alunos contidos na lista:void PrintAlunos(Dl l_alunos) {
Apply(PrintAluno, l_alunos);}
Onde a função PrintAluno é definida por:void PrintAluno(Item a) {
printf(“Aluno nº %d, %s\n”, Num((Aluno) a), Nome((Aluno) a));
}Não é preciso escrever ciclos !
AED (IST/DEEC) 105
• Tipos abstractos de 1ª Classe
• Filas de Complexos
• Filas de matrizes
• Listas Duplamente Ligadas
Síntese da Aula 6 de Tipologia e Operações