estrutura de dados -...
TRANSCRIPT
Estruturas de Dados
Listas e Filas
2
Estrututuras de dados lineares
Pilhas
Pilhas (stack)
Estrutura de dados onde a inserção e remoção de elementos ocorre a partir de uma único ponto de interação – o topo da pilha
LIFO ◦ Last In First Out
Exemplos ◦ Pilha de pratos a lavar
◦ Pilha de execução na linguagem C
Variáveis locais são empilhadas em uma pilha
Ao término da função, as variáveis são desempilhadas
4
Pilhas
Operações ◦ Empilhar (push)
Insere um novo elemento no topo da pilha
◦ Desempilhar (pop)
Recupera e remove um elemento do topo da pilha
5
Listas 6
Lista sequencial
Lista encadeada
Listas
Lista sequencial ◦ Acesso a qualquer elemento em tempo constante
◦ Movimentação e inserção custosa
◦ Tamanho máximo definido
◦ Ideal para:
Listas de tamanho conhecido (pequenas), inserção remoção no fim
7
Listas
Lista encadeada ◦ Não precisa deslocar elementos nas operações de inserção e remoção
◦ Crescimento em tempo de execução
◦ Limite é a memória disponível
◦ Acesso a elementos, porém, requer busca prévia
◦ Ideal para:
Listas grandes, inserção/remoção no meio, sem tamanho máximo definido
8
Listas encadeadas
Ponteiros
9
typedef struct no {
t_elemento dado; // elemento contendo os dados
struct no * prox; // ponteiro para o proximo elemento
} t_no; // tipo da estrutura
t_no * p;
Listas encadeadas 10
free(P);
P = NULL;
Lista encadeada 11
// Tipo base dos elementos da lista
typedef struct elementos {
char nome[50];
// Outros elementos
} t_elemento;
// Estrutura lista
typedef struct no {
t_elemento dado; // elemento contendo os dados
struct no * prox; // ponteiro para o proximo elemento
} t_no; // tipo da estrutura
// define t_lista como sendo um outro nome para "t_no *"
typedef t_no* t_lista;
12
t_no * criaNo() {
t_no * no = (t_no*) malloc(sizeof(t_no));
if (no)
no->prox = NULL;
return no;
}
int isVazia(t_lista lista) {
return (lista == NULL);
}
int getTamanho(t_lista lista) {
int n = 0;
while (lista != NULL) {
lista = lista->prox;
n++;
}
return n;
}
Lista encadeada 13
t_no * getNo(t_lista lista, int pos) {
int n = 0;
if (pos<0)
return 0;
while (lista != NULL) {
if (n==pos)
return lista;
lista = lista->prox;
n++;
}
return 0;
}
Lista encadeada 14
t_elemento * getElemento(t_lista lista, int pos)
{
t_no * no = getNo(lista, pos);
if (no != NULL)
return &(no->dado);
else
return NULL;
}
Lista encadeada 15
int getPosicao(t_lista lista, t_elemento dado) {
int n = 0;
while (lista != NULL) {
if (compara(lista->dado, dado)==0)
return n;
lista = lista->prox;
n++;
}
return -1;
}
int compara(t_elemento dado1, t_elemento dado2) {
return strcmp(dado1.nome, dado2.nome);
}
Lista encadeada: implementação
16
int inserir(t_lista *lista, int pos, t_elemento dado) {
t_no * p, * novo;
if (pos == 0) {
novo = criaNo();
if (novo == NULL)
return 0;
novo->dado = dado;
novo->prox = *lista;
*lista = novo;
return 1;
}
p = getNo(*lista, pos-1);
if (p == NULL)
return 0;
novo = criaNo();
if (novo == NULL)
return 0;
novo->dado = dado;
novo->prox = p->prox;
p->prox = novo;
return 1;
}
Lista encadeada 17
int remover(t_lista *lista, int pos) {
t_no *anterior, *p;
if (isVazia(*lista)) return 0; // erro: lista vazia
if (pos<0) return 0; // erro: posicao invalida
// remocao da primeira posicao em lista nao vazia
if (pos == 0) {
p = *lista;
*lista = p->prox;
} else { // remocao em qualquer posicao
anterior = getNo(*lista, pos-1);
if (anterior == NULL)
return 0; // erro: posicao invalida
p = anterior->prox;
if (p == NULL)
return 0; // erro: posicao invalida
anterior->prox = p->prox;
}
free(p);
return 1;
}
Listas
Distribuição na memória ◦ Sequencial
◦ Encadeada
Tamanho ◦ Estática
◦ Dinâmica
Ordenamento ◦ Ordenada
◦ Desordenada
18
Listas ordenadas
Implementação sequencial ou encadeada
Nós ordenados de acordo com os dados que possuem e uma lógica de ordenação
Complexidade de implementação comparável com as não ordenadas
Diferente apenas na operação de inserção ◦ Não é necessário passar a posição de inserção
◦ É efetuada uma busca pela posição correta
19
Lista encadeada ordenada 20
int getPosicaoInsercaoOrdenada(t_lista lista, t_elemento dado)
{
int n = 0;
while (lista != NULL) {
if (compara(lista->dado, dado)>=0)
return n;
lista = lista->prox;
n++;
}
// lista vazia, ou nao achou elemento, retorna posicao zero
return n;
}
Listas encadeadas
Listas circulares
21
Listas circulares
Último elemento aponta para o primeiro, e não mais para NULL
É possível atingir qualquer elemento da lista a partir de qualquer nó.
Convencionalmente utiliza-se como ponteiro para a lista um ponteiro para o último elemento. ◦ Tem-se acesso direto ao “último” e “primeiro” elemento.
22
Lista encadeada 23
Lista duplamente encadeada
Lista circular duplamente encadeada
Lista duplamente encadeada 24
// Tipo base dos elementos da lista
typedef struct elementos {
char nome[50];
} t_elemento;
// Estrutura lista
typedef struct no {
struct no * anterior; // ponteiro para o proximo elemento
t_elemento dado; // elemento contendo os dados
struct no * prox; // ponteiro para o proximo elemento
} t_no; // tipo da estrutura
Lista duplamente encadeada
É possível percorrer a lista em ordem inversa
O nó atual acessa o antecessor e o sucessor
Último e primeiro nós são equivalentes
Desvantagem: Mais memória com o ponteiro extra
25
Filas
Conjunto de itens onde o acesso a elementos é feito em uma extremidade (início da fila) e as inserções de elementos são realizadas na outra extremidade (final da fila)
First in, first out (FIFO) Lista linear em que a inserção é feita
numa extremidade e a eliminação na outra.
26
Filas
Fila de um banco Fila do cinema Fila de atendimento
◦ Quem primeiro entrar na fila, é o primeiro a ser atendido (a sair da fila).
Grupo de carros esperando sua vez para passar no pedágio
Gerenciador de impressão num ambiente multiusuário (impressora compartilhada)
Escalonamento de tarefas: fila de processos aguardando os recursos do sistema operacional.
Fila de pacotes a serem transmitidos numa rede de computadores
27
Filas
Implementação ◦ Realizada a partir de uma lista com duas cabeças (ponteiros).
◦ A implementação encadeada dinâmica torna mais simples as operações de inserção e remoção.
◦ Já a implementação sequencial é um pouco mais complexa, mas pode ser usada quando há previsão do tamanho máximo da fila.
28
Filas
Fila sequencial ◦ Um vetor de elementos
◦ Um campo para controlar o início da fila
◦ Outro campo para controlar o final da fila
29
Filas 30
Filas
Existem mais dois elementos livres na fila, mas nenhum outro elemento pode ser inserido
Fila.final chegou à condição de limite (MAX -1)
Podemos chegar à situação absurda em que a fila está vazia, mas nenhum elemento novo pode ser inserido
A representação sequencial descrita anteriormente não é adequada
31
Filas
Problemas… Existem mais dois elementos livres na fila,
mas nenhum outro elemento pode ser inserido
Fila.final chegou à condição de limite (MAX -1)
Podemos chegar à situação absurda em que a fila está vazia, mas nenhum elemento novo pode ser inserido.
Conclusão: A representação sequencial descrita anteriormente não é adequada!
32
Fila circular 33
Forçar final a usar o espaço liberado na frente
Para permitir a reutilização das posições já ocupadas, usa-se o conceito de Fila Circular
x x x x x
fim inicio
Fila circular
Fila cheia?
Quando o fim == (inicio-1) ou
Se o inicio for zero?
Quando o fim == (MAX-1);
O ponteiro do fim não pode passar pelo do inicio;
34
x x x x x
fim inicio
Filas - Implementação
Operações ◦ Criar fila
◦ Verificar se fila está vazia
◦ Verificar se fila está cheia
◦ Inserir item na fila
◦ Remover item da fila
◦ Exibir fila
◦ Esvaziar fila
35
Fila sequencial 36
// tamanho maximo da fila
#define MAX 5
// Tipo base dos elementos da fila
typedef struct elementos {
char nome[50];
} t_elemento;
typedef struct fila {
t_elemento vetor[MAX]; // vetor que armazena a fila
int inicio; // posicao do primeiro elemento
int fim; // posicao do ultimo elemento
int quant_element; // numero de elementos da fila
} t_fila;
Fila sequencial 37
t_fila criar()
{
t_fila fila;
fila.inicio = 0;
fila.fim = -1;
fila.quant_element = 0;
return fila;
}
int isVazia (t_fila * fila)
{
return (fila->quant_element == 0);
}
int isCheia(t_fila * fila)
{
return (fila->quant_element == MAX);
}
Fila sequencial 38
int inserir (t_fila * fila, t_elemento valor)
{
if (isCheia(fila))
return 0;
(fila->quant_element)++;
fila->fim = (fila->fim + 1) % MAX;
fila->vetor[fila->fim] = valor;
return 1;
}
t_elemento remover(t_fila * fila)
{
t_elemento valor = { "" } ;
if (isVazia(fila))
return valor; // Erro: fila vazia
valor = fila->vetor[fila->inicio];
fila->vetor[fila->inicio].nome[0] = '\0';// zera, opcional
(fila->quant_element)--;
fila->inicio = (fila->inicio + 1) % MAX;
return valor;
}
Fila sequencial 39
void exibir(t_fila * fila) {
int i;
if (isVazia(fila)) {
printf("Fila vazia\n");
return;
}
printf("\nExibindo fila:\n");
printf("inicio: %d\n", fila->inicio);
printf("fim: %d\n", fila->fim);
for (i=0 ; i<MAX ; i++) {
printf("%d::%s\n", i, fila->vetor[i].nome);
}
}
Fila encadeada
Lista simplesmente encadeada “especial”
Para remover da fila, implementa-se uma função que retira sempre do início
Para inserir na fila, implementa-se uma função que acrescenta sempre no final
40
Fila encadeada
Lista simplesmente encadeada – Desvantagem: Para cada elemento inserido na fila, teremos
que percorrer todos os nós até encontrar o último. Não é interessante
Lista simplesmente encadeada com dois ponteiros;
–Desvantagem: ter dois ponteiros Lista simplesmente encadeada circular
–Único ponteiro para o final da fila Lista simplesmente encadeada com cabeça especial.
–Um único ponteiro para a cabeça especial, e, essa cabeça é que tem o ponteiro para o inicio e o fim
41
Fila encadeada
Características ◦ Ponteiro para o primeiro nó;
◦ Ponteiro para o último nó;
◦ Informação sobre a quantidade de elementos da lista.
42
Fila encadeada
Operações ◦ Criar fila
◦ Verificar se fila está vazia
◦ Inserir item na fila
◦ Remover item da fila
◦ Exibir fila
◦ Esvaziar fila
43
Fila encadeada 44
// Tipo base dos elementos da lista
typedef struct elementos {
char nome[50];
} t_elemento;
typedef struct no {
t_elemento dado;
struct no * prox;
} t_no;
typedef struct fila {
t_no* inicio;
int quant_element;
t_no* final;
} t_fila;
Fila encadeada 45
t_fila * criaCabeca ()
{
t_fila * fila = (t_fila*) malloc(sizeof(t_fila));
if (fila) {
fila->inicio = fila->final = NULL;
fila->quant_element=0;
}
return fila;
}
t_no * criaNo() {
t_no * no = (t_no*) malloc(sizeof(t_no));
// verifica se houve memoria suficiente para alocar
if (no)
no->prox = NULL;
return no;
}
Fila encadeada 46
int isVazia (t_fila * fila)
{
return (fila->quant_element == 0);
}
int inserir (t_fila *fila, t_elemento valor) {
t_no *novo;
novo = criaNo();
if (novo == NULL)
return 0; // Erro: memoria insuficiente
novo->dado = valor;
if (isVazia(fila))
fila->inicio = novo;
else
(fila->final)->prox = novo;
fila->final = novo;
fila->quant_element++;
return 1;
}
Fila encadeada 47
t_elemento remover (t_fila *fila)
{
t_no *aux;
t_elemento valor = { "" } ;
if (isVazia(fila))
return valor; // Erro: fila vazia
valor = (fila->inicio)->dado;
if (fila->inicio == fila->final)
fila->final = NULL;
aux = fila->inicio;
fila->inicio = (fila->inicio)->prox;
free(aux);
fila->quant_element--;
return valor;
}
Fila de prioridade
Filas de prioridade – A fila fica ordenada por ordem de prioridade.
– A operação de inserção não insere somente no final, pode ser em qualquer posição obedecendo a ordem de prioridade.
– A operação de remoção remove sempre o primeiro elemento.
– Implementação:
• Remoção rápida: O(1)
• Inserção lenta: O(n), ou O(log n). Depende da implementação. Para atingir O(log n) teria que ser implementada usando árvores na implementação encadeada; ou busca binária na implementação sequencial.
48
Próximas aulas
Estruturas de dados não lineares
49
Referências
Notas de Aula do Prof. Bruno B. Boniati
Notas de Aula do Prof. João Luís Garcia Rosa
Notas de Aula do Prof. Derzu Omaia
50