You are on page 1of 37

Estruturas de Dados

EA 876
Prof. Marco Aurlio A. Henriques
DCA/FEEC/UNICAMP
2007

O que so estruturas de dados?

So mecanismos de organizao das informaes


visando um processamento eficiente das mesmas.
Tipos de dados:

bsicos: normalmente dependentes da arquitetura de


hardware; no podem ser alterados (redefinidos) por
programas; so a base para outros tipos de dados.

Ex. (em C): int, float, double, char .

abstratos: formados por uma combinao entre tipos


bsicos iguais ou diferentes; so criados (definidos) por
programas.

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


estruturas; arranjos de estruturas (tabelas).

Estruturas de dados lineares

Manuteno da estrutura independente do


contedo.

Estrutura se baseia apenas na posio dos itens.

Manipulao do contedo tarefa da aplicao.

Ex. de estruturas lineares suportadas por C++:

vector
deque
list

Estruturas de dados associativas

Manuteno da estrutura depende do contedo


(total ou parcial) dos itens.

Contedo parcial dos itens chamado de chave.

Acesso aos elementos possvel independentemente


da posio.

Ex. de estruturas associativas suportadas por C++:

conjuntos
mapas

Muito utilizadas na construo de tabelas.

Estruturas lineares: vector

Arranjo com capacidade de armazenamento


dinmica.

Se o espao reservado se esgotar, um outro ser


reservado automaticamente.

Estrutura simples e de baixa sobrecarga no


armazenamento de dados em memria.

Usos em C++:

inserir arquivo de cabealho: #include <vector>


caso seja um vetor de strings, inserir arquivo de
cabealho: #include <string>
criao da estrutura: vector < string > minha_lista
insero de elementos: inserte ou push_back
remoo de elementos: erase ou pop_back
acesso a elementos: operador [ ]

Estruturas lineares: deque

deque = double ended queue


Similar ao vector, mas mantm informaes da
posio de ambas extremidades.
Tambm no eficiente inserir ou remover
dados intermedirios.
Em C++:

inserir arquivo de cabealho: #include <deque>

criar instncia: deque <int> fila;

mtodos extras: push_front e pop_front

Estruturas lineares: list

Implementao de uma lista duplamente


encadeada.

Elementos no esto contguos na memria: cada um


precisa guardar informaes sobre seu antecessor e
sucessor na lista.

Inseres e remoes de elementos intermedirios so


mais eficientes que em deque ou vector.

Acesso direto a elementos no interior da lista no


eficiente: operador [ ] no est disponvel.

Usos em C++:

#include <list>;
#include <string>;
list <string> alunos;

Estruturas associativas: sets

Elementos ordenados pelo seus valores.

No 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 mtodos: set_union, set _intersection

Estruturas associativas: maps

Elementos organizados na forma (chave, valor).

Acesso a valor possvel 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];

Alocao de elementos

Aspectos de implementao a considerar:

Como os dados so mantidos em memria?

Como um valor localizado em uma coleo?

Ambas as perguntas esto relacionadas


forma como os elementos so alocados.

Alocao contgua

Elementos ocupam espao contguo (contnuo).


S preciso guardar o endereo inicial.

Alocao no-contgua

Cada elemento ocupa um espao em regies distintas de


memria.
preciso informao extra para localizar elementos.

Alocao contgua de elementos

Linguagens de programao suportam


agregados contguos e uniformes: arranjos.

Todos os elementos so de um mesmo tipo.

Usos em C++:

Arranjos so definidos e acessados pelo


operador de indexao [ ].

int elemento [49];


elemento [0] = 127;

Nome do arranjo ponteiro (endereo) para incio


da rea de seus dados.

O nome elemento equivale a *elemento[0] .

elemento[i] equivale a *(elemento + i).

Strings em C++

Strings so arranjos de caracteres e so muito


utilizados em qualquer linguagem, apesar de
nem sempre terem um bom suporte da mesma.
Em C++, se o arquivo de cabealho string for
includo no programa, possvel 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!!!;

Obteno de elementos de arranjos

Se d pela aplicao de mtodos especficos.

