Estrutura de dados

37
Estruturas de Dados EA 876 Prof. Marco Aurélio A. Henriques DCA/FEEC/UNICAMP 2007

description

Estrutura de dados

Transcript of Estrutura de dados

Page 1: Estrutura de dados

Estruturas de Dados

EA 876

Prof. Marco Aurélio A. Henriques

DCA/FEEC/UNICAMP

2007

Page 2: Estrutura de dados

O que são estruturas de dados?● São mecanismos de organização das informações

visando um processamento eficiente das mesmas.● Tipos de dados:

– básicos: normalmente dependentes da arquitetura de hardware; não podem ser alterados (redefinidos) por programas; são a base para outros tipos de dados.

● Ex. (em C): int, float, double, char .– abstratos: formados por uma combinação entre tipos

básicos iguais ou diferentes; são criados (definidos) por programas.

● Ex. (em C): arranjos de ints ou de floats; registros ou estruturas; arranjos de estruturas (tabelas).

Page 3: Estrutura de dados

Estruturas de dados lineares● Manutenção da estrutura é independente do

conteúdo.– Estrutura se baseia apenas na posição dos itens.– Manipulação do conteúdo é tarefa da aplicação.– Ex. de estruturas lineares suportadas por C++:

● vector● deque● list

Page 4: Estrutura de dados

Estruturas de dados associativas● Manutenção da estrutura depende do conteúdo

(total ou parcial) dos itens.– Conteúdo parcial dos itens é chamado de chave.– Acesso aos elementos é possível independentemente

da posição.– Ex. de estruturas associativas suportadas por C++:

● conjuntos● mapas

– Muito utilizadas na construção de tabelas.

Page 5: Estrutura de dados

Estruturas lineares: vector● Arranjo com capacidade de armazenamento

dinâmica.– Se o espaço reservado se esgotar, um outro será

reservado automaticamente.– Estrutura simples e de baixa sobrecarga no

armazenamento de dados em memória.– Usos em C++:

● inserir arquivo de cabeçalho: #include <vector>● caso seja um vetor de strings, inserir arquivo de

cabeçalho: #include <string>● criação da estrutura: vector < string > minha_lista● inserção de elementos: inserte ou push_back● remoção de elementos: erase ou pop_back● acesso a elementos: operador [ ]

Page 6: Estrutura de dados

Estruturas lineares: deque● deque = double ended queue● Similar ao vector, mas mantém informações da

posição de ambas extremidades.● Também não é eficiente inserir ou remover

dados intermediários.● Em C++:

– inserir arquivo de cabeçalho: #include <deque>– criar instância: deque <int> fila;– métodos extras: push_front e pop_front

Page 7: Estrutura de dados

Estruturas lineares: list● Implementação de uma lista duplamente

encadeada.– Elementos não estão contíguos na memória: cada um

precisa guardar informações sobre seu antecessor e sucessor na lista.

– Inserções e remoções de elementos intermediários são mais eficientes que em deque ou vector.

– Acesso direto a elementos no interior da lista não é eficiente: operador [ ] não está disponível.

– Usos em C++:● #include <list>; ● #include <string>;● list <string> alunos;

Page 8: Estrutura de dados

Estruturas associativas: sets

● Elementos ordenados pelo seus valores.● Não podem haver elementos repetidos.● Usos em C++:

– #include <set>– set <int> meu_conjunto;– busca de um elemento: find– se houver elementos repetidos: deve ser usado

multiset em lugar de set– outros métodos: set_union, set _intersection

Page 9: Estrutura de dados

Estruturas associativas: maps● Elementos organizados na forma (chave, valor).

– Acesso a valor é possível a partir de chave.– Largamente utilizados em software de sistema.

● Usos em C++:– #include <map>

● #include <multimap> // aceita chaves repetidas– #include <string>– map <string, int> estoque;

● chave é string e valor de estoque é um inteiro– operador [ ]:

● estoque[“caneta”] = 21;● int quantidade = estoque[“caneta”];

