Estruturas de dados clássicas
Vetores ou arrays
Vetores, ou arrays, são estruturas de dados lineares e estáticas, isto é, são compostas por
um número fixo (finito) de elementos de um determinado tipo de dados.
O espaço de memória utilizado é alocado em tempo de compilação (declaração das
variáveis), ou seja, quando o programa começa a ser executado, as variáveis do tipo vetor
já estão alocadas na memória com o número total de elementos.
O tempo de acesso aos elementos de um vetor é muito rápido, sendo considerado
constante: os elementos são acessados pelo seu índice no vetor.
Porém, a remoção de elementos pode ser custosa se não for desejável que haja espaços
"vazios" no meio do vetor, pois nesse caso é necessário "arrastar" de uma posição todos
os elementos depois do elemento removido.
Essa é uma estrutura muito recomendada para casos em que os dados armazenados não
mudarão, ou pouco mudarão, através do tempo.
Lista
A Lista é uma estrutura de dados linear, composta por uma sequência de nós ou nodos.
Existem duas formas de representar as listas:
- Alocação sequencial: os nós ocupam posições sequenciais contíguas.
- Alocação dinâmica (encadeada): os nós (celulas) apontam para o próximo
elemento da lista.
Diferentemente dos vetores, na alocação dinâmica a reserva de memória para cada célula
(nó) ocorre em tempo de execução do programa. Neste caso, a quantidade máxima de nós
em uma lista será determinada pelo tamanho de memória disponível no computador.
Outra vantagem da alocação dinâmica sobre a seqüencial é que o gasto de memória é
proporcional ao número de nós da lista. Por exemplo, se a lista tiver apenas dois nós,
serão gastos bytes de memórias referentes a estes dois nós.
Para trabalhar com uma lista dinâmica (ligada), devemos guardar o primeiro elemento da
lista.
Lista simplesmente encadeada (LSE): cada nó da lista ponta para o próximo nó.
A LSE só pode ser percorrida em um único sentido
Lista duplamente encadeada (LDE): cada nó da lista aponta para o nó anterior e
posterior.
A LDE pode ser percorrida em ambos os sentidos
Lista Circular: O primeiro nó aponta para o último e o último aponta para o primeiro.
Noções da Linguagem C pág 1
Pilha
.
É uma lista linear em que todas as inserções, as remoções e os acessos são feitos em
uma única extremidade, chamada topo.
São baseadas no princípio LIFO (last in, first out) ou UEPS (Último a entrar, primeiro a sair)
onde os dados que foram inseridos por último na pilha serão os primeiros a serem
removidos.
Existem duas funções que se aplicam a todas as pilhas:
PUSH, que insere um dado no topo da pilha, e POP, que remove o item no topo da pilha.
Exemplos de pilhas são as pilhas de pratos, pilhas de livros, etc.
Exemplo:
Considere a pilha abaixo:
13
19
14
10
Qual será seu o estado final, após executar as seguintes instruções:
Pop x
Pop y
Pop z
Push y 14
Push x 13
Push z 19
10 Resposta:
Noções da Linguagem C pág 2
Qual será o estado final das pilhas abaixo, após executar as seguintes instruções:
4
3
2
1
A B C
Push(B,pop(A))
Push(C,pop(A))
Push(B,pop(A))
Push(C,pop(A))
Push(A,pop(B))
Push(C,pop(B))
Push(C,pop(A))
2
4
1
3
A B C
Resposta:
Noções da Linguagem C pág 3
Fila
As filas são estruturas baseadas no princípio FIFO (first in, first out) ou PEPS (Primeiro a
entrar, primeiro a Sair) em que os elementos que foram inseridos no início são os primeiros
a serem removidos.
Uma fila possui duas funções básicas: ENQUEUE (incluir - INC), que adiciona um
elemento ao final da fila, e DEQUEUE (retirar - DEL), que remove o elemento no início da
fila.
Ex: fila de bancos,
A política de inserção e remoção em filas é conhecida como:
A) FILO
B) LIFO
C) UEPS
D) LILO
E) FIFO
Resposta: E
A política de inserção e remoção em pilhas é conhecida como:
A) LIFO
B) FILO
C) PEPS
D) LILO
E) FIFO
Resposta: A
Qual será o estado final da Fila abaixo após executar as instruções:
inicio
Y F C
INC “X”
INC “T”
DEL
DEL
INC “R”
INC “J” Resposta:
DEL C–X–T–R-J
Deque de entrada restrita: A remoção poder ser feita por qualquer extremidade, porém as
inclusões podem ser feitas apenas por uma.
Deque de saída restrita: A inclusão poder ser feita por qualquer extremidade, porém as
remoções podem ser feitas apenas por uma.
Noções da Linguagem C pág 4
Noções da Linguagem C pág 5
Estruturas de Dados Encadeadas Dinâmicas - Implementação Física
Listas Simplesmente Encadeadas (LSE)
A grande diferença da lista para as outras estruturas de dados, é que as listas não
possuem critério de inclusão e remoção de dados.
Uma lista encadeada tem necessariamente uma variável ponteiro apontando para o seu
primeiro elemento. Essa variável será utilizada sempre, mesmo que a lista esteja vazia, e
deverá apontar sempre para o início da lista (primeiro elemento). Caso esta primeira
variável não seja atualizada corretamente (no caso da inclusão de um elemento na
primeira posição), a lista poderá se perder na memória e não ser mais acessível.
Um elemento da lista é composto de duas partes: a informação propriamente dita e uma
conexão com o próximo elemento.
São chamadas de simplesmente encadeadas porque possuem somente o endereço do
seu próximo (próximo elemento).
typedef struct celula
{ int dados; /* campo para os dados */
struct celula *proximaCelula; /* ponteiro para a proxima celula */
}tipoCelula; /* nome do novo tipo de estrutura */
Uma lista encadeada é toda alocada dinamicamente.
Sabemos que a memória alocada dinamicamente não possui um nome como acontece nas
variáveis comuns, portanto, todas as listas devem possuir uma variável padrão, do tipo
ponteiro, que vai apontar para o seu inicio.
Uma vez que o primeiro elemento será uma célula, e cada célula é uma estrutura, então a
variável que apontará para o início da lista será um ponteiro de estrutura.
A variável início mostrada na figura acima será então definida como:
TipoCelula * inicio; /* ponteiro para uma estrutura tipoCelula */
Uma vez que a lista não possui elementos ainda, então:
inicio = NULL;
Para uma lista vazia (sem células), a variável inicio possui valor NULL:
Noções da Linguagem C pág 6
Incluindo o primeiro elemento (primeira célula):
TipoCelula aux; /* variavel auxiliar: ponteiro para uma estrutura tipoCelula
Para reservar memória para nova célula, utilizamos o comando malloc
aux = malloc (sizeof (tipoCelula));
Temos então:
e precisamos atualizar os ponteiros para que a lista receba seu primeiro elemento. Sendo
assim:
1) aux->proximaCelula = NULL; // atribui NULL ao campo proximacelula da célula
apontada por aux
2) inicio = aux; // copia o endereco de aux em inicio
2
Para inserir dados nesta primeira célula, podemos utilizar o ponteiro aux, que permanece
apontando para a célula.
aux->dados = 10; /*atribui o valor 10 ao campo dados da célula pontada por aux
Obs: Cada célula de uma lista também é chamada de nó ou nodo
O programa a seguir cria uma lista com três nós, conforme exibida a abaixo
inicio
matricula proximo
11 2 3
Noções da L inguagem C 7 pá
#include <stdio.h>
#include <stdlib.h>
main( )
{ typedef struct no
{int matricula;
stuct no *proximo;
} tipoNo;
tipoNo *inicio, *novo, *atual;
/* cria o primeiro registro (nodo 1) */
novo = malloc(sizeof (tipoNo)); /* aloca o nó na memória */
novo->matricula = 1; /* atribui 1 para amatrícula */
novo->proximo = NULL; /* NULL = Fim */
inicio = novo; /* inicio aponta para o primeiro nó */
atual = novo;
/* cria o segundo registro (nodo 2) */
novo = malloc(sizeof (tipoNo)); /* instancia o segundo nó */
novo->matricula = 2;
novo->Proximo = NULL; /* NULL = Fim */
atual->proximo = novo; /* nó anterior aponta para o segundo lista */
atual = novo;
/* cria o terceiro registro (nó 3) */
novo = malloc(sizeof (tipoNo)); /* instancia o terceiro nó */
novo->matricula = 3;
novo->Proximo = NULL; /* NULL = Fim */
atual->proximo = novo; /* nó anterior aponta para o segundo lista */
atual = novo;
/* exibe os nós da lista */
atual = inicio;
while (atual != NULL)
{ printf("\n matricula = %d ",atual->matricula);
atual=atual->proximo;
}
getchar();
}
Noções da L inguagem C 8 pá
O programa abaixo cria uma lista dinâmica (FILA) com 5 nós, contendo as matrículas:
1, 2, 3, 4, e 5, respectivamente.
#include "stdio.h"
#include <stdlib.h>
main()
{ typedef struct no
{int matricula;
struct no *proximo;
}tipoNo;
tipoNo *inicio, *novo, *atual;
int i;
clrscr();
inicio = atual = NULL;
for (i=1;i<6;i++)
{ novo = malloc(sizeof(tipoNo));
novo->matricula = i;
novo->proximo=NULL;
if (inicio == NULL)
inicio = novo;
else
atual->proximo = novo;
atual = novo;
}
/* exibe a lista */
atual = inicio;
while (atual != NULL)
{ printf("\n matricula = %d ",atual->matricula);
atual=atual->proximo;
}
getch();
}
Inicio
matricula
prox
11 2 3 4 5
Noções da L inguagem C 9 pá
O programa abaixo cria uma lista dinâmica (tipo Pilha) com 3 nós, contendo as matrículas:
1, 2, e 3.
topo
matriculaaprox
#include <stdio.h>
3 2 1
main()
{
typedef struct no
{int matricula;
struct no *proximo;
}tipoNo;
tipoNo *topo, *novo, *atual;
clrscr();
/* inclui primeiro registro na pilha */
novo = malloc(sizeof(tipoNo));
novo->matricula = 1;
novo->proximo = NULL;
topo = novo;
/* inclui segundo registro na pilha */
novo = malloc(sizeof(tipoNo));
novo->matricula = 2;
novo->proximo = topo;
topo = novo;
/* inclui terceiro registro na pilha */
novo = malloc(sizeof(tipoNo));
novo->matricula = 3;
novo->proximo = topo;
topo = novo;
/* exibe os registros da pilha */
atual = topo;
while (atual != NULL)
{ printf("\n matricula = %d ",atual->matricula);
atual=atual->proximo;
}
getch();
}
Será exibido: matricula = 3
matricula = 2
matricula = 1
Noções da L inguagem C 10 pág
O programa abaixo cria uma lista encadeada do tipo Pilha, com as matrículas, 1, 2,3,4 e 5.
#include "stdio.h"
main()
{
typedef struct no
{int matricula;
struct no *proximo;
}tipoNo;
tipoNo *topo, *novo, *atual;
int i;
clrscr();
topo = atual = NULL;
for (i=1;i<6;i++)
{ novo = malloc(sizeof(tipoNo));
novo->matricula = i;
if (topo == NULL)
novo->proximo = NULL;
else
novo->proximo = topo;
topo = novo;
}
/* exibe os registros da pilha */
atual = topo;
while (atual != NULL)
{ printf("\n matricula = %d ",atual->matricula);
atual=atual->proximo;
}
getch();
Será exibido: matricula = 5
matricula = 4
matricula = 3
matricula = 2
matricula = 1
topo
matricula proximo
15 4 3 2 1
Noções da L inguagem C 11 pág
Percorrendo a lista
Para percorrer uma lista (fila ou pilha) temos que utilizar uma variável auxiliar (ponteiro
auxiliar).
Inicialmente, aux deverá apontar para o início da fila (ou para o topo, no caso das pilhas).
Depois, aux receberá o endereço contido no campo proximo, ou seja, receberá o
endereço da próxima célula (próximo nó).
Enquanto aux for diferente de NULL, repete-se o processo acima.
Observe o trecho de programa a seguir que exibirá todos os nós da lista.
aux = inicio;
while (aux != NULL)
{ printf("\n matricula = %d ",aux->matricula);
aux = aux->proximo;
}
getchar();
}
Inicio
matricula proximo
11 2 3 4 5
Noções da L inguagem C 12 pág
Incluindo um nó no final da lista (Fila)
O último nó da lista não apontava para nenhum outro, agora, este deverá apontar para o
novo nó.
Início 10 27
valor Próximo valor Proximo
- se a lista não é vazia, percorrer a lista até a última célula (aux apontará para o último nó)
- alocar memória para o novo nó (malloc)
- atribuir dados aos campos de dados
- atribuir NULL ao campo ponteiro da nova célula incluída
- atribuir ao campo ponteiro da última célula o endereço da nova célula
TipoNo *aux, *inicio, *novo;
if (inicio != NULL)
{ aux = inicio;
while(aux->proximo != NULL)
aux = aux->proximo;
novo = malloc(sizeof(tipoNo))
novo->valor = 55;
novo->proximo = NULL;
aux->proximo = novo;
}
Desta forma, a lista ficará assim:
Início
10 27 55
valor Proximo valor Proximo Valor Proximo
Noções da L inguagem C 13 pág
Excluindo o primeiro nó da lista
Início 2 7 3
Dado Prox Dado Prox Dado Prox
apontar aux para o inicio da fila (aux = inicio)
início recebe o endereço do segundo nó (inicio = aux-prox ou inicio = inicio->prox)
retirar o primeiro nó da memória ( free(aux) );
tipoNo *aux, *inicio;
aux = inicio; /* aux aponta para o início da fila */
inicio = aux->prox; /* inicio aponta para o segundo nó */
free(aux); /* libera da memória do primeiro nó */
A lista ficará da seguinte forma:
inicio
Dado prox
17 3
Noções da L inguagem C 14 pág
Excluindo um nó qualquer da lista
Observe a lista:
Início 2 7 3
Dado Prox Dado Prox Dado Prox
Desejamos fazer a exclusão do nó com valor 7 (segundo nó)
- percorrer a lista até o nó anterior ao de valor 7 (primeiro nó)
- atribuir o endereço do nó de valor 7 a um ponteiro auxiliar (para poder liberar a memória)
- alterar o endereço apontado pelo nó 1, para que ela aponte para onde o nó de valor 7 aponta
atualmente (nó 3).
- liberar a memória do nó de valor 7 ( free(aux) )
A lista ficará da seguinte forma:
Início 2 7 3
Dado Prox Dado Prox Dado Prox
tipoNo aux, apaga;
aux = inicio;
while(aux->prox->valor != 7)
aux = aux->prox;
apaga = aux->prox; /* apaga recebe o endereço do nó 2 */
aux->prox = apaga->prox; /* nó 1 aponta para o nó 3 */
free(apaga); /* libera área do nó 2 */
Noções da L inguagem C 15 pág
Listas Duplamente Encadeadas (LDE)
As listas duplamente encadeadas são aquelas em que cada nó possui não só o endereço
do nó anterior mas também o endereço do próximo nó. Observe o gráfico e a declaração
abaixo:
typedef struct celula
{
struct celula *anterior; /* ponteiro da celula anterior */
int indice; /* campo de dado */
char nome[15]; /* campo de dado */
struct no *proxima; /* ponteiro da proxima célula */
} tipoCelula;
tipoCelula *cabeca, *cauda;
Noções da L inguagem C 16 pág
Exercícios
1) Cite duas características das LSE (listas Resposta:
simplesmente encadeadas) Cada nó aponta para o nó posterior
Só pode ser percorrida em um único
sentido
2) Cite duas características das LDE (listas Resposta:
duplamente encadeadas) Cada nó aponta para o nó posterior e
para o nó anterior
Pode ser percorrida nos dois sentidos
3) Cite duas características das estruturas com Resposta:
alocação estática de memória A quantidade de memória a ser alocada
para as variáveis é definida em tempo
de compilação (na declaração das
variávies)
A alocação de memória é feita pela
quantidade máxima de elementos
definida no vetor.
Não podemos alterar a quantidade
máxima de elementos declarados (e
alocados) ao longo da execução do
programa.
4) Cite duas características das estruturas com Resposta:
alocação dinâmica de memória A quantidade de memória a ser alocada
para as variáveis é definida em tempo
de execução.
A alocação de memória é feita para
cada célula (nó) individualmente.
A quantidade máxima de elementos
depende exclusivamente da memória
total disponível no computador.
5) Sobre o trecho de programa abaixo, pode-se afirmar que:
typedef struct no
{ int matricula;
char nome[30];
struct no *proximo;
} tipoNo;
tipoNo *inicio;
A)
B) A) Pode ser a estrutura de uma fila estática
C) B) Pode ser a estrutura de um registro de vetor
D) C) Pode ser a estrutura de uma lista duplamente encadeada
E) D) Pode ser a estrutura de uma lista encadeada dinâmica
F) E) Pode ser a estrutura de uma lista estática
Noções da L inguagem C 17 pág
6) Sobre o trecho de programa abaixo, pode-se afirmar que:
typedef struct no
{ int matricula;
char nome[30];
int proximo;
} tipoNo;
tipoNo x[50];
G) A) Pode ser a estrutura de uma lista simplesmente encadeada estática
H) B) Pode ser a estrutura de um PILHA dinâmica
I) C) Pode ser a estrutura de uma lista duplamente encadeada
J) D) Pode ser a estrutura de uma lista encadeada dinâmica
K) E) Pode ser a estrutura de uma FILA dinâmica
7) Sobre o trecho de programa abaixo, pode-se afirmar que:
Typedef struct no
{struct no *anterior ;
int matricula;
char nome[30];
struct no *proximo;
} tipoNo;
tipoNo *inicio;
a) A) Pode ser a estrutura de uma fila estática
b) B) Pode ser a estrutura de um registro de vetor
c) C) Pode ser a estrutura de uma lista duplamente encadeada
d) D) Pode ser a estrutura de uma lista encadeada
e) E) Pode ser a estrutura de uma lista estática
8) Sobre o trecho de programa abaixo, pode-se afirmar que:
Typedef struct no
{ int anterior ;
int matricula;
char nome[30];
int proximo;
} tipoNo;
tipoNo x[50];
f) A) Pode ser a estrutura de uma Fila dinâmica
g) B) Pode ser a estrutura de uma lista duplamente encadeada estática
h) C) Pode ser a estrutura de uma lista duplamente encadeada dinâmica
i) D) Pode ser a estrutura de uma lista simplesmente encadeada
j) E) Pode ser a estrutura de uma Pilha dinâmica
9) A política de inserção e remoção em filas é conhecida como:
F) A) FILO
G) B) LIFO
H) C) UEPS
I) D) LILO
J) E) FIFO
Noções da L inguagem C 18 pág
10) A política de inserção e remoção em pilhas é conhecida como:
F) A) LIFO
G) B) FILO
H) C) PEPS
I) D) LILO
J) E) FIFO
11) Sobre o deque de saída restrita podemos afirmar que:
A) A) Podemos excluir em ambas as extremidades
B) B) Podemos incluir em apenas uma extremidade
C) C) Podemos excluir em apenas uma extremidade
D) D) Não é permitido excluir elementos
E) E) Não é permitido incluir elementos
12) Sobre o deque de entrada restrita podemos afirmar que:
A) Podemos incluir em ambas as extremidades
A) B) Podemos incluir em apenas uma extremidade
B) C) Podemos excluir em apenas uma extremidade
C) D) Não é permitido excluir elementos
D) E) Não é permitido incluir elementos
13) Qual será o estado final da fila, após executar as instruções abaixo:
inicio
Y T F
INC “C”
INC “D”
INC “H”
DEL
DEL
INC “B”
Noções da L inguagem C 19 pág
14) Considerando a pilha ao lado, qual será o
seu estado final após executar as seguintes
instruções: 22
45
Pop x 17
Pop y 5
Pop z
Pop w
Push y
Push x
Push w
Push z
Resposta:
15) Qual será o estado final das pilhas ao lado,
após executar as seguintes instruções: 40
31
Push(B,pop(A)) 27
Push(C,pop(A)) 15
Push(B,pop(A)) A B C
Push(C,pop(A))
Push(A,pop(B))
Push(C,pop(B))
Push(C,pop(A))
C
A B
Resposta:
Noções da L inguagem C 20 pág
16) Percorrendo a lista abaixo, qual a seqüência
obtida ?
1 2 3
S 7 O 3 A 5
4 5 6
R 9 1 B 2
7 8 9
O 4 E T 8
A) BOASORTE
B) BOA SORTE
C) SORTEBOA
D) SORTE BOA
E) SOR TEBOA
17) Percorrendo a lista abaixo, qual a seqüência
obtida ?
1 2 3
X 8 Y 6 Z 9
4 5 6
R 3 T 1 C 4
7 8 9
A 5 G M 7
18) Considerando a lista abaixo que implementa uma PILHA qual será o
primeiro e o último valor a ser excluído desta lista?
Endereço 00 01 02 03 04 05 06
Valor K W I A H Z B
proximo 03 NULL 06 05 02 04 01
19) Suponha que a tabela abaixo represente uma lista encadeada de
nomes, organizada sobre os 5 elementos de um vetor. Qual o primeiro
elemento desta lista?
Elemento Nome Próximo
1 Maria 0
2 Antonio 4
3 João 5
4 Carlos 3
5 Josefina 1
Noções da L inguagem C 21 pág
20) Suponha que a tabela deva representar uma lista duplamente encadeada de cores,
organizada sobre os 5 elementos de um vetor:
Elemento Cor Anterior Próximo
1 ? 4 2
2 ? 1 3
3 ? 2 0
4 ? 5 1
5 ? 0 4
Sabendo-se que a ordem das cores na lista é BEGE – VERDE – AZUL –
VERMELHO – AMARELO, a coluna intitulada cor, na tabela acima, deveria
apresentar, de cima para baixo, o seguinte preenchimento:
A) BEGE- VERMELHO-AMARELO-AZUL-VERDE
B) AZUL-BEGE-VERDE-VERMELHO-AMARELO
C) AMARELO-AZUL-BEGE-VERMELHO-VERDE
D) VERMELHO-AZUL-AMARELO-BEGE-VERDE
E) AZUL-VERMELHO-AMARELO-VERDE-BEGE
21) Considerando que a lista abaixo encontra-se instanciada na memória,
o que será exibido pelo trecho de programa a seguir:
aux = inicio;
while (aux->proximo != NULL)
aux = aux -> proximo;
novo = malloc(sizeof(tipoNo));
novo->valor = “F”;
novo->proximo = NULL;
aux->proximo = novo;
aux = inicio;
while (aux != NULL)
{ printf(“\n %c “,aux->valor);
aux = aux->próximo;
}
inicio
letr proxim
o
H K M
Noções da L inguagem C 22 pág
Noções da L inguagem C 23 pág