Mtodos so como funes, mas aplicadas a objetos.

Aplicao se d com o operador . (ponto) entre os


nomes do objeto e do mtodo.

Ex:

Obteno de um elemento:

int altura = pessoa.size( );

mtodo 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.

Alocao no-contgua de elementos

Espao para cada elemento requisitado


independentemente.
No preciso reservar com antecedncia toda
a rea de memria que se deseja utilizar.
Alocao dinmica: permite obter a quantidade
de memria necessria para cada novo
elemento.

Em C++ : mtodo new

rea no mais usada deve ser liberada:

Em C++: mtodo delete

Listas ligadas

Estruturas de armazenamento no-contguo.


Trata-se de uma seqncia de elementos (ns)
espalhados pela memria, mas conectados logicamente
de alguma forma.
Pontos de acesso:

cabea (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 no estar presente

Alm dos dados, cada n armazena tambm o


endereo de seu sucessor (next).

campo next do ltimo elemento contm um ponteiro nulo.

Tipos bsicos de listas

Lista simplesmente ligada (ou encadeada)

Cada n tem indicao de seu sucessor, mas no


de seu antecessor.

Varredura dos ns s pode ser feita da cabea


para a cauda da lista.

Lista duplamente ligada (ou encadeada)

Cada n tem indicao de seu sucessor (next) e de


seu antecessor (prev).

possvel varrer a lista nos dois sentidos: cabea


para cauda e cauda para cabea.

Operaes bsicas em listas

Criao de um n: CREATE_NODE(dado)

Remoo de um n: DELETE_NODE(n)

Remoo do primeiro n: REMOVE_FIRST(lista)


Remoo do ltimo n: REMOVE_LAST(lista)

Ligao de um n a outro: LINK_NODE(n1, n2)

Verificao de lista vazia: IS_EMPTY(lista)

Insero de n na cabea: INSERT(lista, n)

Insero de n na cauda: APPEND(lista, n)

Busca de um n especfico: FIND(lista, chave)

Filas (queues)

Estruturas implementadas normalmente via


arranjos ou listas.

Elementos podem ou no ser contguos em memria.

Poltica FIFO (first in, first out) de acesso aos


dados
Pares de operaes possveis:

INSERT(lista, n) e REMOVE_LAST(lista) ou
APPEND(lista, n) e REMOVE_FIRST(lista)

Pilhas (stacks)

Estruturas que podem ser implementadas via


arranjos ou listas.

Normalmente elementos so contguos em


memria devido ao melhor desempenho.

Poltica LIFO (last in, first out) de acesso aos


dados.
Operaes possveis:

PUSH: insero no topo da pilha

POP: remoo do topo da pilha

estas operaes podem ser implementadas pelas


operaes bsicas de listas INSERT(lista, n) e
REMOVE_FIRST(lista)

rvores

Estruturas muito usadas na programao de


sistemas.
Tratam-se de listas, nas quais os ns podem
ter mais de um sucessor e no mximo um
antecessor.
Formalmente: conjunto de um ou mais ns
divididos em um n raiz (sem antecessor) e
zero ou mais conjuntos disjuntos de ns que
tambm so (sub)rvores.

rvores: definies teis

N antecessor : n pai

N sucessor : n filho

N sem antecessor: n raiz

Ns sem sucessores (grau zero): ns folhas

Nmero de sucessores de um n: grau do n

Maior dos graus de n = grau da rvore

rvore binria

rvore no qual cada n tem no mximo dois


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

rvores binrias balanceadas


Nmero de nveis mnimo = log2n + 1

rvores binrias: varredura

Pr-ordem

Intra-ordem

raiz, sub-rvore da esquerda e pr-ordem, subrvore da direita em pr-ordem


sub-rvores da esquerda, raiz, sub-rvore da direita
em intraordem

Ps-ordem

sub-rvore da esquerda (em ps-ordem), subrvore da direita (em ps-ordem), raiz

Tabelas

Estrutura de dados muito utilizada

Dados armazenados so obtidos com o


fornecimento de uma ou mais chaves de busca.

Ex: GET_VALUE(tabela, chave)

Remoo de dados tambm exige chave(s).

Ex: tabelas de processos em sistemas


operacionais, tabelas de relacionamento em
bancos de dados.

Ex: REMOVE(tabela, chave)

Insero requer tambm dado a ser inserido.

Ex: INSERT(tabela, chave, dado)

Tabelas: implementao

Exemplo de implementao em C
#define TAM_TABELA 1560
typedef struct {
unsigned int chave;
char nome[40];
} entrada;
typedef struct {
int n;
endrada elem[TAM_TABELA];
} Tabela;
Tabela cadastro;

Busca de dados: busca linear

No 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)