Page 10: Estrutura de dados

Alocação de elementos● Aspectos de implementação a considerar:

– Como os dados são mantidos em memória?– Como um valor é localizado em uma coleção?

● Ambas as perguntas estão relacionadas à forma como os elementos são alocados.– Alocação contígua

● Elementos ocupam espaço contíguo (contínuo).● Só é preciso guardar o endereço inicial.

– Alocação não-contígua● Cada elemento ocupa um espaço em regiões distintas de

memória.● É preciso informação extra para localizar elementos.

Page 11: Estrutura de dados

Alocação contígua de elementos● Linguagens de programação suportam

agregados contíguos e uniformes: arranjos.– Todos os elementos são de um mesmo tipo.

● Usos em C++:– Arranjos são definidos e acessados pelo

operador de indexação [ ].● int elemento [49];● elemento [0] = 127;

– Nome do arranjo é ponteiro (endereço) para início da área de seus dados.

● O nome “elemento” equivale a “ *elemento[0] ”.● elemento[i] equivale a *(elemento + i).

Page 12: Estrutura de dados

Strings em C++● Strings são arranjos de caracteres e são muito

utilizados em qualquer linguagem, apesar de nem sempre terem um bom suporte da mesma.

● Em C++, se o arquivo de cabeçalho string for incluído no programa, é possível criar strings como se fossem tipos de dados primitivos.– #include <string>– string nao_tenho_nada;– string alerta(“Salve-se quem puder!”);– string atencao(alerta);– string mensagem = “Dê o seu recado!!!”;

Page 13: Estrutura de dados

Obtenção de elementos de arranjos● Se dá pela aplicação de métodos específicos.● Métodos são como funções, mas aplicadas a objetos.● Aplicação se dá com o operador “.” (ponto) entre os

nomes do objeto e do método.● Ex: int altura = pessoa.size( );

● Obtenção de um elemento: – método at : char sexta_letra = pessoa.at(5);– sobrecarga do operador [ ]:

char sexta_letra = pessoa[5] ● Sobrecarregar um operador da linguagem C++ é associar um

novo comportamento ao mesmo.

Page 14: Estrutura de dados

Alocação não-contígua de elementos

● Espaço para cada elemento é requisitado independentemente.

● Não é preciso reservar com antecedência toda a área de memória que se deseja utilizar.

● Alocação dinâmica: permite obter a quantidade de memória necessária para cada novo elemento.– Em C++ : método new

● Área não mais usada deve ser liberada:– Em C++: método delete

Page 15: Estrutura de dados

Listas ligadas● Estruturas de armazenamento não-contíguo.● Trata-se de uma seqüência de elementos (nós)

espalhados pela memória, mas conectados logicamente de alguma forma.

● Pontos de acesso:– cabeça (ou topo) da lista:

● indica o primeiro elemento● é mantida à parte em um nó chamado descritor da lista

– cauda (ou fim) da lista: indica o último elemento e pode não estar presente

● Além dos dados, cada nó armazena também o endereço de seu sucessor (next).

● campo next do último elemento contém um ponteiro nulo.

Page 16: Estrutura de dados

Tipos básicos de listas● Lista simplesmente ligada (ou encadeada)

– Cada nó tem indicação de seu sucessor, mas não de seu antecessor.

– Varredura dos nós só pode ser feita da cabeça para a cauda da lista.

● Lista duplamente ligada (ou encadeada)– Cada nó tem indicação de seu sucessor (next) e de

seu antecessor (prev).– É possível varrer a lista nos dois sentidos: cabeça

para cauda e cauda para cabeça.

Page 17: Estrutura de dados

Operações básicas em listas– Criação de um nó: CREATE_NODE(dado)– Remoção de um nó: DELETE_NODE(nó)

● Remoção do primeiro nó: REMOVE_FIRST(lista)● Remoção do último nó: REMOVE_LAST(lista)

