Você está na página 1de 95

Programas operam sobre dados

Dados so relacionados e possuem estrutura

Como representar e manipular dados em


um computador
Para representar um baralho precisamos:
Representar cartas: naipe e valor
struct carta { char naipe; char valor; };
Representar a ordem das cartas
Operaes de manipulao:
Comprar a carta no topo do baralho
Colocar uma carta no fundo do baralho
Embaralhar
Retirar uma carta aleatria do meio do baralho
Estruturas de dados tm vantagens e
desvantagens
Devemos escolher a estrutura de dados
depois de analisar as operaes que vamos
realizar sobre os dados
Empilha(A)
Operaes:
Criar uma pilha
Empilhar um elemento
Desempilhar um elemento
Recuperar o tamanho da pilha
Destruir uma pilha
ltimo elemento a entrar
A
o primeiro elemento a sair Fundo da pilha
Empilha(B)
Operaes:
Criar uma pilha
Empilhar um elemento
Desempilhar um elemento
Recuperar o tamanho da pilha
Destruir uma pilha
B
ltimo elemento a entrar
A
o primeiro elemento a sair Fundo da pilha
Empilha(C)
Operaes:
Criar uma pilha
Empilhar um elemento
Desempilhar um elemento
Recuperar o tamanho da pilha
C
Destruir uma pilha
B
ltimo elemento a entrar
A
o primeiro elemento a sair Fundo da pilha
Desempilha
Operaes:
Criar uma pilha
Empilhar um elemento
Desempilhar um elemento
Recuperar o tamanho da pilha
C
Destruir uma pilha
B
ltimo elemento a entrar
A
o primeiro elemento a sair Fundo da pilha
Empilha(D)
Operaes:
Criar uma pilha
Empilhar um elemento
Desempilhar um elemento
Recuperar o tamanho da pilha
D
Destruir uma pilha
B
ltimo elemento a entrar
A
o primeiro elemento a sair Fundo da pilha
Empilha(E)
Operaes:
Criar uma pilha
Empilhar um elemento
Desempilhar um elemento
E
Recuperar o tamanho da pilha
D
Destruir uma pilha
B
ltimo elemento a entrar
A
o primeiro elemento a sair Fundo da pilha
Soluo de expresses matemticas
Calculadora HP-12c
Guardar variveis locais em chamadas
recursivas de funo
Armazenamento em posies contguas de
um arranjo
Como s precisamos saber a posio do
elemento que est no topo, usamos um
inteiro para armazenar seu ndice no arranjo
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
struct pilha * cria(void) {
struct pilha *p;
p = malloc(sizeof(struct pilha));
4
if(!p) { perror(NULL); exit(1); }
/* IMPORTANTE: */
3 p->topo = 0;
2 /* No precisa alocar o vetor
* por que ele est esttico na
1
* struct pilha. */
0: Topo da pilha }
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
void empilha(struct pilha *p, int A){
p->elementos[p->topo] = A;
p->topo = p->topo + 1;
4
}

3 ...
2 empilha(p, 7123);
...
1

0: Topo da pilha
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
void empilha(struct pilha *p, int A){
p->elementos[p->topo] = A;
p->topo = p->topo + 1;
4
}

3 ...
2 empilha(p, 7123);
...
1

0: 7123
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
void empilha(struct pilha *p, int A){
p->elementos[p->topo] = A;
p->topo = p->topo + 1;
4
}

3 ...
2 empilha(p, 7123);
...
1: Topo da pilha

0: 7123
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
int desempilha(struct pilha *p) {
p->topo = p->topo 1;
return p->elementos[p->topo];
4
}

3: Topo da pilha ...


2: 8905 int t = desempilha(p);
...
1: 1200

0: 7123
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
int desempilha(struct pilha *p) {
p->topo = p->topo 1;
return p->elementos[p->topo];
4
}

3 ...
2: 8905 Topo da pilha int t = desempilha(p);
...
1: 1200