Busca de dados: busca binria

Exige que dados estejam ordenados


Divide espao 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
ordenao

Tabela Hash

Estrutura de dados na qual as buscas se do a


partir de uma chave baseada em funo hash.

Funo hash: mapeia um smbolo ou uma string de


smbolos de tamanho arbitrrio em um valor inteiro.

Vantagem: timo desempenho na busca:

busca linear: complexidade de O(n)

busca binria: complexidade de O(log2 n)

busca por tabela hash: complexidade de O(1) (se


no houver colises) a O (n) (se houver muitas
colises)

Funes Hash: coliso

Ocorre quando dois ou mais valores de entrada


resultam no mesmo hash.
Entradas com coliso so consideradas
sinnimas.

Sinnimos podem ser organizados em listas


ligadas contguas ou no em memria.

Uma boa funo hash deve resultar em um


nmero mnimo (nulo) de colises.

Exemplos de tabela hash

F(x) = x mod 10
0 => 10, 0, 120, 50
1 => 71, 21, 1, 11
2 => 52, 912, 2, 32
...
9 => 109, 19, 89, 9

F(x) = primeira letra de x


a => antonio, ana
b => bruno, brasil
c => carla, coimbra
...
z => zfiro, z,

Os 2 exemplos tm colises: os sinnimos so


organizados em uma lista ligada e varridos
seqencialmente at se encontrar o dado
desejado; complexidade pode atingir O(n).

Exemplos de funes hash

Meio do quadrado:

chave interpretada como nmero e elevada ao


quadrado; os r bits do meio do resultado so
usados como endereo de uma tabela (hash) de 2r
posies.

Resto da diviso:

o valor de hash a ser buscado na tabela o resto


da diviso do valor da chave por um nmero primo
M (nmeros primos reduzem as chances de
coliso).

Ordenao

Funo to bsica e essencial que os


computadores so conhecidos como
ordenadores na Espanha e Frana.
indispensvel para certos tipos de busca e de
organizao de dados.
Existe uma grande variedade de algoritmos de
ordenao com diferentes graus de
complexidade e eficincia.

Principais algoritmos de ordenao

Por maior (ou menor) valor

Bubble Sort

Quick Sort

Heap Sort

Radix Sort

Estes e outros tipos esto ilustrados por meio


de animaes no material extra disponvel na
pgina da disciplina.

Ordenao por maior valor

Procurar nos dados o de maior valor e fazer a


permuta dele com aquele na ltima posio (N-1).
Repetir a operao para o segundo maior valor e
fazer a permuta dele com aquele na penltima
posio (N-2).
Repetir a operao anterior para os demais dados
at que no haja mais nenhum a permutar.

Bubble Sort

Escolher um par de dados e permut-los se


estiverem fora de ordem.
Repetir a operao anterior at que todos os
pares possveis tenham sido considerados.
Ex: // Bubble Sort

int 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]);
} } }

Quick Sort

Trabalha em duas fases: diviso e ordenao.

Exemplo da estratgia dividir para conquistar:

divide os dados em dois subconjuntos menores e


aplica em cada um o algoritmo novamente;

diviso deve garantir que todos os elementos em


uma parte no so inferiores a todos os demais da
outra parte;

no h preocupao inicial com a ordenao dentro


de cada parte, mas sim que uma parte seja 100%
menor que a outra.

Quick Sort: exemplo


// Exemplo de Quick Sort
int 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.