– Ligação de um nó a outro: LINK_NODE(nó1, nó2)– Verificação de lista vazia: IS_EMPTY(lista)– Inserção de nó na cabeça: INSERT(lista, nó)– Inserção de nó na cauda: APPEND(lista, nó)– Busca de um nó específico: FIND(lista, chave)

Page 18: Estrutura de dados

Filas (queues)● Estruturas implementadas normalmente via

arranjos ou listas.– Elementos podem ou não ser contíguos em memória.

● Política FIFO (first in, first out) de acesso aos dados

● Pares de operações possíveis:● INSERT(lista, nó) e REMOVE_LAST(lista) ou● APPEND(lista, nó) e REMOVE_FIRST(lista)

Page 19: Estrutura de dados

Pilhas (stacks)● Estruturas que podem ser implementadas via

arranjos ou listas.– Normalmente elementos são contíguos em

memória devido ao melhor desempenho.● Política LIFO (last in, first out) de acesso aos

dados.● Operações possíveis:

– PUSH: inserção no topo da pilha– POP: remoção do topo da pilha– estas operações podem ser implementadas pelas

operações básicas de listas INSERT(lista, nó) e REMOVE_FIRST(lista)

Page 20: Estrutura de dados

Árvores● Estruturas muito usadas na programação de

sistemas.● Tratam-se de listas, nas quais os nós podem

ter mais de um sucessor e no máximo um antecessor.

● Formalmente: conjunto de um ou mais nós divididos em um nó raiz (sem antecessor) e zero ou mais conjuntos disjuntos de nós que também são (sub)árvores.

Page 21: Estrutura de dados

Árvores: definições úteis● Nó antecessor : nó pai● Nó sucessor : nó filho● Nó sem antecessor: nó raiz● Nós sem sucessores (grau zero): nós folhas● Número de sucessores de um nó: grau do nó● Maior dos graus de nó = grau da árvore

Page 22: Estrutura de dados

Árvore binária● Árvore no qual cada nó tem no máximo dois

filhos (sub-árvores da esquerda e da direita).

Árvores binárias balanceadas

Número de níveis mínimo = log2n + 1

Page 23: Estrutura de dados

Árvores binárias: varredura● Pré-ordem

– raiz, sub-árvore da esquerda e pré-ordem, sub-árvore da direita em pré-ordem

● Intra-ordem– sub-árvores da esquerda, raiz, sub-árvore da direita

em intraordem● Pós-ordem

– sub-árvore da esquerda (em pós-ordem), sub-árvore da direita (em pós-ordem), raiz

Page 24: Estrutura de dados

Tabelas● Estrutura de dados muito utilizada

– Ex: tabelas de processos em sistemas operacionais, tabelas de relacionamento em bancos de dados.

● Dados armazenados são obtidos com o fornecimento de uma ou mais chaves de busca.– Ex: GET_VALUE(tabela, chave)

● Remoção de dados também exige chave(s).– Ex: REMOVE(tabela, chave)

● Inserção requer também dado a ser inserido.– Ex: INSERT(tabela, chave, dado)

Page 25: Estrutura de dados

Tabelas: implementação● Exemplo de implementação em C

#define TAM_TABELA 1560typedef struct {

unsigned int chave;char nome[40];

} entrada;typedef struct {

int n;endrada elem[TAM_TABELA];

} Tabela;Tabela cadastro;

Page 26: Estrutura de dados

Busca de dados: busca linear● Não exige dados ordenados● Varre os dados (chaves) um a um até encontrar

aquele desejado● Pode ser preciso varrer todas as entradas● Complexidade do algoritmo: O(n)

Page 27: Estrutura de dados

Busca de dados: busca binária● Exige que dados estejam ordenados● Divide espaço de busca em duas partes;

compara entrada na fronteira com dado procurado e decide em que parte continuar a busca.

● Complexidade: O(log2n) + complexidade da

ordenação

Page 28: Estrutura de dados

Tabela Hash● Estrutura de dados na qual as buscas se dão a

partir de uma chave baseada em função hash.– Função hash: mapeia um símbolo ou uma string de