0: 7123
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
int desempilha(struct pilha *p) {
p->topo = p->topo 1;
return p->elementos[p->topo];
4
}

3 ...
2: Topo da pilha int t = desempilha(p);
/* t == 8905 */
1: 1200 ...
0: 7123
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
int tamanho(struct pilha *p) {
return p->topo;
}
4

2: Topo da pilha
1: 1200

0: 7123
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
int destroi(struct pilha *p) {
free(pilha);
}
4

2: Topo da pilha
1: 1200

0: 7123
O cdigo apresentado no testa se a pilha
est cheia antes de empilhar um elemento.
Modifique a funo empilha para que ela
imprima um erro se a pilha estiver cheia.
O cdigo apresentado no testa se a pilha
est vazia antes de desempilhar. Modifique a
funo desempilha pra que ela imprima
um erro se a pilha estiver vazia.
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
void empilha(struct pilha *p, int A){
if(p->topo == MAX_ELEMENTOS-1) {
printf(pilha cheia.);
4
exit(1);
}
3 p->elementos[p->topo] = A;
2 p->topo = p->topo + 1;
}
1

0: Topo da pilha
struct pilha {
int elementos[MAX_ELEMENTOS];
int topo;
}
MAX_ELEMENTOS 1
int desempilha(struct pilha *p) {
if(p->topo == 0) {
printf(pilha vazia.);
4
exit(1);
}
3: Topo da pilha p->topo = p->topo 1;
2: 8905 return p->elementos[p->topo];
}
1: 1200

0: 7123
Enfilera(A)
Operaes:
Criar uma fila
Enfileirar um elemento
Desenfileirar o primeiro elemento
Recuperar o tamanho da fila
Destruir uma fila
Primeiro elemento a entrar
A
o primeiro elemento a sair Comeo da fila
Enfilera(B)
Operaes:
Criar uma fila
Enfileirar um elemento
Desenfileirar o primeiro elemento
Recuperar o tamanho da fila
Destruir uma fila
B
Primeiro elemento a entrar
A
o primeiro elemento a sair Comeo da fila
Enfilera(C)
Operaes:
Criar uma fila
Enfileirar um elemento
Desenfileirar o primeiro elemento
Recuperar o tamanho da fila
C
Destruir uma fila
B
Primeiro elemento a entrar
A
o primeiro elemento a sair Comeo da fila
Desenfilera
Operaes:
Criar uma fila
Enfileirar um elemento
Desenfileirar o primeiro elemento
Recuperar o tamanho da fila
C
Destruir uma fila
B
Primeiro elemento a entrar
Comeo
A da fila
o primeiro elemento a sair Comeo da fila
Enfilera(D)
Operaes:
Criar uma fila
Enfileirar um elemento
Desenfileirar o primeiro elemento
D
Recuperar o tamanho da fila
C
Destruir uma fila
B
Primeiro elemento a entrar
Comeo da fila
o primeiro elemento a sair
Itens so armazenados em posies
contguas de um arranjo
Operao enfilera expande a parte de trs da
fila: marcar o ndice do ltimo elemento
Operao desenfilera retrai a parte da frente
da fila: marcar o ndice do primeiro elemento
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro;
int ultimo;
}
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

struct fila * cria(void) {


struct fila *f;
4 f = malloc(sizeof(struct fila));
3 if(!f) { perror(NULL); exit(1); }
/* IMPORTANTE: */
2
f->primeiro = 0;
1 f->ultimo = 0;
0: Primeiro | ltimo }
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

void enfilera(struct fila *f, int A){


f->elementos[f->ultimo] = A;
4 f->ultimo += 1;
3 }
2

1
...
enfilera(f, 322);
0: Primeiro | ltimo ...
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

void enfilera(struct fila *f, int A){


f->elementos[f->ultimo] = A;
4 f->ultimo += 1;
3 }
2

1: ltimo
...
enfilera(f, 322);
0: 322 Primeiro ...
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

