APOSTILA
ESTRUTURA
DE DADOS
MANAUS 2013
ABSTRAO DE DADOS
Um processo qualquer seqncia finita e ordenada de passos que visa promover
transformaes definidas sobre uma determinada matria-prima. Se denominamos entrada a
matria-prima no seu estado inicial; e sada o que se obtm aps as transformaes
realizadas pelo processo, temos o esquema geral a seguir:
ENTRADA
SADA
PROCESSAMENTO
(Estado Inicial)
(Estado Final)
Entrada/sada de um processo
Matria-prima abstrata: processamento de dados.
Abstrata: apresenta-se sob a forma de valores.
Processamento realizado pelo computador:
Entrada: dados colhidos do mundo real externo ao computador;
Processo: srie finita de operaes que so realizadas a partir desses dados;
Sada: transformao sofrida pelos dados atravs de um processo.
DADOS
CONHECIMENTO
INFORMAO
processamento de dados
Exemplo:
Raio R de uma
circunferncia
P=2..R
Permetro P da
circunferncia
TAD (Modelo
Matemtico)
IMPLEMENTAO
TCD (Padro
bits, Rotinas)
LISTAS LINEARES
uma estrutura que armazena elementos de forma alinhada, ou seja, com elementos
dispostos um aps o outro, como em uma lista de nomes, peas, valores, pessoas, compras,
etc.
FUNDAMENTOS
Uma Lista Linear, uma coleo L: [a1, a2, ..., an], n>=0, cuja propriedade estrutural baseiase apenas na posio relativa dos elementos, que so dispostos linearmente. Se n=0,
dizemos que a lista L vazia; caso contrrio, so vlidas as seguintes propriedades:
a1 o primeiro elemento de L;
an o ltimo elemento de L;
ak, a<k<n, precedido pelo elemento ak-1 e seguido por ak+1 em L.
a1
a2
a3
...
an
ESTRUTURA DE DADOS PGINA 4
Uma lista com um array, pode ser implementada como uma seqncia de records com
elementos disponveis:
de forma consecutiva - Lista Esttica Seqencial;
de forma no consecutiva - Lista Esttica Encadeada;
Uma lista pode ser ordenada ou no. Pascal permite construir EDs avanadas - Lista
Dinmicas; mais versteis, utilizando ponteiros e variveis dinmicas.
Considerando apenas operaes de acesso, insero e remoo restritas aos extremos das
listas, temos casos especiais:
Pilha: insero, remoo, acesso realizados em um nico extremo. Lista LIFO.
Fila: insero num extremo e remoo, acesso no outro extremo. Lista FIFO.
ALOCAO DE MEMRIA
Para implementar uma lista linear: como podemos armazenar os elementos da lista dentro do
computador? Alocar rea de memria responsabilidade do programador e estar em uma
das quatro categorias abaixo:
ESTTICA
DINMICA
SEQENCIAL
Esttica Seqencial
Dinmica Seqencial
ENCADEADA
Esttica Encadeada
Dinmica Encadeada
ALOCAO ESTTICA
X ALOCAO DINMICA
ALOCAO ESTTICA:
Quantidade total de memria utilizada pelos dados previamente conhecida e definida de
modo imutvel, no prprio cdigo-fonte do programa. Durante o programa no varia a
quantidade de memria.
ALOCAO DINMICA:
Programa cria novas variveis enquanto executa, ou seja, reas de memrias no declaradas
no programa passam a existir durante a execuo.
ESTTICA
DINMICA
1FFAh
P:
1FFAh
12345
Memria livre no sistema
elemento
Clula
Dados;
Endereos.
Destaque:
Endereo do primeiro elemento da lista L;
Endereo do elemento fictcio que segue o ltimo elemento da lista (NULO, TERRA,
3FAAh
A1
1C34h
1C34h
A2
1725h
1725h
A3
a1
1
a2
2
an
n
Desvantagem:
movimentao quando eliminado/inserido elemento
tamanho mximo pr-estimado
Quando usar:
listas pequenas
insero/remoo no fim da lista
tamanho mximo bem definido
Begin
i:=1;
for j:=i to L.n-1 do
L.A[j]:=L.A[j+1];
L.n:=L.n-1;
End;
i := 1;
While (L[i].chave <> x) do
i := i+1;
{checa se encontrado o sentinela}
If (i = Nelem + 1)
Then
busca := 0
Else
busca := i;
End;
2) LISTAS SEQUENCIAIS ORDENADAS
No caso de listas ordenadas, deve-se aproveitar o fato de que nem sempre necessrio
percorrer a lista toda para concluirmos que elemento no est na lista.
A verso do algoritmo de busca com sentinela para listas ordenadas :
Function busca_ord(x)
Var
i: 1..Max;
Begin
L[Nelem+1] .chave := x; {insere elemento sentinela}
i := 1;
While (L[i].chave < x) do {compara-se apenas os menores}
i := i+1;
If (i = Nelem + 1) or i(L[i].chave <> x)
Then
busca := 0
Else
busca := i;
End;
O fato de se utilizar o recurso da sentinela na busca seqencial, acima, elimina a necessidade
de testar, para cada elemento, se o final da lista alcanado ou no.
No caso de listas ordenadas, pode-se apresentar um algoritmo BEM mais eficiente o qual
tira MUITO MAIS proveito do fato da lista estar ordenada!
O algoritmo de busca binria tem como idia bsica o fato de que, dada uma posio dentro
da lista, o elemento procurado vai estar ou antes ou depois desta posio, e, portanto, no se
precisa procurar dos dois lados.
Numa dada lista ordenada:
Compara-se o elemento procurado com o registro do meio da lista, para saber se o
elemento estaria na metade superior ou inferior da lista.
Repete-se esse processo at encontrar o elemento ou esgotar a lista.
Function busca_bin(x)
Var
inf, sup, meio: ndices;
Begin
inf := 1;
sup := n;
busca_bin := 0;
While inf <= sup do
Begin
meio := [(inf + sup) div
If L[meio].chave = x
then
Begin
busca_bin :=
inf := sup +
End
Else If (L[meio].chave
Then
inf := meio
Else
sup := meio
2];
meio;
1;
< x)
+ 1
-1;
End;
End;
CRIAO DE BIBLIOTECAS
UNITS EM TURBO PASCAL
Uma Unit uma coleo de constantes, tipos de dados, variveis, procedimentos e funes.
Cada Unit como um programa Pascal separado. Ela uma biblioteca de declaraes que
permite dividir seu programa e compil-lo em partes separadas. Ela pode ter um corpo
principal o qual chamado antes do seu programa ser iniciado para preparar as
"inicializaes" necessrias.
Todas as declaraes em uma Unit esto normalmente relacionadas. Por exemplo, a unit CRT
contm todas as declaraes de rotinas relativas SCREEN do PC. O Turbo Pascal possui 8
Units pr-definidas: System, Overlay, Graph, Dos, Crt, Printer...
ESTRUTURA DE UMA UNIT
UNIT <identificador>; {arquivo deve ter mesmo nome.PAS}
INTERFACE
uses <lista de units> {opcional}
<declaraes pblicas> {s cabealho}
IMPLEMENTATION
uses <lista de units> {opcional}
<declaraes privadas>
<implementao de proc. e funes>
{corpo das funes e proc.}
Begin
<inicializaes>
End.
{ou}
End.
ESTRUTURA DE DADOS PGINA 12
{L.A[p].info
elemento}
ltimo
End;
Ultimo := L.A[p].info;
End;
3) Quantos elementos tem a lista ?
Function No_elementos(L: Lista): integer;
Var
Nelem: integer;
p: endereco;
Begin
If L.Prim = 0
Then
Nelem := 0 {lista vazia}
Else
Begin
p := L.Prim;
Nelem := 1;
While L.A[p].lig <> 0 do
Begin
Nelem := Nelem + 1; {Nelem contm o Nmero
de elementos}
p := L.A[p].lig;
End;
End;
No_elementos := Nelem;
End;
ESTRUTURA DE DADOS PGINA 15
LISTA DINMICA LD
As linguagens de programao modernas tornaram possvel explicitar no apenas o acesso
aos dados, mas tambm aos endereos desses dados.
Isso significa que ficou possvel a utilizao de ponteiros explicitamente implicando que uma
distino notacional deve existir entre os dados e as referncias (endereos) desses dados.
A notao introduzida por Wirth, com a introduo de Pascal, : Type Tp = ^T. Essa
declarao expressa que valores do tipo Tp so ponteiros para dados do tipo T. Portanto,
lemos o smbolo ^ como sendo ponteiro para... e na declarao acima lemos Tp um ponteiro
para variveis do tipo T.
O fato de que o tipo dos elementos apontados ser evidente na declarao do ponteiro tem
importncia fundamental. Isso distingue ponteiros de linguagens de alto nvel de endereos
em Assembly.
Valores para ponteiros so gerados quando dados correspondentes a seus tipos so
alocados/deslocados dinamicamente. Em Pascal, os procedimentos new e dispose existem
com esse propsito.
Portanto, deixa-se a cargo do programa (via linguagem de programao), e no do
programador, prover e devolver espao para inseres e eliminaes em tempo de execuo.
Nesse caso, tipo_apontado qualquer tipo, simples ou definido pelo usurio, do Pascal. Ou
seja, no posso fazer:
VAR ptr : ^ARRAY[1..10] OF integer;
O que temos aqui? Apenas uma varivel, chamada ptr, que um ponteiro para um inteiro, ou
seja, ela guarda um endereo de memria onde pode ser armazenado um inteiro. Mas de qual
pedao ela tem o endereo? Nenhum. Para efetivamente dar um valor a ptr temos que fazer:
new(ptr);
O que, ento, isso faz? Esse comando simplesmente diz ao sistema operacional para que este separe
um pedao de memria em que caiba um inteiro (o tipo apontado por ptr), guardando o endereo deste
pedao em ptr. E qual esse endereo? No sabemos, e nem precisamos saber, pois o Pascal abstrai
tudo isso. Ou seja, podemos agora usar a varivel ptr quase como se fosse um integer comum. Por
que quase? Veja abaixo:
VAR ptr : ^integer;
BEGIN
new(ptr); {separei um pedao de memria para um
inteiro}
ptr^ := 2; {coloquei o valor 2 nesse pedao de
memria}
ptr^ := ptr^ * 3; {fao esse pedao de memoria
receber o triplo
do que l havia}
END.
Viu como fizemos? "ptr^" pode ser usada como qualquer varivel integer. Veja agora o programa
abaixo:
type
tipo=^integer;
VAR
p1 : tipo;
p2 : tipo;
BEGIN
clrscr;
new(p1); {reservei um pedao de memoria para um inteiro,
fazendo p1 apontar para ele}
p2 := p1; {fiz p2 apontar para o mesmo pedao de memoria
que p1 aponta}
p1^ := 4; {coloquei o valor 4 nesse pedao de memoria}
writeln(p2^); {escrevi o valor que est no pedao de
memria apontado por p2, ou seja, 4, pois
p2 aponta para o mesmo pedao de memria
que p1}
p2^ := p2^ + 3; {adicionei 3 ao valor que havia no pedao
de memria apontado por p2 e armazenei
novamente nesse pedao o resultado}
writeln(p1^); {escrevo o contedo da memria apontada por
p1, ou seja, 7, pois p1 aponta para o mesmo
pedao de memria que p2 aponta}
readkey;
END.
Ao fazer p2 := p1 (note que no p2^ := p1^), guardamos uma cpia do endereo que
estava em p1 em p2. Ou seja, fazemos p2 apontar para a mesma regio de memria
que p1 apontava:
Ao lermos p2^ no write, simplesmente lemos o valor que est na regio da memria
apontada por p2, ou seja, 4.
Ao lermos p1^ no write, novamente lemos o valor que est na regio de memria
apontada por p1, ou seja, 7, j que esta a mesma regio que apontada por p2 e que
foi modificada no passo anterior.
estamos copiando o contedo da regio de memria apontada por p1 para a regio de memria apontada
por p2. J se fizermos
p2 := p1;
estaremos fazendo p2 apontar para a mesma regio de memria apontada por p1. Agora que sabemos
como carregar valores com ponteiros, como fazemos para "zerar" um ponteiro? Ou seja, para dizer que
ele no aponta para lugar nenhum?
p1 := NIL;
Se no fizermos isso, ele conter um endereo de memria que pode j ter sido liberada pelo programa,
ou que pode no pertencer ao programa, o que geraria um erro quando da execuo.
E, por falar em liberar memria, como fazemos se quisermos liberar a memria que reservamos com
new?
Dispose(varivel_de_ponteiro);
ou seja
Dispose(p1);
Dispose avisa ao sistema operacional que no vamos mais precisar desse pedao de memria, liberando
esta. SEMPRE libere a memria que no vai mais usar para no esgotar os recursos da mquina.
Cuidado com o seguinte erro:
type
tipo=^integer;
VAR p1 : tipo;
p2 : tipo;
BEGIN
new(p1);
p2 := p1;
p1^ := 4;
Dispose(p2);
writeln(p1^)
END.
isso pode gerar um erro, pois j liberei a memria apontada por p2, que a mesma apontada por p1
Vale tambm lembrar que, ao final do programa, se voc no liberou a memria usada, o computador a
libera para voc. Ainda assim uma boa prtica limpar seu lixo.
E se agora quisermos um ponteiro para um tipo mais complexo, como registro?
TYPE
Tipo1=real;
Tipo2=integer;
Reg = RECORD
cp1 : tipo1;
cp2 : tipo2;
cp3 : ARRAY[1..10] of char
END;
VAR p : ^reg;
BEGIN
New(p);
END.
->
->
Agora que j vimos o que so ponteiros, vamos aprender, na prxima seo, a us-los.
assim fica fcil no? Mas como fazer isso em Pascal? Usando ponteiros. Como? Com uma
lista encadeada. O que, ento, uma lsita encadeada?
Uma lista encadeada uma lista onde cada elemento - chamado de n - contm um valor e
um ponteiro para o elemento seguinte. Assim, sabendo onde est o primeiro elemento da lista,
podemos chegar a qualquer outro elemento. H vrios tipos de listas encadeadas:
Simples:
O sinal de aterramento significa que este ponteiro NIL, ou seja, no aponta para lugar
nenhum.
Circular:
Duplamente encadeada:
e muitas outras mais. O limitante apenas sua imaginao. Aqui iremos usar somente listas
simples. Mas e qual as vantagens e desvantagens de cada uma? Listas duplamente
encadeadas so fceis de se percorrer, mas ocupam mais espao na memria. Note que
nessas eu posso, a partir de um elemento, voltar na lista, percorr-la de trs para frente, pois
tenho ponteiros que medizem onde esto o prximo elemento e o anterior.
As circulares simples so fceis de percorrer e no ocupam muita memria. Mas se o nmero
de elementos for grande, vai se comportar quase como uma lista simples. Qual lista a
melhor? Depende do problema a ser resolvido.,p> Agora vamos definir operaes bsicas em
listas:
Esvaziamento da lista
etc
Vamos ver ento como criar uma lista encadeada. Nos exemplos que seguem estaremos
usando a lista encadeada simples, conforme foi apresentada acima.
Antes de mais nada, vamos definir nossa lista:
TYPE tipo = real;
p_no = ^no;
no
= RECORD
valor : tipo;
prox : p_no
END;
Pronto! O que fizemos com isso? Dissemos que a lista est vazia ao darmos um valor "nada"
cabea desta. Se no fizermos isso, a cabea pode conter lixo indesejvel.
Agora vamos incluir um elemento na lista. A questo : onde? Voc decide. Pode ser no
incio, pode ser no meio (caso voc queira ordenar a lista enquanto a constri) e pode ser no
fim. Nesse caso, vamos por no fim. Ento, como faremos?
Suponha que temos a seguinte lista:
Fazemos o prximo elemento de p (que agora aponta para o fim da lista) ser q, ou seja,
fazemos q ser o novo fim da lista
Vamos agora excluir um elemento da lista. Novamente, qual? Voc escolhe! Vamos tomar
como poltica a excluso do primeiro elemento da lista. Como faremos isso?
Suponha a lista:
E o procedimento fica:
PROCEDURE Exclui(VAR cabeca : p_no; VAR
valor:tipo);
VAR p : p_no; {auxiliar}
BEGIN
IF cabeca <> NIL THEN
BEGIN
{a lista no est vazia}
p := cabeca;
{fao a cabea apontar para o prximo}
cabeca := cabeca^.prox;
{retorno o valor que est em p}
valor := p^.valor;
{mato o elemento apontado por p}
Dispose(p);
END
{else a lista est vazia, no h o que tirar}
END;
Suponha que queremos simplesmente matar a lista inteira, como fazemos isso? Da mesma
forma que exclumos um elemento, s que no devolvemos valor algum:
Mato p
O procedimento fica:
E como fazemos para contar os elementos de uma lista? Basta criar um contador e percorrer
a lista incrementando o contador:
Incremento cont
Ou seja:
FUNCTION NumEl(cabeca : p_no) : integer;
VAR p : p_no; {auxiliar}
BEGIN
p := cabeca;
NumEl := 0;
WHILE p <> NIL DO
BEGIN
p := p^.prox;
NumEl := NumEl + 1
END
END;
Agora, usando algumas das funes acima, vamos incluir um novo n na posio i da nossa
lista. Como faremos isso? Suponha a seguinte lista
Criamos, ento, espao para o novo elemento, fazendo q apontar para ele:
Primeiro criamos espao para o novo elemento, fazendo q apontar para ele:
Eliminamos q:
E se a posio pedida for 1? Esse, novamente, um caso um pouco mais complicado, pois no h
como parar um elemento antes, o que indica que nosso algoritmo falha. Como fazer, ento? Basta
seguir o algoritmo dado acima para retirar um elemento do incio da lista.
Vamos, ento, funo que retira o 1 elemento da lista. Essa funo retorna o valor que estava nesse
elemento:
Agora vamos ver como buscar a posio do primeiro elemento que contenha o valor x na
nossa lista. Para tal, o procedimento simples:
Ou seja:
PROCEDURE ExcluiX(VAR cabeca:p_no; elemento:tipo);
VAR el : tipo; {o elemento a ser excludo, auxiliar}
BEGIN
el := TiraDaPos(cabeca,Pos(cabeca,elemento))
{exclu, el jogo fora}
END;
PILHAS
Uma PILHA um tipo especial de LISTA LINEAR em que todas as operaes de insero e
remoo so realizadas numa mesma extremidade, denominada TOPO.
Cada vez que um novo elemento deve ser inserido na pilha, ele colocado no topo; e em
qualquer momento, apenas aquele posicionado no topo da pilha pode ser removido. Devido a
esse tipo de acesso, os elementos so sempre removidos numa ordem inversa quela em que
foram inseridos, de modo que o ltimo elemento que entra exatamente o primeiro que sai.
Por isso essas listas so denominadas LIFO (last-in/first-out).
Uma LISTA LIFO, uma coleo que pode aumentar ou diminuir durante a sua existncia.
Pilha sinnimo de Lista LIFO.
Exemplo: Pilha de pratos.
Uma pilha suporta trs operaes bsicas, tradicionalmente denominadas como:
Topo: Acessa o elemento posicionado no topo da pilha;
Push: Insere um novo elemento no topo da pilha (Insere);
Pop: Remove um elemento do topo da pilha (Retira ou Elimina).
Sendo P uma pilha e x um elemento qualquer, a operao push(P,x) aumenta o tamanho da
pilha P, acrescentando o elemento x no seu topo. A operao Pop(P) faz com que a pilha
diminua, removendo e retornando o elemento no seu topo. Das trs operaes bsicas, a
nica que no altera o estado da pilha Top(P); ela simplesmente retorna uma cpia do
elemento existente no topo da pilha, sem removlo.
OPERAO
--Push (P,a)
Push (P,b)
Push (P,c)
Pop (P)
Pop (P)
Push (P,d)
Top (P)
ESTADO DA PILHA
P: [ ]
P: [a]
P: [b,a]
P: [c,b,a]
P: [b,a]
P: [a]
P: [d,a]
P: [d,a]
RESULTADO
--------c
b
--d
an
an-1
...
a2
a1
Final
Comeo
Exemplo limitaes fsicas de uma pilha (cho, mesa, prato, teto, altura da parede)
Precisamos ento de mais trs operaes essenciais para manipular pilhas:
Init: Inicializa a pilha no estado vazia;
IsEmpty: verifica se a pilha est vazia;
IsFull: verifica se a pilha est cheia.
Init(P), IsEmpty(P), IsFull(P).
Exemplos do uso de pilhas:
1. Programa para converter de decimal para binrio.
2. Chamadas e retornos de rotinas em um programa, cujo papel da pilha fundamental
no controle do programa.
Begin
If p.topo = 0
then
EstaVazia := true
Else
EstaVazia := false;
end;
Function EstaVazia(p:pilha):boolean;
Begin
EstaVazia := (p.topo=0)
End;
Function EstaCheia(p:pilha):boolean;
Begin
If p.topo = MAX
then
EstaCheia := true
Else
EstaCheia := false;
end;
function EstaCheia(p:pilha):boolean;
begin
EstaCheia := (p.topo=MAX)
end;
EMPILHANDO UM ELEMENTO
procedure push(var p:pilha); x:elem);
begin
if (not EstaCheia(p)
then
begin
p.topo := p.topo+1;
p.memo[p.topo] := x;
end
else
writeln('Estouro de pilha!');
end;
DESEMPILHANDO UM ELEMENTO
function pop(var p:pilha):elem;
begin
if not EstaVazia(p)
then
begin
pop := p.memo[p.topo];
p.topo := p.topo-1;
ESTRUTURA DE DADOS PGINA 38
end;
else
writeln('Pilha vazia');
end;
OBTENDO O VALOR DO TOPO
function top(p:pilha):elem;
begin
if not EstaVazia(p)
then
top := p.memo[p.topo];
else
writeln('Pilha vazia!);
end;
FILAS
Uma FILA um tipo especial de LISTA LINEAR em que as inseres so realizadas num
extremo, ficando as remoes restritas ao outro. O extremo onde os elementos so inseridos
denominado final e, aquele de onde so removidos denominado comeo da fila.
A cada insero, um novo elemento colocado no final da fila. O elemento que aguarda mais
tempo na fila, o do comeo, o removido por primeiro. A ordem de sada corresponde
diretamente ordem de entrada, ou seja, os primeiros que entram so os primeiros que saem.
Graas a isso, as filas so denominadas listas FIFO (First-In/First- Out).
Exemplo bastante comum: balco de atendimento, onde pessoas formam fila para
aguardarem atendimento. No devemos considerar pessoas que furam a fila, pois o tipo
abstrato de dados no suporta insero nem remoo no meio da lista.
Sai
Comeo
Final
Entra
Fila em ingls, significa queue. Duas operaes bsicas que uma fila suporta so:
F:
F:
F:
F:
F:
F:
F:
F:
F:
F:
F:
F:
F:
F:
ESTADO DA FILA
[]
[a]
[a,b]
[a,b,c]
[a,b,c,d]
[b,c,d]
[c,d]
[c,d,e]
[c,d,e,f]
[d,e,f]
[d,e,f,c]
[e,f,c]
[f,c]
[c]
RESULTADO
----------a
b
----c
--d
e
f
Final
a2
...
an-1
an
if not cheia(f)
then
begin
f.memo[f.final] := x;
f.final := f.final+1;
end
else
writeln('Fila cheia!');
end;
function dequeue(var f:fila):elem;
begin
if not vazia(f)
then
begin
dequeue := f.memo[f.comeco];
f.comeco := f.comeco+1;
end
else
writeln('Fila vazia!');
end;
begin
end.
EXEMPLO DO PROGRAMA PRINCIPAL QUE UTILIZA A BIBLIOTECA:
program fila_tst;
uses crt,filaest;
var
minhafila:fila;
elemento :elem;
c :char;
begin
clrscr;
init(minhafila);
write('digite elemento: ');
readln(elemento);
while (elemento<>' ') do
begin
enqueue(minhafila,elemento);
write('digite elemento: ');
readln(elemento);
end;
while not vazia(minhafila) do
begin
elemento := dequeue(minhafila);
write(elemento);
end;
writeln(pressione uma tecla...);
c := readkey;
end.
f.final := nil;
end
else
begin
pont := f.comeco^.prox;
dispose(f.comeco);
f.comeco := pont;
end;
end
else
writeln('Fila Vazia!');
End;
begin
end.
Referncias:
Algoritmos e Estrutura de Dados
Wirth, Niklaus
LTC
Estrutura de Dados e Algoritmos
Preiss, Bruno R.
Campus
Lgica de Programao e Estrutura de Dados
Sandra Puga & Gerson Rissetti
Prentice-hall
Algoritmos e Programao de Computadores
Norton Trevisan Roman