símbolos de tamanho arbitrário em um valor inteiro.● Vantagem: ótimo desempenho na busca:

– busca linear: complexidade de O(n)– busca binária: complexidade de O(log

2 n)

– busca por tabela hash: complexidade de O(1) (se não houver colisões) a O (n) (se houver muitas colisões)

Page 29: Estrutura de dados

Funções Hash: colisão● Ocorre quando dois ou mais valores de entrada

resultam no mesmo hash.● Entradas com colisão são consideradas

sinônimas.– Sinônimos podem ser organizados em listas

ligadas contíguas ou não em memória.● Uma boa função hash deve resultar em um

número mínimo (nulo) de colisões.

Page 30: Estrutura de dados

Exemplos de tabela hash● F(x) = x mod 10

0 => 10, 0, 120, 501 => 71, 21, 1, 112 => 52, 912, 2, 32...9 => 109, 19, 89, 9

● F(x) = primeira letra de x

a => antonio, anab => bruno, brasilc => carla, coimbra...z => zéfiro, zé,

● Os 2 exemplos têm colisões: os sinônimos são organizados em uma lista ligada e varridos seqüencialmente até se encontrar o dado desejado; complexidade pode atingir O(n).

Page 31: Estrutura de dados

Exemplos de funções hash● Meio do quadrado:

– chave é interpretada como número e elevada ao quadrado; os r bits do meio do resultado são usados como endereço de uma tabela (hash) de 2r posições.

● Resto da divisão:– o valor de hash a ser buscado na tabela é o resto

da divisão do valor da chave por um número primo M (números primos reduzem as chances de colisão).

Page 32: Estrutura de dados

Ordenação● Função tão básica e essencial que os

computadores são conhecidos como “ordenadores” na Espanha e França.

● É indispensável para certos tipos de busca e de organização de dados.

● Existe uma grande variedade de algoritmos de ordenação com diferentes graus de complexidade e eficiência.

Page 33: Estrutura de dados

Principais algoritmos de ordenação● Por maior (ou menor) valor● Bubble Sort● Quick Sort● Heap Sort● Radix Sort● Estes e outros tipos estão ilustrados por meio

de animações no material extra disponível na página da disciplina.

Page 34: Estrutura de dados

Ordenação por maior valor

● Procurar nos dados o de maior valor e fazer a permuta dele com aquele na última posição (N-1).

● Repetir a operação para o segundo maior valor e fazer a permuta dele com aquele na penúltima posição (N-2).

● Repetir a operação anterior para os demais dados até que não haja mais nenhum a permutar.

Page 35: Estrutura de dados

Bubble Sort● Escolher um par de dados e permutá-los se

estiverem fora de ordem.● Repetir a operação anterior até que todos os

pares possíveis tenham sido considerados.● Ex: // Bubble Sortint bubble(int vetor[], int n){int i,j;for(i=0;i<n;i++){

for(j=1;j<(n-i);j++){if(vetor[j-1]>vetor[j])

SWAP(vetor[j-1], vetor[j]);} } }

Page 36: Estrutura de dados

Quick Sort● Trabalha em duas fases: divisão e ordenação.● Exemplo da estratégia “dividir para conquistar”:

– divide os dados em dois subconjuntos menores e aplica em cada um o algoritmo novamente;

– divisão deve garantir que todos os elementos em uma parte não são inferiores a todos os demais da outra parte;

– não há preocupação inicial com a ordenação dentro de cada parte, mas sim que uma parte seja 100% menor que a outra.

Page 37: Estrutura de dados

Quick Sort: exemplo// Exemplo de Quick Sortint quicksort(int *vetor, int inf, int sup){int pivot;if(sup > inf){

pivot = dividir(vetor, inf, sup);quicksort(vetor, inf, pivot-1);quicksort(vetor, pivot+1, sup);

}}Etapa dividir:● escolher um elemento qualquer do vetor como pivot;● varrer todos os elementos entre os índices inf e sup e os

colocar os colocar à esquerda ou direita do pivot.