int desenfilera(struct fila *f) {


int r = f->elementos[f->primeiro];
4 f->primeiro += 1;
3: ltimo return r;
}
2: 819

1: 7890
...
int p = desenfilera(f);
0: 322 Primeiro ...
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

int desenfilera(struct fila *f) {


int r = f->elementos[f->primeiro];
4 f->primeiro += 1;
3: ltimo return r;
}
2: 819

1: 7890 Primeiro
...
int p = desenfilera(f);
0 ...
Depois de vrias inseres e
MAX_ELEMENTOS 1
remoes, a fila pode
ultrapassar a memria dos
elementos!
4

3
Soluo: Imaginar o arranjo
2
como um crculo. A posio
1
que vem depois de
(ELEMENTOS_MAX 1)
0
a posio zero
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

void enfilera(struct fila *f, int A){


f->elementos[f->ultimo] = A;
4 f->ultimo += 1;
3 if(f->ultimo == MAX_ELEMENTOS) {
f->ultimo = 0;
2
}
1 }
0: Primeiro | ltimo
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

int desenfilera(struct fila *f) {


int r = f->elementos[f->primeiro];
4 f->primeiro += 1;
3: ltimo if(f->primeiro == MAX_ELEMENTOS) {
f->primeiro = 0;
2: 819
}
1: 7890 return r;
0: 322 Primeiro }
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

int tamanho(struct fila *f) {


int t = f->ultimo f->primeiro;
4 if(t < 0) { t += MAX_ELEMENTOS; }
3: ltimo return t;
}
2: 819

1: 7890
0: 322 Primeiro
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }

void destroi(struct fila *f) {


free(f);
4 }
3: ltimo

2: 819

