Você está na página 1de 6

Estruturas de Informação

aula 18: Algoritmos recursivos para listas encadeadas

1 Introdução

A gente não conseguiu os ganhos de eficiência que a gente esperava com as listas encadeadas.

Quer dizer, a gente viu isso na aula passada.

Todos os algoritmos para a manipulação de listas encadeadas executam em tempo O(n).

Mesmo a busca na lista ordenada — (que executa em tempo O(log n) nos vetores)

E agora?

Bom, agora a gente pode encontrar motivação em outro lugar.

Quer dizer, tem uma observação muito legal que nós podemos fazer sobre as listas encadeadas

• Dentro de uma lista encadeada existe uma lista encadeada !

• • • ... •

Quer dizer, a coisa é recursiva.

E daı́ a gente pode utilizar estratégias recursivas para trabalhar com listas encadeadas.

Por exemplo, imagine que nós queremos imprimir uma lista encadeada.

A estratégia recursiva para fazer isso consiste no seguinte

- Para imprimir uma lista encadeada

. nós imprimimos o primeiro elemento da lista


. e depois imprimimos a lista encadeada que está dentro da lista encadeada

O código que implementa essa ideia fica assim

Algoritmo Imprime-Rec (p)


{
Se ( p = Nulo ) Retorna

Imprime ( p->val )

Imprime-Rec ( p->prox )
}

E é só isso — (apenas 3 linhas! )

1
2 Algoritmos recursivos para listas encadeadas

Certo.

Agora imagine que nós queremos imprimir a lista na ordem contrária — (i.e., começando com o
último e terminando no primeiro)

A estratégia recursiva para fazer isso é a seguinte

- Para imprimir uma lista encadeada ao contrário

. nós imprimimos a lista dentro da lista, ao contrário


. e depois imprimimos o primeiro elemento

Quer dizer, primeiro nós imprimimos do último até o segundo, e depois nós imprimimos o
primeiro elemento.

A coisa fica assim

Algoritmo Imprime-contrario-Rec (p)


{
Se ( p = Nulo ) Retorna

Imprime-contrario-Rec ( p->prox )

Imprime ( p->val )
}

Só isso!

Legal, não é?

Vejamos outros exemplos.

Exemplos

a. Busca

Imagine que nós temos uma lista encadeada

p −→ 7 • 3 • 18 • ... 5 •

E imagine que nós queremos saber se o número k está nessa lista ou não.
A estratégia recursiva de busca é a seguinte

- Para procurar o elemento k em um lista encadeada, nós

. verificamos se o primeiro elemento é o k


. se n~
ao for, nós procuramos o k no restante da lista

Abaixo nós temos o código que implementa essa ideia

2
Algoritmo Busca-Rec (p,k)
{
Se ( p = Nulo ) { Imprime ("N~
ao está lá!")
Retorna
}

Se ( p-val = k ) { Imprime ("Achei!")


Retorna
}

Busca-Rec ( p->prox, k )
}


b. A soma dos elementos

Imagine que nós temos uma lista encadeada

p −→ 7 • 3 • 18 • ... 5 •

E imagine que nós queremos calcular a soma de todos os elementos da lista.


A estratégia recursiva para fazer isso é a seguinte

- Para somar todos os elementos de uma lista encadeada

. primeiro nós calculamos a soma no restante da lista


. e depois nós adicionamos o primeiro elemento ao resultado

A coisa fica assim

Algoritmo Soma-Rec (p,k)


{
Se ( p = Nulo ) Retorna (0)

soma <-- Soma-Rec ( p->prox )

soma <-- soma + p->val

Retorna (soma)
}


c. O k-ésimo elemento

Imagine que nós temos uma lista encadeada

p −→ 7 • 3 • 18 • ... 5 •

E imagine que nós queremos imprimir o k-ésimo elemento da lista


A estratégia recursiva para fazer isso é a seguinte

3
. caso k = 1, nós imprimimos o primeiro elemento da lista
. ao, nós imprimimos o (k − 1)-ésimo elemento do restante da lista
sen~

A coisa fica assim

Algoritmo Imprime-elem (p,k)


{
Se ( p = Nulo ) Retorna

Se ( k = 1 ) Imprime ( p->val );

Sen~
ao Imprime-elem (p->prox, k-1)
}


d. Inserção no fim da lista

Imagine que nós temos uma lista encadeada

p −→ 7 • 3 • 18 • ... 5 •

E imagine que nós queremos inserir um novo elemento k no final da lista.


A intuição aqui é que na estratégia recursiva o único caso que existe é a inserção na lista
vazia.
Quer dizer,

- Para inserir o elemento k no final da lista encadeada p

. nós retornamos uma lista que só contém o elemento k,


caso a lista p esteja vazia
. ou ent~
ao nós inserimos o elemento k no final do restante da lista p

A coisa fica assim

Algoritmo Insere-final-Rec (p,k)


{
Se ( p = Nulo )
{
aux <-- Novo (RegInt)
aux->val <-- k; aux->prox <-- Nulo

Retorna(aux);
}
p->prox <-- Insere-final-Rec (p->prox, k)
Retorna (p)
}

(Note que esse algoritmo retorna um ponteiro para a lista com o novo elemento no final.)


4
e. Inserção na lista ordenada

Imagine que nós temos uma lista encadeada ordenada

p −→ 3 • 5 • 7 • ... 18 •

E imagine que nós queremos inserir um novo elemento k nessa lista.


A intuição aqui é que na estratégia recursiva o único caso que existe é a inserção na primeira
posição da lista.
Quer dizer,

- Para inserir o elemento k na lista encadeada ordenada p

. nós inserimos o elemento k na primeira posiç~


ao,
caso ele seja menor que o primeiro elemento (ou a lista esteja vazia)
. ou ent~
ao nós inserimos o elemento k no restante da lista p

A coisa fica assim

Algoritmo Insere-ordenada-Rec (p,k)


{
Se ( p = Nulo OU k < p->val )
{
aux <-- Novo (RegInt)
aux->val <-- k; aux->prox <-- p

Retorna(aux);
}
p->prox <-- Insere-ordenada-Rec (p->prox, k)
Retorna (p)
}


f. Remoção

Imagine que nós temos uma lista encadeada

p −→ 7 • 3 • 18 • ... 5 •

E imagine que nós queremos remover o novo elemento k da lista.


A intuição aqui é que na estratégia recursiva o único caso que existe é a remoção do primeiro
elemento da lista.
Quer dizer,

- Para remover o elemento k da lista encadeada p

. nós removemos o primeiro elemento de p, caso ele seja igual a k


. ou ent~
ao nós fazemos a remoç~
ao do elemento k no restante da lista p

5
A coisa fica assim

Algoritmo Remoç~
ao-Rec (p,k)
{
Se ( p = Nulo ) Retorna

Se ( p->val = k )
{
Retorna( p->prox );
}
Sen~
ao
{
p->prox <-- Remoç~ao-Rec (p->prox, k)
Retorna (p)
}
}

Você também pode gostar