LISTAS LINEARES - Universidade Estadual de Mato Grosso do Sul
LISTAS LINEARES - Universidade Estadual de Mato Grosso do Sul
LISTAS LINEARES - Universidade Estadual de Mato Grosso do Sul
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
1<br />
Listas Lineares<br />
Dentre as estruturas <strong>de</strong> da<strong>do</strong>s não primitivas, as listas lineares são as <strong>de</strong><br />
manipulação mais simples.<br />
Uma lista linear agrupa informações referentes a um conjunto <strong>de</strong> elementos<br />
que, <strong>de</strong> alguma forma, se relacionam entre si. Ela po<strong>de</strong> se constituir, por exemplo, <strong>de</strong><br />
informações sobre os funcionários <strong>de</strong> uma empresa, sobre notas <strong>de</strong> compras, itens <strong>de</strong><br />
estoque, notas <strong>de</strong> alunos, etc.<br />
Uma lista linear, ou tabela, é então um conjunto <strong>de</strong> n ≥ 0 nós L[1], L[2], ...,<br />
L[n] tais que suas proprieda<strong>de</strong>s estruturais <strong>de</strong>correm, unicamente, da posição relativa<br />
<strong>do</strong>s nós <strong>de</strong>ntro da seqüência linear. Tem-se:<br />
• se n > 0, L[1] é o primeiro nó;<br />
• para 1 < K ≤ n, o nó L[k] é precedi<strong>do</strong> por L[k-1];<br />
• Operações Mais Freqüentes Em Listas:<br />
• busca;<br />
• inclusão;<br />
• remoção;<br />
São operações básicas, que precisam <strong>de</strong> algoritmos eficientes.<br />
• Outras Operações:<br />
• alteração;<br />
• combinação <strong>de</strong> duas listas;<br />
• or<strong>de</strong>nação;<br />
• <strong>de</strong>terminação <strong>do</strong> primeiro e <strong>do</strong> último nó da lista.<br />
• Casos Particulares <strong>de</strong> Lista:<br />
• <strong>de</strong>que (inserção e remoção só nas extremida<strong>de</strong>s da lista);<br />
• pilha (inserção e remoção só em um extremo);<br />
• pilha( inserção em um extremo e remoções no outro).<br />
• Tipo <strong>de</strong> armazenamento <strong>de</strong> uma lista:<br />
• alocação seqüencial;<br />
• alocação enca<strong>de</strong>ada.<br />
Alocação Seqüencial<br />
Maneira mais simples <strong>de</strong> se manter uma lista na memória. Como a<br />
implementação <strong>de</strong> alocação seqüencial em linguagens <strong>de</strong> alto nível é geralmente<br />
realizada com reserva <strong>de</strong> memória ⇒ alocação estática.<br />
Obs.: Inserção e Remoção <strong>de</strong> nós não ocorrem <strong>de</strong> fato: simulação.<br />
I<strong>de</strong>al para filas e pilhas.<br />
Seja uma lista linear. Cada nó é forma<strong>do</strong> por campos, que armazenam as<br />
características distintas <strong>do</strong>s elementos da lista. Além disso, cada nó da lista possui,<br />
geralmente, um i<strong>de</strong>ntifica<strong>do</strong>r, <strong>de</strong>nomina<strong>do</strong> chave. Para evitar ambigüida<strong>de</strong>s, supõe-se
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
2<br />
que todas as chaves são distintas. A chave, quan<strong>do</strong> presente, se constitui em um <strong>do</strong>s<br />
campos <strong>do</strong> nó. Os nós po<strong>de</strong>m se encontrar or<strong>de</strong>na<strong>do</strong>s, ou não, segun<strong>do</strong> os valores <strong>de</strong><br />
suas chaves ⇒ lista or<strong>de</strong>nada ou não-or<strong>de</strong>nada.<br />
Ex. 1: Consi<strong>de</strong>re uma lista L <strong>de</strong> n elementos.<br />
Nó 1 Nó 2 Nó 3 Nó 4 Nó 5<br />
Chave Nome En<strong>de</strong>reço<br />
⇒ REGISTRO<br />
Ex.1.1: Algoritmo que realiza a busca <strong>de</strong> um elemento na lista L.<br />
Função busca (x); {x é o elemento procura<strong>do</strong>}<br />
inicio<br />
i ← 1;<br />
busca ← 0;<br />
enquanto i ≤ n faça<br />
se L[i].chave = x então {chave encontrada}<br />
busca ← i;<br />
i ← n +1;<br />
senão<br />
i ← i + 1;<br />
{pesquisa prossegue}<br />
fim se<br />
fim enquanto<br />
fim;<br />
Ex.1.1a: Outra maneira <strong>de</strong> escrever o algoritmo:<br />
Função busca (x); {x é o elemento procura<strong>do</strong>}<br />
inicio<br />
L[n+1].chave ← x;<br />
enquanto L[i].chave ≠ x faça<br />
i ← i + 1;<br />
fim enquanto<br />
se i ≠ n + 1 então<br />
busca ← i;<br />
senão<br />
busca ← 0;<br />
fim se<br />
fim;
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
3<br />
Ex.2: Algoritmo para busca na lista or<strong>de</strong>nada:<br />
Função busca_ord (x); {x é o elemento procura<strong>do</strong>}<br />
inicio<br />
L[n+1].chave ← x;<br />
enquanto L[i].chave ≠ x faça<br />
i ← i + 1;<br />
fim enquanto<br />
se i ≠ n + 1 ou L[i].chave ≠ x então<br />
busca_ord ← 0;<br />
senão<br />
busca_ord ← i;<br />
fim se<br />
fim;<br />
Ex.3: Um méto<strong>do</strong> bem mais eficiente: Busca Binária.<br />
Função busca_binaria (x); {x é o elemento procura<strong>do</strong>}<br />
inicio<br />
inf ← 1;<br />
sup ← n;<br />
busca_binaria ← 0;<br />
enquanto inf ≤ sup faça<br />
meio ← L[inf + sup)/2]; {índice a ser busca<strong>do</strong>}<br />
se L[meio].chave = x então<br />
busca_binaria ← meio; {elemento encontra<strong>do</strong>}<br />
inf ← sup + 1;<br />
senão<br />
se L[meio].chave < x então<br />
inf ← meio + 1;<br />
senão<br />
sup ← meio -1;<br />
fim se<br />
fim se<br />
fim enquanto<br />
fim;<br />
Para realizar as operações <strong>de</strong> inserção e remoção utilizamos o procedimento <strong>de</strong><br />
busca. No caso da inserção, o objetivo é evitar chaves repetidas e, no caso da remoção, a<br />
necessida<strong>de</strong> <strong>de</strong> localizar o elemento a ser removi<strong>do</strong>.
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
4<br />
Ex:4: O algoritmo abaixo efetua a inserção <strong>de</strong> um nó na lista.<br />
Algoritmo {inserção <strong>de</strong> um nó na lista L}<br />
se n < m então<br />
se busca(x) = 0 então<br />
L[n+1] ← novo_valor;<br />
n ← n + 1;<br />
senão<br />
escreva (“elemento já existe na tabela”);<br />
fim se<br />
senão<br />
escreva (“overflow”);<br />
fim se<br />
Fim algoritmo<br />
Ex 5: O algoritmo abaixo efetua a remoção <strong>de</strong> um nó da lista.<br />
Algoritmo {remoção <strong>de</strong> um nó na lista L}<br />
se n ≠ 0 então<br />
índice ← busca(x);<br />
se índice = 0 então<br />
valor_recupera<strong>do</strong> ← L[índice];<br />
para i <strong>de</strong> 1 até n – 1 faça<br />
L[i] ← L[i+1];<br />
fim para<br />
n ← n – 1;<br />
senão<br />
escreva (“elemento não se encontra na tabela”);<br />
fim se<br />
senão<br />
escreva (“un<strong>de</strong>rflow”);<br />
fim se<br />
fim algoritmo<br />
Ambos os algoritmos consi<strong>de</strong>ram tabelas não or<strong>de</strong>nadas. A memória<br />
pressuposta disponível tem m posições (na realida<strong>de</strong> m+1, porque é necessária uma<br />
posição extra para a busca).<br />
• Overflow: não há mais espaço para inserção;<br />
• Undrflow: remoção em lista vazia.<br />
Obs.: Ambos os casos fazer tratamento<br />
No caso <strong>de</strong> tabelas or<strong>de</strong>nadas, o algoritmo <strong>de</strong> remoção não se modifica. O<br />
algoritmo <strong>de</strong> inserção, entretanto, precisa ser refeito, uma vez que, nesse caso, a posição<br />
<strong>do</strong> nó torna-se relevante.
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
5<br />
Pilhas e Filas<br />
Armazenamento seqüencial ⇒ i<strong>de</strong>al quan<strong>do</strong> inserções e remoções não<br />
acarretam movimentação <strong>de</strong> nós, o que ocorre se os elementos a serem inseri<strong>do</strong>s e<br />
removi<strong>do</strong>s estão em posições seqüenciais, como a primeira ou a última posição. Pilhas e<br />
filas satisfazem tais condições.<br />
Pilhas<br />
Utiliza-se indica<strong>do</strong>res especiais, <strong>de</strong>nomina<strong>do</strong>s ponteiros, para o acesso a<br />
posição selecionadas. No caso da pilha, usa-se apenas um ponteiro, o ponteiro topo, pois<br />
as inserções e remoções são executadas na mesma extremida<strong>de</strong> da lista.<br />
Ex1.: Pilha<br />
Situação 1: inicial: pilha vazia<br />
1 2 3 . . . m<br />
⇑<br />
topo<br />
Situação 2: inserir informação A<br />
1 2 3 . . . m<br />
A<br />
⇑<br />
topo<br />
Situação 3: inserir informação B<br />
1 2 3 . . . m<br />
A<br />
B<br />
Situação 4: retirar informação B<br />
1 2 3 . . . m<br />
A<br />
⇑<br />
topo<br />
Situação 5: inserir informação C<br />
1 2 3 . . . m<br />
A<br />
⇑<br />
topo<br />
C<br />
⇑<br />
topo
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
6<br />
Situação 6: retirar informação C<br />
1 2 3 . . . m<br />
A<br />
⇑<br />
topo<br />
Situação 7: retirar informação A<br />
1 2 3 . . . m<br />
⇑<br />
topo<br />
pilha vazia<br />
Ex.1a: Algoritmo <strong>de</strong> inserção na pilha P<br />
Algoritmo<br />
se topo ≠ M então<br />
topo ← topo + 1;<br />
P [topo] ← novo_valor;<br />
senão<br />
escreva(“overflow”);<br />
fim se<br />
Fim Algoritmo<br />
Ex. 1b: Algoritmo <strong>de</strong> remoção da pilha P<br />
Algoritmo<br />
se topo ≠ 0 então<br />
valor_recupera<strong>do</strong> ← P [topo];<br />
topo ← topo - 1;<br />
senão<br />
escreva(“un<strong>de</strong>rflow”);<br />
fim se<br />
Fim Algoritmo<br />
Filas<br />
Filas exigem uma implementação mais elaborada. São necessários <strong>do</strong>is<br />
ponteiros: início da fila (I) e retaguarda (R). Isso porque na fila as inserções são feitas<br />
sempre no final da fila e as remoções sempre no início da fila. Para a inserção <strong>de</strong> um<br />
elemento, move-se o ponteiro R; para a retirada, move-se o ponteiro I. A fila vazia é<br />
representada por I = R = 0.
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
7<br />
Ex2.: Fila<br />
Situação 1: inicial: fila vazia<br />
1 2 3 . . . m<br />
⇑<br />
I R<br />
Situação 2: inserir informação A<br />
1 2 3 . . . m<br />
A<br />
⇑<br />
I R<br />
Situação 3: inserir informação B<br />
1 2 3 . . . m<br />
A B<br />
⇑<br />
I<br />
⇑<br />
R<br />
Situação 4: retirar informação A<br />
1 2 3 . . . m<br />
B<br />
⇑<br />
I R<br />
Situação 5: inserir informação C<br />
1 2 3 . . . m<br />
B C<br />
⇑<br />
I<br />
⇑<br />
R<br />
Situação 6: retirar informação B<br />
1 2 3 . . . m<br />
C<br />
⇑<br />
I R
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
8<br />
Situação 7: retirar informação C<br />
1 2 3 . . . m<br />
⇑<br />
topo<br />
fila vazia<br />
Ex: 2a: Algoritmo <strong>de</strong> inserção da fila F<br />
Algoritmo<br />
inicio<br />
prov ← r mod M+1;<br />
se prov ≠ I então<br />
r ← prov;<br />
F[r] ← novo_valor;<br />
se I = 0 então<br />
I ← 1;<br />
fim se<br />
senão<br />
escreva (“overflow”);<br />
fim se<br />
Fim Algoritmo<br />
Ex: 2b: Algoritmo <strong>de</strong> remoção da fila F<br />
Algoritmo<br />
inicio<br />
se I ≠ 0 então<br />
valor_recupera<strong>do</strong> ← F[I];<br />
se I = R então<br />
I ← R ← 0;<br />
senão<br />
I ← I mod n + 1;<br />
fim se<br />
senão<br />
escreva (“un<strong>de</strong>rflow”);<br />
fim se<br />
Fim Algoritmo<br />
À medida que os ponteiros são incrementa<strong>do</strong>s na memória disponível, a fila<br />
“se move”, o que po<strong>de</strong> dar origem à falsa impressão <strong>de</strong> memória esgotada. Para eliminar<br />
esse problema, consi<strong>de</strong>ram-se os m nós aloca<strong>do</strong>s como se estivessem em círculo, on<strong>de</strong><br />
F[1] segue F[m].<br />
Notação Polonesa: Aplicação Para Pilhas<br />
Uma representação para expressões aritméticas que seja conveniente <strong>do</strong> ponto <strong>de</strong><br />
vista computacional, é aumento <strong>de</strong> interesse, por exemplo, na área <strong>de</strong> compila<strong>do</strong>res. A
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
9<br />
notação tradicional é ambígua e, portanto, obriga ao pre-estabelecimento <strong>de</strong> regras <strong>de</strong><br />
priorida<strong>de</strong>, o que torna a tarefa computacional mais complexa,<br />
Consi<strong>de</strong>ran<strong>do</strong> apenas operações binárias, temos outros tipos <strong>de</strong> representação:<br />
• notação completamente parentizada: acrescenta-se sempre um para <strong>de</strong><br />
parênteses a cada par <strong>de</strong> operan<strong>do</strong>s e a seu opera<strong>do</strong>r.<br />
EX:<br />
notação tradicional: A * B – C / D<br />
notação parentizada: ((A * B) – (C/D))<br />
• notação polonesa: os operan<strong>do</strong>s aparecem imediatamente antes <strong>do</strong>s<br />
operan<strong>do</strong>s. Essa notação explicita quais operan<strong>do</strong>s, e em que or<strong>de</strong>m, <strong>de</strong>vem ser<br />
calcula<strong>do</strong>s. Por esse motivo, dispensa o uso <strong>de</strong> parênteses, sem ambigüida<strong>de</strong>s.<br />
EX:<br />
notação tradicional: A * B – C / D<br />
notação polonesa: -* A B / C D<br />
• notação polonesa reversa: notação polonesa com os opera<strong>do</strong>res<br />
aparecen<strong>do</strong> após os operan<strong>do</strong>s. (usada em máquinas <strong>de</strong> calcular).<br />
EX:<br />
notação tradicional: A * B – C / D<br />
notação polonesa: A B * C D / -<br />
Tanto a expressão original quanto a expressão resultante <strong>de</strong>vem ser<br />
armazenadas em listas.<br />
⇒ Antes <strong>de</strong> colocar o algoritmo, exemplificar.<br />
Expressão parentizada: ((3*4) – (10/2))
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
10<br />
Algoritmo Para Conversão da Notação Parentizada na Notação Polonesa Reversa:<br />
• os operan<strong>do</strong>s aparecem na mesma or<strong>de</strong>m na notação tradicional e na notação<br />
polonesa reversa.<br />
Na notação polonesa reversa<br />
• na notação polonesa reversa os operan<strong>do</strong>s aparecem na or<strong>de</strong>m em que <strong>de</strong>vem ser<br />
calcula<strong>do</strong>s (da esquerda para a direita);<br />
• o operan<strong>do</strong>s aparecem imediatamente <strong>de</strong>pois <strong>de</strong> seus operan<strong>do</strong>s.<br />
A principal preocupação <strong>do</strong> algoritmo <strong>de</strong>ve ser a or<strong>de</strong>m e a posição <strong>do</strong>s<br />
opera<strong>do</strong>res. Na notação parentizada, essa or<strong>de</strong>m é indicada pelos parênteses; os mais<br />
internos significam operações prioritárias.<br />
Ex: 1: Algoritmo que realiza a conversão da notação parentizada para a polonesa<br />
reversa<br />
Algoritmo<br />
in<strong>de</strong>x ← 1; {índice da expressão parentizada}<br />
indpol ← 0; {índice da expressão polonesa}<br />
topo ← 0; {ponteiro da pilha}<br />
enquanto in<strong>de</strong>xp ≤ fim então<br />
se exp[in<strong>de</strong>xp] é operan<strong>do</strong> então {passa para a nova lista}<br />
indpol ← indpol +1;<br />
pol[indpol] ← exp[in<strong>de</strong>xp];<br />
senão<br />
se exp[in<strong>de</strong>xp] é opera<strong>do</strong>r então {coloca na pilha}<br />
topo ← topo + 1;<br />
pilha[topo] ← exp[in<strong>de</strong>xp];<br />
senão<br />
se exp[in<strong>de</strong>xp] = “)” então<br />
se topo ≠ 0 então {forma a operação}<br />
opera<strong>do</strong>r ← pilha[topo];<br />
topo ← topo - 1;<br />
indpol ← indpol + 1;<br />
pol[indpol] ← opera<strong>do</strong>r;<br />
senão<br />
"Expressão errada!";<br />
fim se<br />
fim se<br />
fim se<br />
fim se<br />
in<strong>de</strong>xp ← in<strong>de</strong>xp + 1;<br />
fim enquanto<br />
Fim Algoritmo<br />
Uma análise sintática prévia na expressão é pressuposta (verificar se a<br />
expressão é válida!). Para efetuar a conversão, <strong>de</strong>vem-se remover os parênteses e<br />
estabelecer a or<strong>de</strong>m conveniente <strong>de</strong> opera<strong>do</strong>res. Estes <strong>de</strong>vem ser armazena<strong>do</strong>s até que<br />
um ")" seja encontra<strong>do</strong>, o que indica que a operação mais interna, e por conseguinte a<br />
primeira a ser executada, foi <strong>de</strong>tectada. O último opera<strong>do</strong>r armazena<strong>do</strong> correspon<strong>de</strong> a<br />
essa operação. Portanto, a estrutura utilizada no armazenamento <strong>do</strong>s opera<strong>do</strong>res <strong>de</strong>ve
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
11<br />
ser uma pilha. A expressão a ser convertida se encontra no vetor exp e o resulta<strong>do</strong> da<br />
conversão, no vetor pol. A variável fim indica a dimensão da expressão.<br />
Exercícios<br />
1. Utilizan<strong>do</strong> o algoritmo visto em sala, converta as expressões abaixo para a notação<br />
polonesa reversa:<br />
a) (((5 * 2) / 5) - (9 / 5))<br />
b) (7 - ((4 * (3 - 2)) * 2 ))<br />
c) (4 * (((3 - 8) / 4) - 5))<br />
2. Proponha um algoritmo para achar o resulta<strong>do</strong> das expressões na notação polonesa<br />
reversa.<br />
3. Use o algoritmo <strong>de</strong>senvolvi<strong>do</strong> no ítem anterior e calcule o resulta<strong>do</strong> das expressões<br />
<strong>do</strong> exercício 1.<br />
4. Proponha mudanças no algoritmo que converte expressões parentizadas para<br />
notação polonesa reversa, para tratar o opera<strong>do</strong>r unário - e números com mais <strong>de</strong> um<br />
dígito.<br />
Solução <strong>do</strong> exercício 2:<br />
indpol ← 1;<br />
topo ← 0;<br />
enquanto indpol ≤ fim faça<br />
se pol[indpol] é operan<strong>do</strong> então<br />
Push(pol[indpol]); {insere na pilha}<br />
senão se pol[indpol] é opera<strong>do</strong>r então<br />
oper1 ← pop(); {retira <strong>do</strong>is operan<strong>do</strong>s <strong>do</strong> topo da pilha}<br />
fim se<br />
fim se<br />
fim enquanto<br />
oper2 ← pop();<br />
result ← calcula_oper(oper2, oper1, pol[indpol]);<br />
push( result ); {empilha resulta<strong>do</strong> parcial}
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
12<br />
Listas Lineares em Alocação Enca<strong>de</strong>ada<br />
- Operações em listas implementadas com alocação seqüencial são muito fracas;<br />
- Na utilização <strong>de</strong> mais <strong>de</strong> duas listas, a gerência <strong>de</strong> memória é mais complexa ⇒ usar<br />
alocação dinâmica (ou alocação enca<strong>de</strong>ada).<br />
Na alocação enca<strong>de</strong>ada, as posições <strong>de</strong> memória são alocadas (ou<br />
<strong>de</strong>salocadas) na medida em que são necessárias (ou dispensadas). Os nós <strong>de</strong> uma lista<br />
encontram-se aleatoriamente dispostos na memória e são interliga<strong>do</strong>s por ponteiros, que<br />
indicam a posição <strong>do</strong> próximo elemento da tabela.<br />
Cada nó terá, agora, um campo adicional, que conterá o en<strong>de</strong>reço <strong>do</strong><br />
próximo nó da lista.<br />
1 2 3 4 ... n<br />
Lista seqüencial:<br />
Lista enca<strong>de</strong>ada:<br />
nó 1 nó 2 nó 3 nó 4<br />
Vantagens e <strong>de</strong>svantagens <strong>do</strong>s tipos <strong>de</strong> alocação:<br />
- A alocação enca<strong>de</strong>ada é mais conveniente quan<strong>do</strong> o problema inclui o tratamento <strong>de</strong><br />
mais <strong>de</strong> uma lista;<br />
- O acesso ao k-ésimo elemento da lista é imediato na alocação seqüencial, enquanto<br />
na alocação enca<strong>de</strong>ada obriga ao percurso na lista até o elemento <strong>de</strong>seja<strong>do</strong>.<br />
Como em uma lista enca<strong>de</strong>ada os nós não estão, obrigatoriamente, em posições<br />
contíguas da memória, ao se realizar uma inserção ou remoção, há a necessida<strong>de</strong> <strong>de</strong><br />
encontrar novas posições <strong>de</strong> memória para armazenamento e liberar outras que possam<br />
ser reutilizadas posteriormente.<br />
É preciso, portanto, gerenciar a memória disponível. As linguagens<br />
geralmente possuem um módulo <strong>de</strong> gerência <strong>de</strong> memória disponível ao usuário,<br />
bastan<strong>do</strong> apenas que este se refira às rotinas internas <strong>de</strong> ocupação e <strong>de</strong>volução <strong>de</strong> nós da<br />
lista <strong>de</strong> espaço disponível. Em Pascal, as rotinas new(pt) e dispose(pt) executam essa<br />
tarefa.<br />
Nos algoritmos, usamos uma notação especial:<br />
- a indicação <strong>do</strong> en<strong>de</strong>reço <strong>de</strong> um nó, feita por um ponteiro, será<br />
representada pelo símbolo →. Cada ponteiro utiliza<strong>do</strong> é associa<strong>do</strong> a um<br />
único tipo <strong>de</strong> nó. Assim, pt→info representa o campo info <strong>do</strong> nó<br />
aponta<strong>do</strong> por pt; pt→prox representa o en<strong>de</strong>reço <strong>do</strong> campo prox<br />
aponta<strong>do</strong> por pt.<br />
pt<br />
info<br />
prox<br />
nó
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
13<br />
Um conjunto <strong>de</strong> nós enca<strong>de</strong>a<strong>do</strong>s formam uma tabela. A associação <strong>do</strong> ponteiro<br />
pt ao tipo <strong>de</strong> nó é <strong>de</strong>finida previamente na <strong>de</strong>claração das variáveis. Exemplo:<br />
<strong>de</strong>clare No registro (Info numérico,<br />
Prox ponteiro No);<br />
<strong>de</strong>clare Pt ponteiro No;<br />
pt<br />
infor<br />
prox<br />
infor<br />
prox<br />
nó<br />
nó<br />
Listas simplesmente enca<strong>de</strong>adas<br />
Qualquer estrutura, inclusive listas, que seja armazenada em alocação<br />
enca<strong>de</strong>ada requer o uso <strong>de</strong> um ponteiro que indique o en<strong>de</strong>reço <strong>de</strong> seu primeiro nó. O<br />
percurso <strong>de</strong> uma lista é feito, então, a partir <strong>de</strong>sse ponteiro. A idéia consiste em seguir,<br />
consecutivamente, pelos en<strong>de</strong>reços existentes no campo que indica o próximo nó<br />
(semelhante ao índice da alocação seqüencial).<br />
Algoritmo que percorre uma lista para impressão <strong>do</strong> campo info:<br />
Obs.: ptlista é o ponteiro para o primeiro nó.<br />
Algoritmo<br />
Pont ← ptlista; {pont é um ponteiro auxiliar}<br />
enquanto pont ≠ null faça {null indica o final da lista}<br />
escreva pont → info;<br />
Pont ← pont → prox;<br />
fim enquanto<br />
Fim algoritmo<br />
⇒ Fazer esquema para facilitar visualização!<br />
Algoritmo <strong>de</strong> busca: consi<strong>de</strong>rações<br />
- <strong>de</strong>ve ser eficiente;<br />
- primeira inserção e última remoção exigem testes especiais.<br />
Solução: nó-cabeça, nunca removi<strong>do</strong>, que será indica<strong>do</strong> pelo ponteiro <strong>de</strong> início da<br />
lista (esse nó terá essa utilida<strong>de</strong> específica, não conten<strong>do</strong>, portanto, informações<br />
relacionadas à tabela propriamente dita).<br />
Lista vazia:<br />
ptlista<br />
nó-cabeça<br />
ptlista<br />
nó 1 nó 2 nó 3
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
14<br />
Algoritmo <strong>de</strong> busca:<br />
- ptlista: guarda o nó cabeça da lista<br />
- x: chave procurada<br />
Procedimento BuscaEnc( x, ant, pont );<br />
início<br />
Ant ← ptlista;<br />
Ptr ←ptlista → prox; {ptr: ponteiro <strong>de</strong> percurso}<br />
Pont ← null;<br />
enquanto ptr ≠ null faça<br />
se ptr → chave < x então<br />
Ant ← ptr; {atualiza ant e ptr}<br />
Ptr ← ptr → prox;<br />
senão se ptr → chave = x então<br />
Pont ← ptr; {chave encontrada}<br />
fim se<br />
Ptr ← null;<br />
fim se<br />
fim enquanto<br />
fim;<br />
- o parâmetro pont retorna apontan<strong>do</strong> para o elemento procura<strong>do</strong> e, ant para o<br />
elemento anterior ao procura<strong>do</strong>;<br />
- se o elemento não for encontra<strong>do</strong>, pont aponta para null e ant indica o elemento<br />
anterior ao último procura<strong>do</strong>.<br />
Inserção e remoção<br />
Após a realização da busca, as operações <strong>de</strong> inserção e remoção em uma lista<br />
enca<strong>de</strong>ada são triviais. Três fases <strong>de</strong>vem ser cumpridas:<br />
- alocação / <strong>de</strong>salocação <strong>de</strong> memória;<br />
- utilização <strong>do</strong> nó;<br />
- acerto da lista<br />
Exemplo: inserção<br />
ant<br />
ptlista<br />
nó 1 nó 2 nó 3<br />
pt
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
15<br />
Algoritmo que realiza a inserção <strong>de</strong> um novo nó na lista:<br />
Algoritmo<br />
BuscaEnc( x, ant, pont );<br />
se pont = null então<br />
Alocar( pt ); {alocar nó}<br />
pt → info ← novo_valor;<br />
pt → chave ← x; {utilizar nó}<br />
pt → prox ← ant → prox;<br />
ant → prox ← pt; {arrumar lista}<br />
senão<br />
“Elemento já está na lista!”;<br />
fim se<br />
Fim Algoritmo;<br />
- inserção <strong>do</strong> nó conti<strong>do</strong> na variável novo, após o nó aponta<strong>do</strong> por ant;<br />
- mantém a lista or<strong>de</strong>nada.<br />
⇒ Desenhar esquema.<br />
Algoritmo que realiza a remoção <strong>de</strong> um nó da lista:<br />
Algoritmo<br />
BuscaEnc( x, ant, pont );<br />
se pont ≠ null então<br />
ant → prox ← pont → prox; {arrumar lista}<br />
valor_recupera<strong>do</strong> ← pont → info; {utilizar nó}<br />
Desocupar( pont );<br />
{<strong>de</strong>salocar memória}<br />
senão<br />
“Elemento não se encontra na lista!”;<br />
fim se<br />
Fim Algoritmo;<br />
Exercícios<br />
1. Usan<strong>do</strong> os procedimentos anteriores (inserção, remoção e busca), escreva um<br />
algoritmo que leia um conjunto <strong>de</strong> N valores numéricos, manten<strong>do</strong>-os em uma lista<br />
or<strong>de</strong>nada. Depois verifique se aparece o valor 12 nesta lista, liberan<strong>do</strong> o nó com esse<br />
valor da memória e indican<strong>do</strong> qual era a sua posição na lista.<br />
2. Apresente os procedimentos <strong>de</strong> inserção, remoção e busca, para uma lista não<br />
or<strong>de</strong>nada.<br />
3. Usan<strong>do</strong> os procedimentos escritos no exercício 2, escreva um algoritmo que leia<br />
uma string e uma palavra, armazenan<strong>do</strong>-as em duas listas, e verifique se a palavre<br />
ocorre na string.<br />
Obs.: o algoritmo <strong>de</strong> inserção <strong>de</strong>ve aceitar elementos repeti<strong>do</strong>s (ou usar o recurso da<br />
chave).<br />
Listas Circulares<br />
A busca em uma lista or<strong>de</strong>nada, vista anteriormente, po<strong>de</strong> ser consi<strong>de</strong>rada<br />
pouco eficiente quan<strong>do</strong> comparada às outras buscas anteriormente mencionadas. Uma<br />
pequena modificação na estrutura física da lista po<strong>de</strong> ser <strong>de</strong> gran<strong>de</strong> auxílio: obrigar o<br />
último nó da lista a apontar para o nó-cabeça, crian<strong>do</strong> uma lista circular enca<strong>de</strong>ada.
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
16<br />
ptlista<br />
...<br />
nó 1 nó 2 nó n<br />
Desta forma, o teste <strong>de</strong> fim <strong>de</strong> lista nunca é satisfeito. A preocupação passa a<br />
ser um critério <strong>de</strong> parada que possa ser incorpora<strong>do</strong> ao teste da busca propriamente dita.<br />
A solução é colocar a chave procurada no nó-cabeça, <strong>de</strong> forma que uma resposta<br />
positiva seja sempre encontrada.<br />
O algoritmo abaixo apresenta a nova busca, no caso <strong>de</strong> listas or<strong>de</strong>nadas. O<br />
ponteiro pont tem o valor <strong>de</strong> ptlista se o elemento não é encontra<strong>do</strong>. Naturalmente,<br />
modificações correspon<strong>de</strong>ntes <strong>de</strong>vem ser introduzidas nos algoritmos <strong>de</strong> inserção e<br />
remoção.<br />
Algoritmo:<br />
Procedimento Busca_Circ (X, Ant, Pont); {lista circular or<strong>de</strong>nada}<br />
Início<br />
Ant ← Ptlista;<br />
Ptlista → Chave ← X;<br />
Pont ← Ptlista → Prox;<br />
enquanto Pont → Chave < X faça<br />
Ant ← Pont;<br />
Pont ← Pont → Prox;<br />
fim enquanto<br />
se Pont ≠ Ptlista então<br />
escreva "Chave localizada";<br />
senão<br />
escreva "Chave não localizada";<br />
fim se<br />
Fim;<br />
Como ficam os algoritmos <strong>de</strong> Inserção e Remoção?<br />
Os algoritmos <strong>de</strong> inserção e remoção não mudam. O que muda é que na<br />
alocação <strong>do</strong> nó-cabeça, o ponteiro prox <strong>de</strong>ve apontar não mais para null, mas para o<br />
próprio nó-cabeça.<br />
ptlista<br />
{alocação <strong>do</strong> nó-cabeça}<br />
Alocar (Ptlista);<br />
Ptlista → Prox ← Ptlista;<br />
⇒ Como ficam os algoritmos para lista circular não or<strong>de</strong>nada?
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
17<br />
Listas Duplamente Enca<strong>de</strong>adas<br />
Nos algoritmos vistos até agora para listas lineares utilizan<strong>do</strong> alocação<br />
enca<strong>de</strong>ada, o ponteiro ant se mostrou sempre útil. Sua função é "rastrear" o ponteiro que<br />
percorre a lista, permitin<strong>do</strong> sempre o retorno ao nó anterior. Algumas vezes, entretanto,<br />
isto não é suficiente, pois po<strong>de</strong>-se <strong>de</strong>sejar o percurso da lista nos <strong>do</strong>is senti<strong>do</strong>s<br />
indiferentemente.<br />
ptlista<br />
nó1 nó2 nón<br />
A lista duplamente enca<strong>de</strong>ada incorpora um novo campo <strong>de</strong> ponteiro. Os<br />
campos <strong>de</strong> ponteiros tomam os nomes <strong>de</strong> ant e post (nó anterior e nó seguinte,<br />
respectivamente).<br />
Os algoritmos <strong>de</strong> busca, inserção e remoção em tabelas or<strong>de</strong>nadas são muito<br />
simples. Na busca, a função retorna indican<strong>do</strong> o nó procura<strong>do</strong> ou, se este não foi<br />
encontra<strong>do</strong>, o nó que seria seu consecutivo.<br />
Busca em uma lista duplamente enca<strong>de</strong>ada or<strong>de</strong>nada:<br />
Função Busca_Dup (X) : ponteiro;<br />
Início<br />
Ultimo ← Ptlista → Ant;<br />
se X ≤ Ultimo → Chave então<br />
Pont ← Ptlista → Post;<br />
enquanto Pont → Chave < X faça<br />
Pont ← Pont → Prox;<br />
fim enquanto<br />
Busca_Dup ← Pont;<br />
senão<br />
Busca_Dup ← Ptlista;<br />
fim se<br />
Fim;<br />
Inserção em lista duplamente enca<strong>de</strong>ada or<strong>de</strong>nada:<br />
ptlista<br />
nó1 nó2 nón<br />
pt
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
18<br />
Algoritmo<br />
Pont ← Busca_Dup (X);<br />
se Pont = Ptlista ou Pont → Chave ≠ X então<br />
Anterior ← Pont → Ant;<br />
Ocupar (Pt);<br />
Pt → Info ← Novo_valor;<br />
Pt → Chave ← X;<br />
Pt → Ant ← Anterior;<br />
Pt → Post ← Pont;<br />
Anterior → Post ← Pt;<br />
Pont → Ant ← Pt;<br />
senão<br />
escreva "Elemento já se encontra na lista";<br />
fim se<br />
Fim Algoritmo<br />
Remoção em lista duplamente enca<strong>de</strong>ada or<strong>de</strong>nada:<br />
Algoritmo<br />
Pont ← Busca_Dup (X);<br />
se Pont ≠ Ptlista e Pont → Chave = X então<br />
Anterior ← Pont → Ant;<br />
Posterior ← Pont → Post;<br />
Anterior → Post ← Posterior;<br />
Posterior → Ant ← Anterior;<br />
Valor_recupera<strong>do</strong> ← Pont → Info;<br />
Desocupar (Pont);<br />
senão<br />
escreva "Elemento não se encontra na lista";<br />
fim se<br />
Fim Algoritmo<br />
ptlista<br />
nó1 nó2 nón<br />
pont<br />
Aplicação: Or<strong>de</strong>nação Topológica<br />
Uso pontencial todas as vezes em que o problema aborda<strong>do</strong> envolve uma<br />
or<strong>de</strong>m parcial.<br />
Uma or<strong>de</strong>m parcial <strong>de</strong> um conjunto S é uma relação entre os objetos <strong>de</strong> S,<br />
representada pelo símbolo ≤, satisfazen<strong>do</strong> as seguintes proprieda<strong>de</strong>s para quaisquer<br />
objetos x, y e z, não necessariamente distintos em S:<br />
i) se x ≤ y e y ≤ z, então x ≤ z (transitiva);
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
19<br />
ii) se x ≤ y e y ≤ x, então x = y (anti-simétrica);<br />
iii) x ≤ x (reflexiva);<br />
A notação x ≤ y po<strong>de</strong> ser lida "x prece<strong>de</strong> ou iguala y".<br />
Se x ≤ y e x = y, escreve-se x < y e diz-se "x prece<strong>de</strong> y". Tem-se então:<br />
i') se x < y e y < z, então x < z (transitiva);<br />
ii') se x < y, então y ∠ x (assimétrica);<br />
iii') x ∠ x (irreflexiva).<br />
A notação y ∠ x significa "y não prece<strong>de</strong> x". Assume-se aqui que S é um<br />
conjunto finito, uma vez que se <strong>de</strong>seja trabalhar no computa<strong>do</strong>r.<br />
Exemplo <strong>de</strong> aplicação:<br />
Execução <strong>de</strong> um conjunto <strong>de</strong> tarefas necessárias, por exemplo, à montagem <strong>de</strong><br />
um automóvel. Uma or<strong>de</strong>m parcial <strong>de</strong>ssas tarefas po<strong>de</strong> ser representada assim:<br />
1 5<br />
3 2 8<br />
4 6<br />
7<br />
Cada caixa na figura representa uma tarefa a ser executada; cada tarefa é<br />
numerada arbitrariamente. Se existe a indicação <strong>de</strong> um caminho da caixa x para a caixa<br />
y, isto significa que a tarefa x <strong>de</strong>ve ser executada antes da tarefa y.<br />
A or<strong>de</strong>nação topológica trata <strong>de</strong> imergir a or<strong>de</strong>m parcial em uma or<strong>de</strong>m linear,<br />
isto é, rearrumar os objetos numa seqüência a 1 , a 2 , ..., a n , tal que sempre que a j < a k , temse<br />
j < k.<br />
1 5 2 8 6 7 3<br />
4
<strong>Universida<strong>de</strong></strong> <strong>Estadual</strong> <strong>de</strong> <strong>Mato</strong> <strong>Grosso</strong> <strong>do</strong> <strong>Sul</strong> - Curso <strong>de</strong> Ciência da Computação<br />
Disciplina: Estruturas <strong>de</strong> Da<strong>do</strong>s<br />
Profª. Raquel Marcia Müller<br />
20<br />
Como obter a or<strong>de</strong>nação topológica:<br />
- inicialmente, consi<strong>de</strong>ra-se um objeto que não é precedi<strong>do</strong> por nenhum outro na<br />
or<strong>de</strong>m parcial. Esse objeto é o primeiro na saída, isto é, na or<strong>de</strong>m final;<br />
- removemos o objeto <strong>do</strong> conjunto S;<br />
- o conjunto resultante obe<strong>de</strong>ce novamente a uma or<strong>de</strong>m parcial. O processo é, então,<br />
repeti<strong>do</strong> até que to<strong>do</strong> o conjunto esteja or<strong>de</strong>na<strong>do</strong>.<br />
Implementação:<br />
Os objetos a serem or<strong>de</strong>na<strong>do</strong>s são numera<strong>do</strong>s <strong>de</strong> 1 a n, em qualquer or<strong>de</strong>m, e<br />
aloca<strong>do</strong>s seqüencialmente na memória. A entrada <strong>do</strong> algoritmo são os pares (j, k),<br />
significan<strong>do</strong> que o objeto j prece<strong>de</strong> o objeto k. O número <strong>de</strong> objetos n e o número <strong>de</strong><br />
pares m também são forneci<strong>do</strong>s. Devem constar da entrada somente os pares<br />
necessários à caracterização da or<strong>de</strong>m parcial; pares supérfluos não constituem erro.<br />
Ex.: o par (8,7) é <strong>de</strong>snecessário, pois po<strong>de</strong> ser <strong>de</strong>duzi<strong>do</strong> <strong>do</strong>s pares (8,6) e (6,7).<br />
0 0 -<br />
1 0 3 2 -<br />
2 2 6 -<br />
3 2 4 -<br />
4 1 -<br />
5 0 2 8 -<br />
6 2 7 -<br />
7 1 3 -<br />
8 1 6 -<br />
CB<br />
O algoritmo lida com n listas enca<strong>de</strong>adas, uma para cada objeto. Na lista i,<br />
estão indica<strong>do</strong>s to<strong>do</strong>s os objetos k que aparecem em pares (i, k), isto é, sucessores <strong>de</strong> i.<br />
Para cada lista é cria<strong>do</strong> um nó-cabeça, chama<strong>do</strong> CB. No nó-cabeça da lista i, além <strong>do</strong><br />
ponteiro para os sucessores <strong>de</strong> i, está armazena<strong>do</strong> o número <strong>de</strong> pares (k, i) existentes,<br />
isto é, o número <strong>de</strong> vezes em que i aparece como sucessor <strong>de</strong> outro objeto. Essa<br />
informação é <strong>de</strong>nominada conta<strong>do</strong>r.<br />
Uma vez organizadas as listas, os nós-cabeça são percorri<strong>do</strong>s em busca <strong>de</strong> um<br />
objeto que não seja sucessor <strong>de</strong> nenhum outro, isto é, cujo campo conta<strong>do</strong>r seja nulo<br />
(zero). To<strong>do</strong>s aqueles que obe<strong>de</strong>cem tal condição, são enca<strong>de</strong>a<strong>do</strong>s pelo próprio campo<br />
conta<strong>do</strong>r, que passa a ter nova função. Em seguida, o objeto é retira<strong>do</strong> da tabela<br />
original, isto é, to<strong>do</strong>s os conta<strong>do</strong>res <strong>de</strong> seus sucessores são <strong>de</strong>crementa<strong>do</strong>s e<br />
imediatamente testa<strong>do</strong>s para que, ao chegarem a zero, sejam incluí<strong>do</strong>s na seqüência <strong>de</strong><br />
saída. O algoritmo termina quan<strong>do</strong> to<strong>do</strong>s os objetos forem retira<strong>do</strong>s.