1: 7890
0: 322 Primeiro
O cdigo apresentado no checa se a fila est
cheia antes de enfileirar um elemento.
Modifique a funo enfilera para que ela
imprima um erro se a fila estiver cheia.
O cdigo apresentado no checa se a fila est
vazia antes de desenfileirar um elemento.
Modifique a funo desenfilera para que
ela imprima um erro se a fila estiver vazia.
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }
int desenfilera(struct fila *f) {
if(f->primeiro == f->ultimo) {
printf(fila vazia.\n);
4 exit(1);
3: ltimo
}
int r = f->elementos[f->primeiro];
2: 819 f->primeiro += 1;
1: 7890 if(f->primeiro == MAX_ELEMENTOS) {
f->primeiro = 0;
0: 322 Primeiro
}
return r;
}
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }
void enfilera(struct fila *f, int A){
if(f->ultimo + 1 == f->primeiro){
printf(fila cheia.\n);
4 exit(1);
3 }
f->elementos[f->ultimo] = A;
2
f->ultimo += 1;
1 if(f->ultimo == MAX_ELEMENTOS) {
0: Primeiro | ltimo f->ultimo = 0;
}
}
struct fila {
int elementos[MAX_ELEMENTOS];
int primeiro; int ultimo;
MAX_ELEMENTOS 1 }
void enfilera(struct fila *f, int A){
if((f->ultimo + 1 == f->primeiro)
|| (f->ultimo == MAX_ELEM-1
4 && f->primeiro == 0)) {
3 printf(fila cheia.\n);
exit(1);
2
}
1 ...
0: Primeiro | ltimo
Operaes: Insere(A, O)

Criar uma fila


Inserir um elemento na posio x
Remover o elemento na posio y
Recuperar o elemento na posio z
Inserir ou remover elementos
no incio ou no fim da lista
Recuperar o tamanho da lista A
Destruir uma fila Comeo da lista
Operaes: Insere(B, O)

Criar uma fila


Inserir um elemento na posio x
Remover o elemento na posio y
Recuperar o elemento na posio z
Inserir ou remover elementos
no incio ou no fim da lista A
Recuperar o tamanho da lista A
B
Destruir uma fila Comeo da lista
Operaes: InsereNoFinal(B)

Criar uma fila


Inserir um elemento na posio x
Remover o elemento na posio y
Recuperar o elemento na posio z
Inserir ou remover elementos B
no incio ou no fim da lista A
Recuperar o tamanho da lista B
Destruir uma fila Comeo da lista
Operaes: Remove(1)

Criar uma fila


Inserir um elemento na posio x
Remover o elemento na posio y
Recuperar o elemento na posio z
Inserir ou remover elementos B
no incio ou no fim da lista A
B
Recuperar o tamanho da lista B
Destruir uma fila Comeo da lista
Itens so armazenados em posies
contguas de um arranjo
Precisamos guardar o ndice do ltimo
elemento para inserir e remover elementos
no final da lista

struct lista {
int elementos[MAX_ELEMENTOS];
int ultimo;
}
struct lista {
int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }

struct lista * cria(void) {


struct lista *f;
4 f = malloc(sizeof(struct lista));
3 if(!f) { perror(NULL); exit(1); }
/* IMPORTANTE: */
2
f->ultimo = 0;
1 }
0 ltimo
struct lista {
int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }
void insere_final(struct lista *f,
int A){
if(f->ultimo == MAX_ELEMENTOS-1){
4 printf(lista cheia.\n);
3
exit(1);
}
2 f->elementos[f->ultimo] = A;
1 f->ultimo += 1;
}
0 ltimo
struct lista {
O(1) int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }
void insere_final(struct lista *f,
int A){
if(f->ultimo == MAX_ELEMENTOS-1){
4 printf(lista cheia.\n);
3
exit(1);
}
2 f->elementos[f->ultimo] = A;
1 ltimo f->ultimo += 1;
}
0: 1876
struct lista {
int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }
void insere(struct lista *f,
int A, int posicao){
if(f->ultimo == MAX_ELEMENTOS-1){
4 printf(lista cheia); exit(1);
3 ltimo
}
for(int i = f->ultimo; i > x; i--){
2: 3412 f->elemtos[i] = f->elemtos[i-1];
1: 7182 }
f->ultimo += 1;
0: 1876
f->elementos[x] = A;
}
insere(f, 8818, 2);

MAX_ELEMENTOS 1
void insere(struct lista *f,
int A, int posicao){
if(f->ultimo == MAX_ELEMENTOS-1){
4 printf(lista cheia); exit(1);
3: 3412 ltimo
}
for(int i = f->ultimo; i > x; i--){
2: 3412 f->elemtos[i] = f->elemtos[i-1];
1: 7182 }
f->ultimo += 1;
0: 1876
f->elementos[x] = A;
}
insere(f, 8818, 2);

MAX_ELEMENTOS 1
void insere(struct lista *f,
int A, int posicao){
if(f->ultimo == MAX_ELEMENTOS-1){
4 ltimo printf(lista cheia); exit(1);
3: 3412
}
for(int i = f->ultimo; i > x; i--){
2: 3412 f->elemtos[i] = f->elemtos[i-1];
1: 7182 }
f->ultimo += 1;
0: 1876
f->elementos[x] = A;
}
insere(f, 8818, 2);
O(n)
MAX_ELEMENTOS 1
void insere(struct lista *f,
int A, int posicao){
if(f->ultimo == MAX_ELEMENTOS-1){
4 ltimo printf(lista cheia); exit(1);
3: 3412
}
for(int i = f->ultimo; i > x; i--){
2: 8818 f->elemtos[i] = f->elemtos[i-1];
1: 7182 }
f->ultimo += 1;
0: 1876
f->elementos[x] = A;
}
Implemente as funes
int remover(struct lista *f,
int elemento, int posicao);

int remover_final(struct lista *f);

Qual a complexidade de cada funo?


O que elas fazem quando a lista est vazia?
struct lista {
O(1) int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }
void recupera(struct lista *f,
int posicao) {
return f->elementos[posicao];
4 ltimo }
3: 3412

2: 8818

1: 7182
0: 1876
struct lista {
O(1) int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }
void tamanho(struct lista *f) {
return f->ultimo;
}
4 ltimo

3: 3412

2: 8818

1: 7182
0: 1876
struct fila {
int elementos[MAX_ELEMENTOS];
int ultimo;
MAX_ELEMENTOS 1 }
void destroi(struct lista *f) {
free(f);
}
4 ltimo

3: 3412

2: 8818

1: 7182
0: 1876
Criar uma lista O(1)
Inserir/remover no final O(1)
Inserir/remover na posio X O(N)
Recuperar o elemento na posio X O(1)
Recuperar o tamanho da lista O(1)
Destruir a lista O(1)
Suportam as mesmas operaes de criar,
inserir/remover no final, inserir/remover no
meio, recuperar o valor de um elemento, etc

Possuem modo de operao diferente

Elementos so armazenados em ns, e cada


n tem um apontador para o prximo n na
lista
struct no {
Dado
int dado;
struct no *proximo; Prximo
};
Exemplo de uma sequncia de ns na memria:
0x840 0x440 0x240
1328 125 8645

0x440 0x240 0x0

1328 125 8645


Elementos so armazenados em ns, e cada n
aponta para o prximo n da lista
Precisamos guardar um apontador para o
primeiro elemento (aponta pro resto da lista)

Podemos guardar um apontador para o ltimo


elemento (para inserir/remover no final)
Podemos guardar o tamanho da lista num inteiro
struct lista {
struct no *primeiro;
struct no *ultimo;
int tamanho;
}; Primeiro
Ultimo

Tamanho 3

1328 125 8645


struct lista * cria() {
O(1) struct lista *f;
f = malloc(sizeof(...));
if(!f){ exit(1); }
f->cabeca = malloc(...);
if(!f->primeiro) { exit(1); }
f->ultimo = f->primeiro;
f->tamanho = 0;
f->cabeca->prox = NULL;
Cabeca
return f;
Ultimo }
Tamanho O
CABECA
Cabeca

Ultimo

Tamanho 43

CABECA
477

1328 125 8645


void insere_inicio(struct lista *f, int A) {
struct no *novo;
novo = malloc(sizeof(struct no));
if(!novo) { perror(NULL); exit(EXIT_FAILURE); }
novo->dado = A;
novo->prox = f->cabeca->prox;
/* NOTA: se a lista estiver vazia, novo->prox
* fica NULL por que f->primeiro o n cabea.
* se n cabea tem que testar se a lista est
* vazia e tratar caso especial. */
f->cabeca->prox = novo;
f->tamanho += 1;
} O(1)
Cabeca
477
Ultimo

Tamanho 43

CABECA

1328 125 8645


void insere_final(struct lista *f, int A) {
struct no *novo = malloc(sizeof(struct no));
if(!novo) { perror(NULL); exit(EXIT_FAILURE); }
novo->dado = A;
novo->prox = NULL;
struct no *ultimo = f->ultimo;
f->ultimo->prox = novo;
/* ultimo->prox = novo; */
f->ultimo = novo;
f->tamanho += 1;
}

O(1)
Cabeca
477
Ultimo

Tamanho 34

CABECA

1328 125 8645


void insere_atras(struct lista *f, int A,
struct no *E) {
struct no *novo = malloc(sizeof(struct no));
if(!novo) { perror(NULL); exit(EXIT_FAILURE); }
novo->dado = A;
novo->prox = E->prox;
E->prox = novo;
if(f->ultimo == E) {
/* insero no final da lista */
f->ultimo = novo;
}
}
O(1)
Os tres mtodos de insero mostrados (no
incio, no final e aps um elemento E) so
equivalentes
Insero no incio insero aps o f->cabeca
Insero no final insero ps o f->ultimo
Insero aps um n E
Tem de seguir os ponteiros prox X vezes
struct no * no_antecessor(struct lista *f, int pos){
struct no *ante = f->cabeca;
int i = 0;
while(i < pos) {
ante = ante->prox;
i += 1;
}
return ante;
}
O(X)
Cabeca

Ultimo

Tamanho 4

CABECA
477

1328 125 8645


Cabeca

Ultimo

Tamanho 3
4

CABECA
477

1328 125 8645


int remove_inicio(struct lista *f) {
struct no *primeiro = f->cabeca->prox;
if(primeiro == NULL) {
printf(lista vazia.\n); return INT_MIN;
}
f->cabeca->prox = primeiro->prox;
f->tamanho -= 1;
int dado = primeiro->dado;
free(primeiro);
return dado;
}

O(1)
Temos que destruir todos os ns da lista
void destroi(struct lista *f) {
struct no *liberar;
while(f->cabeca->prox) {
liberar = f->cabeca;
f->cabeca = f->cabeca->prox;
free(liberar);
}
free(f->cabeca);
free(f);
}
Criar uma lista O(1)
Inserir/remover no final O(1)
Inserir/remover atrs de antecessor O(1)
Encontrar o anterecessor de X O(N)
Recuperar o elemento na posio X O(N)
Recuperar o tamanho da lista* O(1)
Destruir a lista O(N)
ARRANJOS PONTEIROS

Limite mximo de nmero Sem limite de elementos


de elementos (enquanto tiver memria)

Acesso direto ao n-simo Acesso ao n-simo


elemento da lista O(1) elementos requer seguir
vrios apontadores O(n)

Insero/remoo no meio Insero/remoo com


implica realocar todos os antecessor fcil O(1)
elementos seguintes O(n)
Ponteiros usam memria
Na implementao de lista vista, s podemos
inserir atrs de um n antecessor. Por qu?
Por que temos de modificar o ponteiro prox do
antecessor

Como fazer uma lista onde podemos


adicionar elementos na frente de um n
sucessor?
Cabeca Dado

Ultimo Anterior

Tamanho 3 Proximo

CABECA

1328 125 8645


1328 E 8645

Novo
125
1328 125 8645

void insere_antes(struct listadupla *f, int A,


struct no *E) {
struct no *novo = malloc(sizeof(struct no));
if(!novo) { perror(NULL); exit(EXIT_FAILURE); }
novo->dado = A;
novo->prox = E;
novo->ante = E->ante;
E->ante->prox = novo;
E->ante = novo;
}
Cabeca Dado

Ultimo Anterior

Tamanho 3 Proximo

CABECA

1328 125 8645


Implemente a funo
int remove_final(struct lista *f);
Implemente a funo
int remove_atras(struct lista *f, struct no *E);

Suas funes funcionam quando a lista est


vazia? E quando a removemos o primeiro ou
ltimo elementos?
Qual a complexidade de suas funes? Elas
devem ter custo O(1).
As listas que implementamos at agora s
armazenavam elementos do tipo int
E se quisermos armazenar outros tipos de
dados, ou armazenar estruturas complexas
dentro de uma lista?

Armazenar ponteiros para void


Eles podem apontar para qualquer tipo de dado
Todos os algoritmos para criar e destruir uma
lista, bem como para remover e inserir
elementos continuam os mesmos
A nica mudana no tipo do parmetro
recebido pelos mtodos de insero e no tipo
do retorno dos mtodos de remoo
struct no {
struct no *ante;
struct no *prox;
void *dado;
}
void insere_inicio(struct listadupla *f, void *d);

...
/* armazenando um ponteiro pra double */
struct listadupla *f = cria_lista_dupla();
double *fracao = malloc(sizeof(double));
if(!fracao) { perror(NULL); exit(EXIT_FAILURE); }
insere_inicio(f, fracao);
/* continua processamento */
...
struct no {
struct no *ante;
struct no *prox;
void *dado;
}
void* recupera(struct listaduple *f, int posicao);

...
/* recuperando um elemento */
void *dado = recupera(f, 0);
double *fracao = (double *)dado; /* cuidado! */
/* faz operaes com a variavel fracao e depois: */
free(dado);
/* continua processamento */
...
Implemente pilha e fila com ponteiros.