Sei sulla pagina 1di 20

,~r'<

',J

,I!

,'"

I!I "

Pilha

41

push - coloca uma informao na pilha (empilha).


pop - retira uma informao da pilha (desempilha).

I
""

size - retoma o tamanho da pilha.

~'.i

stackpop - retoma o elemento superior da pilha sem remov-lo (equivalente s operaes de pop e um push).

Pilha

empty - verifica se a pilha est vazia.


"A tecnologia dominada por aqueles que
gerenciam o que no entendem:'
Arthur Bloch

A aplicao da estrutura de pilhas mais freqente em compiladores e sistemas operacionais, que a utilizam para controle de dados, alocao de variveis
na memria etc.

problema no uso de pilhas controlar o final da pilha, Isto pode ser feito
de vrias formas, sendo a mais indicada criar um mtodo para verificar se existem
mais dados na pilha para serem retirados.
Uma pilha um conjunto ordenado de itens, no qual novos itens podem ser
inseridos e a partir do qual podem ser eliminados itens de uma extremidade, chamada topo da pilha. Tambm chamada de lista linear, onde todas as inseres e
eliminaes so feitas em apenas uma das extremidades, chamada topo. A figura
3.1 mostra a representao de uma pilha.

Pilha

Tomando a pilha da figura 3.2 como exemplo, a operao push(H) ir


acrescentar um novo elemento ao topo da pilha sendo, em seguida, executado
um conjunto de operaes sobre a pilha:
2 - push(I) - Coloca o elemento I no topo da Pilha
3 - pop) - Retoma o elemento I
4 - popt) - Retoma o elemento H

Dado 05
Dado 04

6 - popt) - Retoma o elemento E

Dado 03

7 - popf) - Retoma o elemento D

Dado 02

8 - push(D) - Coloca o elemento D no topo da Pilha

Dado 01
Figura 3.1: Exemplo de Pilha

A estrutura de dados do tipo pilha tem como caracterstica que a ltima


informao a entrar a primeira a sair (LIFO - last in first out). A estrutura em
pilha tem os seguintes mtodos ou funes:

!'

:,11

1,;1

5 - popt) - Retoma o elemento F

9 - push(E) - Coloca o elemento E no topo da Pilha

:,1!

<)

Pilha 43

42 Estrutura de Dados com Algoritmos e C

de pilhas para resolver um prob~!p_~.pod~3-e._A!li~-I_o_y.~_t~!J?araarmazenar


esta pilha. Mas a pilha uma estrutura dinmica e ode crescer infinitamente,
enquanto- um vetor na inguagem C tem um tamanho fixo; contudo, pode-se definir este vetar com um tamanho suficientemente grancle para conter esta pilha.

Topo

--1 F

H
F

n.'__'

_._

_.

._

._.

~ __

... __

o
c

Figura 3.2: Operaes em uma pilha

Algoritmo 3.2: Colocar um item na pilha (funo PUSH(S,x))


Input: Pilha (8) e o item a ser includona pilha (x)
Output: No tem retorno
1 begin
2
topo de 8<-- topo de 8 + 1
3
8(topo de 8)<-- x
4
return
5 end

3.1 Representao das Operaes com Pseudo-cdigo


As operaes de pilha podem ser representadas com algumas linhas de pseudo-cdigo. Os algoritmos empty (3.1), push (3.2), pop (3.3), stackpop (3.4) e
size (3.5) demonstram as operaes numa pilha. Estes cdigos podem ser adaptados para qualquer linguagem de programao [9].

Algoritmo 3.3: Retirada de um item da pilha (funo POP(S)

2
3

Algoritmo 3.1: Verificaose a pilha est vazia (funo EMPTY(S))

Input: A varivelque contm a pilha (8)


Output: Verdadeiroou falso
1 begin
2
if topo de S = O then
3
I return true
4
else
5
I return false
6
endif
7 end

6
7

Antes de programar a soluo de um problema que usa uma pilha, necessrio determinar como representar uma pilha usando as estruturas de dados
existentes na linguagem de programao. Uma pilha um conjunto ordenado de
itens, e a linguagem C j contm um tipo de dado que representa um conjunto
ordenado de itens: o vetor. Ento, sempre que for necessrio utilizar a estrutura
---------

~~

j!

Algoritmo 3.4: Pega o item do topo da pilha mas no desempilha (funo


STACKPOP(S)

3.2 Pilhas em C

Input: Pilha (8)


Output: Item que est no topo da pilha
begin
if EMPTY(S) then
Erro elepilha vazia
else
I topo de 8<-- topo de 8 -.1
return 8(topo de 8 + 1)
endif
end

Input: Pilha (8)


Output: Item que est no topo da pilha
1 begin
2
if EMPTY (S) then
3
I Erro de pilha vazia
4
else
5
return 8(topo de 8)
6
endif
7 end

"

Pilha
44

Algoritmo

3.5: Tamanho da pilha (funo SIZE(S))

Input: A varivel que contm a.pilha (S)


Output: Quantidade de itens da pilha (topo de S)
1 begin
2
return topo de S
3 end

programa 3.1 apresenta um exemplo de programa em C para manipulao de pilhas.


Programa
/*programa-pilha_Ol.c
3

33

int stacktopO /" retoma o topo da pilha sem desempilbar */


(

retum pilha[posl;
}
38

int main(int argc, char **argv )


(
printf(" \nColocados
dados na pilha

*/

43 I push(2)j
push(3)j
printf("\nTamanho

13 I

da pilha

48 I printf("\npegando

dado
dado
dado

printf("\npegando
printf(" \nPegando

I #include -cstdio.h

int pilha[20]j
int pos-O,

")j

pushf I);

3.1: Exemplo de manipulao de pilha

void push(int valor);


int popfvoid);
int size/void);
8 I int stacktoptvoid);

53

printf("\nTamanho
I retum o,

%d", sizeO)j

da pilha:
da pilha:
da pilha:

da pilha

%d", pop),
%d", popO)j
%d", pop),

%d", sizeO)j

Uma pilha em C podeser declarada como uma estrutura contendo dois objetos: um vetor para armazenar os elementos da pilha e um inteiro para indicar a
posio atual do topo da pilha (programa 3.2).

void push(int valor)

Programa

pilha[pos]=valorj
/" Empilha um novo elemento. No verifoada a capacidade
mxima da pilha. */
pos++j
rerurn;

*/

#include -cstdio.h
#include -cstdlib.h>
#define TAMANHO_PILHA 100

int popt)
/" Retoma o elemento do topo dafilha. No uerificado
ofinal da pilha. */
retum (pilhaj=posl),

3.2: Exemplo de manipulao de pilha com estrutura

/* plograma-pilha_02.c

/" Estrutura que ir conter a pilha de informaes */


struct pilha

23 I (

int topo,
int itens[TAMANHO_PILHA]j

10 I

}j

i~.

45

Estrutura de Dados com Algorionos e C

28

int sizet)
retum pOSj1* retoma o topo da pilha */
}

int empty(struct pilha *p)


15 I {

if( p-c-topo == -1

Pilha

46 .Estrutura de Dados com Algoritmos e C

65

47

pushtcx.Z);

push(&x,3)j

return L;
}
20 I

printf(" \nTamanho
printf("\nElemento

return Oj

da pilha
do topo

%d", size(&xj
da fila %d",stackp0p(&xj

70

int pop(struct pilha .p)


(
25 I
if( empty(p) )
{
printf(" \nPilha
vazia ")j
exit(l)j
}
30 I
/" retoma o item da pilha atual e diminui a posio da pilha */
retum (p-c-itensjp-c-topo=j);

75

printf("\n%d",
printf("\n%d",
printf("\n%d",
printf("\n%d",
return O;
}

pop(&xj
pop(&xj
pop(&xj
pop(&xj

3.3 Exerccios
void push(struct pilha "p, int e)
35 I {

if( p->topo :: (TAMANHO_PILHA

- 1

printf("\nEstouro

da pi Lha ");

exitf l);

}
I" aps oerificar se no baueria estouro na capacidade da pilha,
criada U11to noua posio na pilha e o elemento armazenado */

40

p-c-itensj=-Ip-c-topoj]

: e;

1. Dada uma pilha P, construir uma funo que inverte a ordem dos elementos dessa pilha, utilizando apenas uma estrutura auxiliar. Definir
adequadamente a estrutura auxiliar e prever a possibilidade da pilha
estar vazia.
2. Construir uma funo que troca de lugar o elemento que est no topo
da pilha com o que est na base da pilha. Usar apenas uma pilha como
auxiliar.

return,
45

int size(struct pilha 'p)


(

/" sempre lembrando que na linguagem C o ndice de um


uetor comea na posio O */
retum p-c-ropo-L;

50 I

int stackpop(struct pilha "p)


55 I (

retum p-c-itensjp-stopo],

int main(void)
60 I {

struct pilha x;
x.topo -I,
pushtcx.l);

3. Dada uma pilha contendo nmeros inteiros quaisquer, construir uma


funo que coloca os pares na base da pilha e os mpares no topo da
pilha. Usar duas pilhas como auxiliares.

,c:,. ,-

Fila

49

~I !

1'.1
11

Tomando a fila da figura 4.1 como exemplo, o item a apresenta a fila no seu
estado inicial e executado o conjunto de operaes:

; '!

,i
i

dequeuet) - Retoma o item

A (a fila resultante representada pelo

item B)

11 Fila

enqueue(F) - O item F armazenado ao final da fila (a fila resultante


representada pelo item C)

"A sutileza do pensamento consiste em


descobrir a semelhana das coisas diferentes
e a diferena das coisas semelhantes:'
Charles de Montesquieu

dequeuet) - Retirado o item B da fila

enqueue(G) - Colocado o item G ao final da fila (item D)

-,

"-

Incio

a)ln~
b)

____ J~----

Final

Final

Uma fila um conjunto ordenado de itens a partir do qual se podem eliminar itens numa extremidade - incio da fila - e no qual se podem inserir itens na
outra extremidade - final da fila.
Ela uma prima prxima da pilha, pois os itens so inseridos e removidos
de acordo com o princpio de que o primeiro que entra o primeiro que sai - first in,
first out (FIFO).

conceito de fila existe no mundo real, vide exemplos como filas de banco,
pedgios, restaurantes etc. fu operaes bsicas de uma fila so:

insert ou enqueue - insere itens numa fila (ao final).

<,

"-

"Inicio

-,

Inicio

d)

c)

Final

Final

"-

Figura 4.1: Operaes numa fila

4.1 Representao de Filas com Pseudo-cdigos

remove ou dequeue - retira itens de uma fila (primeiro item).


empty - verifica se a fila est vazia.
size - retoma o tamanho da fila.
front - retoma o prximo item da fila sem retirar o mesmo da fila.
A operao insert ou enqueue sempre pode ser executada, uma vez que
teoricamente uma fila no tem limite. A operao remove ou dequeue s pode
ser aplicado se a fila no estiver vazia, causando um erro de underfiow ou fila vazia
se esta operao for realizada nesta situao.

fu operaes em fila podem ser representados com os seguintes blocos de


cdigo: a operao enqueue (4.1), dequeue (4.2), empty (4.3), size (4.4) e front
(4.5). Estes cdigos podem ser adaptados para qualquer linguagem de programao [9].

50

Fila

Estrutura de Dados com Algoritmos e C

Algoritmo

Algoritmo

4.1: Incluso de dados na fila (ENQUEUE(Q,x

Input: A varivel que contm a fila (Q) e o elemento a ser colocado na fila (x)
Output: Sem retorno
1 begin
2
Q[ fim de Q]<-- x
3
if final de Q = comprimento de Q then
4
fim de Q<-- 1
5
return
6
else
7
Q[ fim de Q]--- fim de Q + 1
8
return
9
endif
10 end

4.4: Tamanho da fila (funo SIZE(Q

Input: A varivel que contm a fila (Q)


Output: Quantidade de itens da fila
1 begin
2 I return
fim de Q
3 end

Algoritmo

1
2

3
4

Algoritmo

4.5: Prximo elemento da fila (funo FRONT(Q

Input: A varivel que contm a fila (Q)


Output: Prximo elemento da fila (mas sem retirar da fila)
begin
I x --- Q[ inicio de Q ]
return :c
end

4.2: Retirada de dados na fila (DEQUEUE(Q

Input: A varivel que contm a fila (Q)


Output: O elemento representado por na fila Q
1 begin
2
x <-- Q[ inicio de Q]
3
if incio de Q = comprimento de Q then
4
I Inicio de Q<-- 1
5
else
6
I Inicio de Q<-- Inicio de Q + 1
7
endif
8
return x
9 end

4.2 Filas em C
A exemplo do que ocorre com estrutura em pilha, antes de programar a
soluo de um problema que usa uma fila, necessrio determinar como representar uma fila usando as estruturas de dados existentes na linguagem de programao. Novamente na linguagem C podemos usar um vetor, Mas a fila
uma estrutura dinmica e pode crescer infinitamente, enquanto que um vetor na
linguagem C tem um tamanho fixo. Contudo, pode-se definir este vetor com um
tamanho suficientemente grande para conter a fila. No programa 4.1 apresentado um exemplo para manipulao de filas.
Programa

Algoritmo

1
2
3
4

5
6
7

51

4.1: Exemplo de manipulao de fila em C

4.3: Verificao se a fila est vazia (funo EMPTY(Q)

Input: A varivel que contm a fila (Q)


Output: Verdadeiro ou falso
begin
if Inicio de Q = Fim de Q then
I return true
else
I return false
endif
end

/: programa fila

l,c */

#include -csrdio.h
3 I #include -cstdlib.h
#define TAMANHO_MAXIMO

100

struct queue
8 I{

int itens[TAMANHO_MAXIMO];
int front,rear;
};
13 I int empty(struct

queue * pq)

.1

Estrutura de Dados com Algorionos e C

52

Fila 53

i
I

I;

/" se o incio da fila for igual aofinal da fila, a fila est vazia
if( pq-sfront
{

"
18I

63 I int main(void)

== pq->rear )

retum 1;
}
retumO;

68 I

"

void enqueue(struct
23

*j

queue * pq, int x)

I(
if( pq->rear + 1 >= TAMANHO_MAXIMO)
(
printf(" \nEstouro
da capacidade
exit(l);

28 I

73
da

fila ,,);

}
pq-c-itens] pq->rear++ ] = x;
78

retum;
}
33

I int size(struct queue * pq)


{
retum (pq-srear + 1);

38 I int front(struct

queue

83

* pq)

(
/" o primeiro elemento sempre est no incio do vetar
retum pq-sitensj]:

*j

43

int dequeue(struct
(
int x, i;
if( empty(pq) )
48

queue * pq)

printf(" \nFila
vazia
printfi " \nTamanho
da
printf("\nProximo
da
printf("\nTirando
da
printf("\nTirando
da
printf("\nTirando
da
printf("\nProximo
da
printf("\nTirando
da

%d",
fila
fila
fila
fila
fila
fila
fila

printf(" \nFila

%d", empty(&q;

vazia

No programa 4.1, o vetor foi definido para comportar apenas 100 elementos, caso fosse inserido um 101.Qelemento, haveria o estouro da pilha mesmo
aps vrias operaes de dequeue. Para resolver este problema, na operao
dequeue foi implementada uma tcnica de redistribuio dos elementos na fila,
de tal forma que nunca se chegue a estourar a fila caso haja vrias operaes de
insero ou remoo (exceto se realmente houver 100 elementos da fila e houve
uma tentativa de insero de um novo elemento). O programa 4.2 o trecho que
implementa a tcnica comentada:
Programa 4.2: Reajuste da fila

")j

:}
/" Salva o primeiro elemento e rejaz o arranjo dos itens, puxando o segundo elemento
para oprimeiro, o terceiro para o segundo e assim sucessivamente . j
x = pq->itens[O];
for( i=O; i < pq->rearj i++)

vazia

empty(&q;
%d", size(&q;
%d", front(&q;
%d", dequeuercqj):
%d", dequeuercqj):
%d", dequeuefrqj);
%d", front(&q;
%d", dequeuetcqj);

printf(" \n ,,);

(
printf(" \nFila
exit(l);

53

struct queue q;
q.front = O; q.rear = O;
enqueue(&q,l);
enqueue(&q,2);
enqueue(&q,3);
enqueue(&q,4);

x = pq-c-itensj]:
for( i=O; i < pq->rear; i-)
{
pq-c-itensji] = pq-sirensli-I]:
5 I}
pq->rear--;

pq-e-irensji] = pq-c-itensli-I];
58

}
pq->rear--;

retumx;

Esta tcnica ineficiente, pois cada eliminao da fila envolve deslocar cada
elemento restante na fila. Se uma fila contiver 1000 ou 2000 elementos, cada elemento retirado da fila provocar o deslocamento de todos os demais elementos.
A operao de remoo de um item na fila deveria logicamente trabalhar somen-

54

Fila

Estrutura de Dados com Algoritmos e C

te com aquele elemento, permanecendo


originais.

os demais elementos em suas posies

A soluo para o problema definir o vetor como um crculo, em vez de


uma linha reta. Neste caso, os elementos so inseridos como numa fila reta, e
a remoo de um elemento da fila no altera os demais elementos da fila. Com
o conceito de fila circular, ao chegar ao final da fila, o ponteiro de controle da
fila vai imediatamente para o incio da fila novamente (se este estiver vago). As
seguintes operaes exemplificam a explicao (acompanhar o desenvolvimento
da fila na figura 4.2), sendo o caso 1 o estado inicial da fila:

1)

55

2)
3)

4)

6)

1. Estado inicial
2. enqueue(D) - O item D armazenado ao final da fila
3. enqueue(E) - O item D armazenado ao final da fila
4.

5.

dequeuet) - Retirado o item A da fila

enqueue(F) - O item F armazenado ao final da fila

8)

9)

enqueue(G) - O item G armazenado ao final da fila


6. dequeuet) - Retirado o item B da fila

7. enqueue(H) - O item H armazenado ao final da fila. Neste momento, o


ponteiro da fila chegou ao final do vetor que contm a implementao
da fila.
8.

dequeuet) - Retirado o item C da fila

enqueue(I) - O item I armazenado ao final da fila (mas no incio


do vetor)
9.

enqueue(K) - O item K armazenado ao final da fila (mas na segunda


posio do vetor)

Figura 4.2: Operaes numa fila circular

Desta forma, as funes de manipulao de fila (empty, enqueue, dequeue,


size e front) devem sofrer modificaes para refletir a nova condio de fila circular (programa 4.4):

O programa 4.3 mostra a declarao da estrutura para uma fila circular.


Programa

Programa
/" plograma.fila_02.c
#include -cstdio.h
#include -cstdlib.h

4.3: Declarao de estrutura circular

#define TAMANHO_MAXIMO

100

struct queue

4.4: Manipulao de fila circular em C

*I

5 I #defineTAMANHO_MAXIMO

4 I{

int itens [TAMANHO_MAXIMO]i


int front.rear;

};
struct queue qi
I q.front= q.rear=-1

10

struct queue
{
int itens[TAMANHO_MAXIMO]i
I int front.rear;
}i

10

Fila
56

Estrutura de Dados com Algoritmos e C


retum pq->itens[pq->front+l];

int empty(struct queue * pq)

if( pq-sfront

15

==

pq->rear )

return 1;

int dequeue(struct queue * pq)


65 I (

int x, i;
if( empty(pq) )

return O;

20

void enqueue(struct queue * pq, int x)

printf(" \nFila
exitrl);

70

vazia ,,);

(
25 I

/" Inverso das posies dos ponteiros. Se ofinal do uetor j foi


alcanado, ento retorno-se ao incio do vetor */
if( pq->rear == TAMANHO_MAXIMO-l)
{

/" Inverso das posies dosponteiros. Se ofinal do uetor j foi alcanado,


ento retoma-se ao incio do vetor *I
if( pq-e-front == TAMANHO_MAXIMO - 1)
{
pq-sfront = O;
}
e1se
{
pq-c-front-+;
}
return (pq-e-itens]pq-e-front J);

75

pq->rear = O;
}
30

I else
{
pq->rear++;

80

35

40

if( pq->rear == pq-c-front)


(
I
printf(" \nEstouro
da fila");
exit(I);

85

int main(void)

pq-c-itensjpq-c-rear]= x;
return;

90

45

50

'.~.

55

int size(struct queue * pq)


(
I
/" se ofinal da fila ainda no alcanou ofinal do vetor... *I
if( pq-sfront <= pq-srear)
{
return pq->rear - pq-c-front;/" ... ento o tamanho da fila ofinal
da fila menos o incio da fila... */
I}
/" ... se no, quer dizer que oponteiro definal da fila j alcanou ofinal do vetor
efoi reposicionado para o incio do vetar, ento o tamanho da fila a quantidade
de itens que ainda restam at chegar aofinal do vetor somando itens que esto
no incio do vetor */
return pq->rear + pq-c-front;

95

100

105

60

int front/struct queue * pq)


I(

struct queue q;
q.front = -1;
q.rear = - 1;
enqueue(&q,l);
enqueue(&q,2);
enqueue(&q,3);
enqueue(&q,4);
printf(" \nTamanho
printf(" \nProximo
printf("\nTirando
printf(" \nTirando
printf(" \nTirando
printf("\nProximo
printf("\nTirando
printf(" \nTamanho
enqueue(&q,5);
enqueue(&q,6);
enqueue(&q,7);
enqueue(&q,8);

da
da
da
da
da
da
da
da

fila
fila
fila
fila
fila
fila
fila
fila

%d", size(&q));
%d", front(&q));
%d", dequeue(&q));
%d", dequeue(&q));
%d", dequeue(&q));
%d", front(&q));
%d", dequee(&q));
%d", size(&q));'
.
.

57

Ij
58

Fila

Estrutura de Dados com Algoritmos e C

110 1

115 1

enqueue(&q,9)j
printf("\nTamanho
printf("\nProximo
printf("\nTirando
printf("\nTirando
printf(" \nTirando
printf("\nTirando
printf(" \nproximo
printf("\nTirando
printf(" \nTamanho
enqueuefcq.l

120 1

da
da
da
da
da
da
da
da
da

fila
fila
fila
fila
fila
fila
fila
fila
fila

%d", size(&qj
%d", front(&qj
%d", dequeuetcqj),
%d", dequeuefcqj);
%d", dequeuefcqj),
%d", dequeuecql),
%d", front(&qj
%d", dequeuetcqj):
%d", size(&qj

160 1

printf(" \nTirando
printf("\nTirando
printf(" \nTamanho
printf("\nTirando
printf(" \nTamanho
printf("\nTirando
printf(" \nTamanho
printf("\nFila

da
da
da
da
da
da
da

vazia

fila
fila
fila
fila
fila
fila
fila

59

%d", dequeuecqj),
%d", dequeue/cql),
%d", size(&qj
%d", dequeuefcqj);
%d", size(&qj
%d", dequeue/cqj);
%d", size(&qj

%d", empty(&qj

165

printf("\n")j
return o,

O),

enqueue(&q,II)j
enqueuefeq.l),
enqueuetcq.B),

enqueue/Scq.H);
enqueuecq.lS):
125 1

130 1

1351

140 1

4.3 Exerccios

enqueuefcq.I);
enqueue/cq.l Z),

enqueue(&q,18)j
printf(" \nTamanho
printf(" \nProximo
printf("\nTirando
printf("\nTirando
printf("\nTirando
printf("\nTrando
printf("\nTirando
printf(" \nProximo
printf("\nTirando
printf("\nTirando
printf("\nTirando
printf(" \nTamanho
printf(" \nTirando
printf("\nTamanho
printf(" \nFila

da
da
da
da
da
da
da
da
da
da
da
da
da
da

vazia

fila
fila
fila
fila
fila
fila
fila
fila
fila
fila
fila
fila
fila
fila

%d", size(&qj
%d", front(&qj
%d", dequeuecqj);
%d", dequeuetcqj);
%d", dequeuefcqj);
%d", dequeuefcqj):
%d", dequeuercqj);
%d", front(&qj
%d", dequeuetcqj):
%d", dequeuetcqj):
%d", dequeuetcqj),
%d", size(&qj
%d", dequeuefcqj);
%d", size(&qj

%d", emptytcqj);

enqueuetcq.Z);
enqueuercq.Zl),
enqueueicq.Z),
enqueuefcq.Z);
150 1

j'

i
I-

1\

155

enqueue(&q,24)j
enqueue(&q,25)j
printf("\nTamanho
printf(" \nProximo
printf("\nTirando
printf(" \nProximo
printf("\nTirando

da
da
da
da
da

fila %d", size(&qj


fila %d", front(&qj
fila %d", dequeuecqj),
fila%d", front(&qj
fila %d", dequeuetcqj);

1. Se um vetor armazenando uma fila no considerado circular, O texto sugere que cada operao dequeue deve deslocar para baixo todo
elemento restante de uma fila. Um mtodo alternativo adiar o deslocamento at que rear seja igual ao ltimo ndice do vetor. Quando
essa situao ocorre e faz-se uma tentativa de inserir um elemento na
fila, a fila inteira desloca da para baixo, de modo que o primeiro elemento da fila fique na posio O do vetor. Quais so as vantagens desse
mtodo sobre um deslocamento em cada operao dequeue? Quais as
desvantagens? Reescreva as rotinas dequeue, queue e size usando esse
mtodo.
2. Faa um programa para controlar uma fila de pilhas.

Recursividade

5.1.

Funo para clculo de Fatorial

Na linguagem C, as funes podem chamar a si mesmas. A funo recursiva se um comando no corpo da funo a chama. Para uma linguagem de computador ser recursiva, uma funo deve poder chamar a si mesma. Um exemplo
simples a funo fatorial, que calcula o fatorial de um inteiro. O fatorial de um
nmero N o produto de todos os nmeros inteiros entre 1 e N. Por exemplo,
3 fatorial (ou 3!) 1 * 2 *3 = 6. O programa 5.1 apresenta uma verso
iterativa para clculo do fatorial de um nmero.

11 Recursividade

Programa
"E no sabendo que era impossvel, foi l e fez:'
Jean Cocteau

I 1

~:

61

Recurso O processo de definir algo em termos de si mesmo e , algumas


vezes, chamado de definio circular. Assim, pode-se dizer que o conceito de
algo recursivo est dentro de si, que por sua vez est dentro de si e assim sucessivamente, infinitamente,
a seguir define o ancestral de uma pessoa:

Os pais de uma pessoa so seus ancestrais (caso base);


Os pais de qualquer ancestral so tambm ancestrais da pessoa inicialmente considerada (passo recursivo).
Definies como estas so normalmente encontradas na matemtica. O
grande apelo que O conceito da recurso traz a possibilidade de dar uma definio finita para um conjunto que pode ser infinito [15]. Um exemplo aritmtico:
O primeiro nmero natural zero.
O sucessor de um nmero natural um n'TIero natural.
Na computao o conceito de recursividade amplamente utilizado, mas
difere da recursividade tpica por apresentar uma condio que provoca o fim do
ciclo recursivo. Essa condio deve existir, pois, devido s limitaes tcnicas que
o computador apresenta, a recursividade impedida de continuar eternamente.

5.1: Fatorial (verso iterativa)

int fatorialc ( int n )


int t, f;

o exemplo

61

f=l;
for (r = 1; t<=n; t++)
f=f*t
return f;

Mas multiplicar n pelo produto de todos os inteiros a partir de n-1 at 1


resulta no produto de todos os inteiros de n a 1. Portanto, possvel dizer que
fatorial:
O! = 1

l!=l*O!

2!=2*1!
3! = 3 * 2!
4!=4*3!
Logo o fatorial de um nmero tambm pode ser definido recursivamente (ou
por recorrncia) atravs das seguintes regras (representao matemtica) [15, 1]:
n!

= 1, se n = O

n!=n*(n-1)!,sen>O
O programa 5.2 mostra a verso recursiva do programa fatorial.

62

Recursividade

Estrutura de Dados com Algoritmos e C


Programa 5.2: Fatorial (verso recursiva)

int fatorialr( int n)


I(
int t, f;
1* condio de parada *j
if( n == 1 I I n == O)
(

return 1;

f = fatorialr(n-l)*n; /" chamada da funo *j


return f;

A verso no-recursiva de fatorial deve ser clara. Ela usa um lao que
executado de 1 a n e multiplica progressivamente cada nmero pelo produto
mvel.
A operao de fatorial recursiva um pouco mais complexa. Quando fa chamada com um argumento de 1, a funo devolve 1. Caso contrrio, ela devolve o produto de fatorialr (n-l) *n. Para avaliar essa expresso, fatorialr chamada com n-1. Isso acontece at que n se iguale a 1 e as
chamadas funo comecem a retomar.
torialr

Calculando ofatorial de 2, a primeira chamada a fatorialr provoca uma


segunda chamada com o argumento 1. Essa chamada retorna 1, que , ento,
multiplicado por 2 (o valor original e n). A resposta ento 2.
Para melhor entendimento, interessante ver como o programa executado internamente no computador. No caso do programa iterativo (programa
5.1) necessrio duas variveis f e t para armazenar os diversos passos do
processamento. Por exemplo, ao calcular fatorial de 6, o computador vai passar
sucessivamente pelos seguintes passos (tabela 5.1).
Tabela 5.1: Clculo de fatorial de 6
t

24

120

720

63

No programa recursivo (5.2) nada disto acontece. Para calcular o fatorial de


6, o computador tem de calcular primeiro o fatorial de 5 e s depois que faz a
multiplicao de 6 pelo resultado (120). Por sua vez, para calcular o fatorial de 5,
vai ter de calcular o fatorial de 4. Resumindo, aquilo que acontece internamente
uma expanso seguida de uma contrao:
fatorialr(6)
6 * fatorialr(5)
6 * 5 * fatorialr(4)
6 * 5 * 4 * fatorialr(3)
6 * 5 * 4 * 3 * fatorialr(2)
6 * 5 * 4 * 3 * 2 * fatorialr(l)
6 * 5 * 4 * 3 * 2 * 1
6 * 5 * 4 * 3 * 2
6 * 5 * 4 * 6
6 * 5 * 24
6 * 120
720

Quando uma funo chama a si mesma, novos parmetros e variveis locais


so alocados na pilha e o cdigo da funo executado com essas novas variveis.
Uma chamada recursiva no faz uma nova cpia da funo; apenas os argumentos so novos. Quando cada funo recursiva retoma, as variveis locais e os
parmetros so removidos da pilha e a execuo recomea do ponto da chamada
funo dentro da funo.

5.2 Nmero triangular


Pitgoras, matemtico e filsofo grego, demonstrou vrias propriedades
matemticas, entre elas a propriedade dos nmeros triangulares. Um nmero
triangular um nmero natural que pode ser representado na forma de tringulo
equiltero. Para encontrar o n-simo nmero triangular a partir do nterior basta
somar-lhe 11 unidades. Os primeiros nmeros triangulares so 1,3,6, 10, 15,21,
28. O n-simo termo pode ser descoberto pela frmula a seguir:
n

T" = Lk=lk=1+2+3+

... +(n-2)+(n-1)+n=

110+0
_

[17]

64

Estrutura de Dados com Algoritmos e C

Recursividade
Programa

Estes nmeros so chamados de triangulares pois podem ser visualizados


como objetos dispostos na forma de um tringulo (figura 5.1).

= 1 componente

2=3

a
00

OElEl
[180m
E1E1m0B
5 = 15

int iTotal = O;
while( n > O )

4 I

EI
13

E!
ElE!

E111J

BI1J
OOB

iTotal += n;

ElBB
El00E!

3=6

n--;

10

}
9

[]

e
0m
Dom

GElO

El8ElEl
08080

E1BElIIlO

OOElIJGO

OIJOODElEl

00

I return iTotaI;
}

E!OSB

Este um processo recursivo [8] (figura 5.3) , pois:

000El00

6 = 21

1. Primeira coluna tem n elementos.

7 = 28

'2. Soma-se a prxima coluna com n-1 elementos at que reste apenas 1
elemento.

Figura 5.1: Nmeros triangulares

Supondo que se esteja buscando o quinto elemento (dado pelo nmero 15),
como descobrir este elemento? Basta distribuir entre aslinhas e colunas conforme a figura 5.2 (5+4+3+2+1 = 15).

1--1
IlWlli,
I L::!j I

I I: "
I I: "
lu.ttIl ~

Ir;;wll~

I~I
II!1I r--I
I
11

I@JII~

1111:11l/Ij: 11--1
II~ ... 11128'"
II~.~
~(IIIi!i'/I
.1,; II
1 ..... 1'''' .. 11'" 11--'

:I

"

If@ fm', -,

nas colunas
restantes

____________

5 na primeira
coluna
Total: 15 componentes

1 nesta coluna

Figura 5.3: Descobrindo o quinto elemento triangular de forma recursiva


2 nesta coluna
4 nesta coluna
5 nesta coluna
Total: 15 componentes

o programa

5.4 implementa a soluo recursiva do problema. A figura 5.4


dernostra o que ocorre a cada chamada da funo triangulo, nela pode ser observado o retorno de cada execuo da funo.

Figura 5.2: Descobrindo o quinto elemento triangular

Programa

I :''

Este um processo repetitivo, dado por um programa simples (programa


5.3).

fU,J'
I!!J "

11

-1-'------l------~~
I

3 nesta coluna

I~I:~ ~
:

1
I
II
"
II
I
1~11r;;liil11'iil11'W11
ItmlJlll:!!iJll~ll~
r-I
1I
1I
11
1I I I
'1iil'1IIrom"~'I~',Wiil
IffiJllt:!!!.IlllEJlle2Jllll2j:

T'-(LL.

:~::~ ~ Ij]'"

~n' t , J

-,

1f?111f1F;1]

r-I

5.3: Descobrindo o nmero triangular (iterativo)

int triangulo(int n)

g)
1 linha

65

trianguloint o)
if( n == 1)

5.4: Descobrindo o nmero triangular (recursivo)

66

Recursividade

Estrutura de Dados com Algoritmos e C


Programa
returnn;

67

5.5: Clculo do n-simo termo de Fibonacci (verso iterativa)

int fibc(int n)

2 I(

return n + triangulo(n-I);

int I,h, x, i;
if( n <= 2)
return I;
1 = O;

Chamando a funo
triangulo com n=S

Primeira chamada

i------------n;5-

,,
,,
,,
,,

-- ---

h=1;

-- -- ----:

~'I
~I

'I~~tl
,:;I

,
,
,
,

for(i=2; i<= n; i++)


{
r Clculo do prximo nmero da seqncia. */
x=l;
1= h;
12

h =x + I;
}
return h;

~~~.

:g:

,,

ti'::

,,

I~,

:h:
t,,

u~I
f<.(

:~.::

o n-simo nmero definido como sendo a soma dos dois nmeros anteriores. Logo, fazendo a definio recursiva:

~~!;:

li'..:
I~'~I

'~'

hcl
1''
f~~1

..
__ I)~ I

~~,;1:-:
I
I

il

:J

fib(n)

n se n

fib(n)

= fib(n-2)

<=

+ fib(n-l) se n > 2

A sua determinao recursiva impe o clculo direto do valor para dois elementos de base (a primeira e a segunda gerao). No programa 5.6 mostrada a
verso recursiva para calcular o n-simo termo da seqncia de Fibonacci.

Soma 5

Programa

ROlorna 15

int fibr( int n )

Retorna 15

Figura 5.4: O que ocorre a cada chamada

5.3 Nmeros de Fibonacci


Fibonacci (matemtico da Renascena italiana) estabeleceu uma srie curiosa de nmeros para modelar o nmero de casais de coelhos em sucessivas geraes. Assumindo que nas primeiras duas geraes s existe um casal de coelhos, a
seqncia de Fibonacci a seqncia de inteiros: 1, 1,2,3,5,8,
13,21,34, ....
No programa 5.5 mostrada uma verso iterativa para calcular o rr-simo
termo da seqncia de Fibonacci.

5.6: Clculo do n-simo termo de Fibonacci (verso recursiva)

if( n <= 2)
4 I

return I;
}
/" chama a si prprio 2 vezes.'.'.' */
return fibr(n-I) + fibr(n-2);
9 I}

Esta soluo (programa 5.6) muito mais simples de programar do que


a verso iterativa (programa 5.5). Contudo, esta verso ineficiente, pois cada
vez que a funo fibr chamada, a dimenso do problema reduz-se apenas uma
unidade (de n para n-l), mas so feitas duas chamadas recursivas. Isto d origem
a uma exploso combinatorial e o computador acaba por ter de calcular o mesmo
termo vrias vezes.

68

Estrutura de Dados com Algoritmos e C

Recursividade

Para calcular fibr (5) necessrio calcular fibr (4) e fibr (3) . Conseqentemente, para calcular fibr (4) preciso calcular fibr (3) e fibr (2) . E assim sucessivamente. Este tipo de processamento inadequado, j que o computador
obrigado a fazer trabalho desnecessrio. No exemplo, usando o programa 5.6, para
calcular fibr (5) foi preciso calcular fibr (4) 1 vez, fibr (3) 2 vezes, fibr (2) 3
vezes e fibr (1) 2 vezes. No programa iterativo (programa 5.5), apenas era necessrio calcular fibc (5) , fibc ( 4 ) , fibc (3) , fibc (2) e fibc (1) 1 vez. A figura 5.5
demonstra como ficaria a chamada do programa 5.6 para clculo do stimo termo.

5.1: Algoritmo de Euclides

AIgoritmo

2
3

Input: Me N
Output: MDC calculado
begin
r <-- resto da diviso m por n
while r "" O do

m<--n

Il<--r

return

8
9

<--

resto da diviso m por n

endw

n;

end

Programa
1

5.7: Clculo do MDC iterativo

I #include -estdio.h
int mdc(int m, int n)

int r;
whiIe( m % n != O)

Figura 5.5: Clculo de Fibonacci recursivo para o stimo termo

r e rn % n;
m e n;
n e r;
11

5.4 Algoritmo de Euclides

retumn;

algoritmo de Euclides busca encontrar o mximo divisor comum (MDC)


entre dois nmeros inteiros diferentes de zero. O procedimento simples:

int main(void)
16 I (

1. Chame o primeiro nmero de

e o segundo nmero de

n;

printf(" 6 O, 36
printf(" 3 6, 24
retum O;

2. Divida m por n e chame o resto de r;


3. Se r for igual a zero, ento o MDC
no o procedimento continua;

e o procedimento

termina, se

4. Atribua n para m e r para n;


5. Recomece o procedimento

%d\n", mdc(60,36;
%d\n", mdc(36,24;

do segundo passo.

Estes passos podem ser descritos conforme o algoritmo 5.1.


No programa 5.7 vista uma verso iterativa do algoritmo de Euclides para
clculo do MDC.

o programa

5.8 implementa o algoritmo ele Euclides de forma recursiva.


Programa

#include -csrdio.h
int mdc(int m, int n)
5 I(
if( n == O)

5.8: Clculo do MDC recursivo

69

)
70

Recursividade

Estrutura de Dados com Algoritmos e C

return

I /eturn

m;

71

O;

return rndc(n, rn % n);

5.5 Torres de Hanoi

lO

int rnain(void)
(
printf(" 6 O, 36
printff" 3 6, 24
return O;

%d\n", rndc(60,36;
%d\n", rndc(36,24;

MDC entre dois nmeros rn e n tambm um divisor da sua diferena,


m-n. Por exemplo: o MDC de 60 e 36 12, que divide 24 = 60-36. Por outro
lado, o MDC dos dois nmeros m e n ainda o MDC do menor nmero (n) com
a diferena (m-n). Se houvesse um divisor comum maior, ele seria igualmente
divisor de n, contrariamente hiptese. Portanto, possvel determinar o MDC
de dois nmeros atravs da determinao do MDC de nmeros cada vez menores. O programa termina quando os nmeros forem iguais e, neste caso, o MDC
este nmero. Exemplo: 60-36 = 24; 36-24 = 12; 24-12 = 12; 12 = 12. No programa 5.9 vista um.a verso do programa MDC utilizando os passos descritos
(m sempre tem que ser maior que n).
Programa

5.9: Clculo do MDC recursivo

#include -cstdio.hs
int rndc(int rn, int n)
{
4 I

if( rn == n)
{

return

m;

}
if( rn-n >= n)
9 I

No grande templo de Benares, embaixo da cpula que mana o centro do mundo,


repousa uma placa de lato onde esto pnsas trs agulhas de diamante, cada uma com 50
C711.
de altura e com espessura do C0110de uma abelha. Em uma dessas agulhas, durante a
criao, Deus colocousessenta e quat1'o discos de OU1'0PU1'0,com o disco maior repousando
sobre a placa de lato e os outros diminuindo cada vez mais ate o topo. Essa a t01'1'ede
Brabma. Dia e noite, sem parar; os sacerdotes transferem os discos de uma agulba de
diamante para outra de acordo com as leisfixas e imutveis de Brabma, que exigem que
o sacerdote em viglia no mova mais de um discopOl' vez e que ele coloque este disco em
uma agulba de modo que no haja nenhum disco menor embaixo dele. Quando os sessenta e quat1'o discos tiverem sido assim transferidos da agulha em que a criao de Deus as
colocoupam uma das outras agulhas, a torre, o templo e os brmanes viraro p, e com
um trouejat; o mundo desaparecer.
Vrias so as histrias que contam a origem da Torre de Hanoi. A histria
anterior foi utilizada pelo matemtico francs douard Lucas em 1883 como
inspirao para o jogo criado por ele [18].
A Torre de Hanoi um quebra-cabea que consiste em uma base contendo
trs pinos, onde em um deles so dispostos sete discos uns sobre os outros, em
ordem crescente de dimetro, de cima para baixo. O problema consiste em passar todos os discos de um pino para outro qualquer, usando um dos pinos como
auxiliar, de maneira que um disco maior nunca fique em cima de outro menor
em nenhuma situao. O nmero de discos pode variar sendo que o mais simples
contm apenas trs (figura 5.6).

return mdcn-n, n);


}
return rndc(n, m-n);
14

int rnain(void)
{
printf(" 6 O, 36
printf(" 36 , 24

%d\n", rndc(60,36;
%d\n", rndc(J.6,24;

'11 1~"

111 1'!
,
~

Figura 5.6: Torre de Ranoi

~~.f.
72

Recursividade

Estrutura de Dados com Algoriunos e C

73

A soluo para o problema da Torre de Hanoi com recursividade baseia-se


no seguinte:
I. A nica operao possvel de ser executada mover um disco de um
pino para outro;
2. Uma torre com (N) discos, em um pino, pode ser reduzida ao disco de
baixo e a torre de cima com (N-I) discos;
3. A soluo consiste em transferir a torre com (N-I) discos do pino origem para o pino auxiliar, mover o disco de baixo do pino origem para o
pino destino e transferir a torre com (N-I) discos do pino auxiliar para
o pino destino. Como a transferncia da torre de cima no uma operao possvel de ser executada, ela dever ser reduzida sucessivamente
at transformar-se em um movimento de disco.

,-L=,

,,-

Figura 5.7: Movimentos conforme algoritmo

Para conseguir transferir todos os discos da primeira estaca terceira 2n - 1,


sendo n o nmero de discos, portanto:
Para solucionar um hanoi de 3 discos, so necessrios 23 - 1 movimentos = 7 movimentos.

o algoritmo

5.2 demostra os passos necessrios para desenvolver a funo


recursiva. Os passos podem ser observados na figura 5.7.

Para solucionar um hanoi de 7 discos, so necessrios 127 movimentos (27 - 1).

Algoritmo 5.2: Passar n peas de uma torre (A) para outra (C)

Para solucionar um hanoi de 15 discos, so necessrios 32767 movimentos (215 - 1).

begin
Passar n-I peas da torre inicial (A) para a torre livre (B)
Mover a ltima pea, para a torre final (C)
Passar n-I peas da torre B para a torre (C)
end

Para solucionar um hanoi de 64 discos, como diz a lenda, so necessrios 18446744073709551615 movimentos (264 - 1) ou 585 bilhes
de anos (considerando um movimento por segundo).

1
2
3
4

No programa 5.10 vista a soluo para o problema da Torre de Hanoi


seguindo as definies recursivas.

Baseado no algoritmo 5.2 possvel determinar o nmero de movimentos


necessrios e determinar os movimentos necessrios.

Programa 5.10: Torre de Hanoi recursivo


/* programa]ecursividade_hanoi.c

*/

O nmero de movimentos necessrio simples de determinar:


#include -cstdio.h

hanoi

count(n)

hanoi

count(n-l)

+ 1 + hanoi

count(n-l)

Neste caso, possvel evitar dupla recursividade (como OCOrrecom Fibonacci) de uma forma simples:

5 I void hanoi (int discos, char origem, char desrno.char ajuda);

void hanoi (int discos, char origem, char destirio,'~~

hanoi

count(n)

2 * hanoi_count(n-l)

.\.::":'
"

+ 1
10 I

if( discos == 1)
{
printf(" \ t Mova o disco
}
else

ajuda)~'~'

..,

%d de %c para

%c \n" .discos.origem, destino);

~I

11
,,
l:

74

fi::

Estrutura de Dados com Algoritmos e C

15 I

hanoi( discos-l,origem,ajuda,destino);
printf("\t
Mova o disco
%d de
hanoi( discos-l,ajuda,destino,origem);

Ii

%c para

%c \n",discos,origem,destino);

return;

Programa

5.12: Dhyanh - Saitou, aku, soku e zan

20

1*plograma]ecursividade_curiosidade_Ol.c

"!

int main (void)

(
int total_discos;
printf(" Informe
o numero
scanf(" %d",&total_discos);
hanoi( total_discos,' N.,'B', 'C');
printf(" \ n ,,);
retumO;

25 I

de

discos:

,,);

30I~)

5.6 Curiosidades com Recursividade

programa 5.11 utiliza de recurso para imprimir a fase da lua (cheia,


minguante, crescente ou nova). Este programa foi um dos concorrentes do 15th
International Obfuscated C Code Contest'.
Programa

5.11: Natori - Imprimindo as fases da lua

/" p1'Ograma]ecursividadccuriosidade_OI.c

"!

#include -csrdio.hs
#include -cmath.h
doublel;
mainl.,o,O)

{
retum
10

15

I)

putchar(l--+22&&_

+44&&mainl,-43,...),_&&0)

( main(-43,++0,O),
( O=(0+21)/sqrt(3-0*22-0*O),I*k4
&&
(fabs(time(O)-607728)%2 5 51443)/405859.-4. 7 +
acos0l2< 1.57[" # "J))
:10 );

1. Disponvel em http://www.iocc.org/years.honI

75

o programa 5.12 participou do mesmo concurso/ e usa recursividade em cima


de ponteiros. O cdigo ir gerar outro cdigo que, quando compilado, ir gerar
outro cdigo e assim sucessivamente.

11

Recursividade

#definel**/X
char*d="xO [ ! 4cM, ! "
"4cK'*!4cJc(!4cHg&!4c$j"
"8f'! &-]ge)!'
1 :d+!)
rAc-! *m*"
":d/!4c(b4eO!lr2e2!/tOe4!-y-c6!"
"+I,c6!)f$b(h*c6!
(d'b(i)d5!
(b*a' '&c"
")c5!'b+'&b'c)c4!&b$c'd*c3!&a.h'd+"
101
"dl! %a/g' e+eO! %b-g (d. dj! &c*h' dld-!
(d%g) "
"d4d+! *1, d7d) ! ,h-d; c' ! .bOc>d%!A 'Dc$! (7) 35E"
"!' i cx.
! 2kE '*! -s@d(! (k (fllg&!)
f. e5' f (! +a+)"
"f%2g* ! ?f5f,
!=f-*e/
! <d6el! geO' f3! 6f) -g5! 4d*b"
"+e6!Of%k)d7!+-A'c7!)z/d-+!'n%aO(d5!%cla+/d4"
15 I
"!2)cge2!9b;el!8b>e/!
7cAd-!5fAe+!7fBe(!"
"8hBd&! : iAd$! [73, QO! 1 bF 7! lb?' _6! 1c, 8b4"
"!2b*a,*d3!2n4f2!${4
f.
'!%y4e5!&f%"
"d-A-d7!4c+b)d9!4c-a
'd
: !/i('
'&d"
"; !+1'a+d<!)1*b(d=!'
ma &d>!&d'"
201
"'O_&c?!$dAc@!$cBc@!$
b
<
A&d$'"
":!$d9_&1++A$!%f3a'
nl
_
$ !&"
"f/c(ol_%!
(f+c)q*c
%!
*
f &d+"
"f$s&!-n,d)n(!Oick)
! 3d"
"/bOh*!H'7a,![7*
i]
5
4
71"
25 I "[=ohr&o*t*q*
'*d
*v
*r
; 02"
"7*-=h.l)tcrsth
&t
:
r
9b"
"] .,b-725-.t--11
#r
[
< t8-"
"752793?
<.-;b
].t--+r
I
#
53~
"7-r[/9-X
.v90
<6/<.v;-52/={
k
goh"
301 "./}q; u vto
hr '.i*$engt$
$
,b"
";$1
=t;v;
6
='it.';7='
":
,b-"
"725
= I o'..d
;b] '-- [/+
551
)0"
'''.d
: -?5
I
)0'.'
v/i]q
"-[;
5 2 =' it
0;5335 1 "v96
<7 I
=0
:
d
=0"
"--li ]q-[;
h.
;
"i)q--[;v
9h
.1
<.'

2. http://www.iocc.org/2000/dhyang.hint

76

Estrutura de Dados com Algoritmos e C

Recursividade

77

,!

,nS2={cj
u
c&'
n?4=0:d=
. o-40
n_ [; 54={ cj
UC&
n [; 7 6=i] q [; 6 =vsr
,) \0
n=),BihY_gha
r,w,f
3217];int i,
r<X
p;nO{retum
45 I 768?d[X(143+
X r++
768]:r>2659
? 59:
[(r++-768)%
X 947
xl\(p?6:0):(p = 34
;}sO(for(x= n
O;
50 I ?6:0==32;x= n
O
voidJ** /main X O
=O;w=sprintf (X
X
,"char*d="); for
+143;)if(33-( bed
55 I )(if(b<93)(if
XC!
[w++J=34;for XCi
(P?O:I);i<b;
i++
[w++]=sO;o[
w++
e1se
=p?sO:34;}
60 I
(for(i=92;
i-cb;
++)o[w++J=
32;}
e1se o
[w++
=10;0
w]=O
65

. o'

I i

Jq

i]q
u.i
n

I
b
X
*d
x

(
768]
X
xl\

+
X

(
[

;returnx
r
XX
f=l;f <
f++X

35
o

Euclides: n

Hanoi: discos

o[
,x,
XX
)%
=d
) ?
X)
(p
;}
=p
Xo
*d

1)
o
+

J
X
}

]
[

5.7 Cuidados com Recursividade


Ao escrever funes recursivas, deve-se ter um comando i f em algum lugar
para forar a funo a retomar sem que a chamada recursiva seja executada. Se
no existir, a funo nunca retomar quando chamada (equivalente a um loop
infinito). Omitir O comando if um erro comum quando se escrevem funes
recursivas.
Isto garante que o programa recursivo no gere uma seqncia infinita de
chamadas a si mesmo. Portanto, todo programa deve ter uma condio de parada
no recursiva. Nos exemplos vistos, as condies de paradas no recursivas eram:

Sem essa sada no recursiva, nenhuma funo recursiva poder ser computada.
Ou seja, todo programa recursivo deve ter uma condio de parada no recursiva.

A maioria das funes recursivas no minimiza significativamente o tamanho do cdigo ou melhora a utilizao da memria. Alm disso, as verses recursivas da maioria das rotinas podem ser executadas um pouco mais lentamente
que suas equivalentes iterativas devido s repetidas chamadas funo. De fato,
muitas chamadas recursivas a uma funo podem provocar um estouro da pilha.
Como o armazenamento para os parmetros da funo e variveis locais est na
pilha e cada nova chamada cria uma nova cpia dessas variveis, a pilha pode provavelmente escrever sobre outra memria de dados ou de programa. Contudo,
no necessrio se preocupar com isso, a menos que uma funo recursiva seja
executada de forma desenfreada. A principal vantagem das funes recursivas a
possibilidade de utiliz-Ias para criar verses mais claras e simples de vrios algoritmos, embora uma soluo no recursiva envolvendo outras estruturas (pilhas,
filas etc.) seja mais difcil de desenvolver e mais propensa a erros. Dessa forma,
ocorre um conflito entre a eficincia da mquina e a do programador. O custo
da programao est aumentando e o custo da computao est diminuindo.
Isto leva a um cenrio que no vale a pena para um programador demandar
muito tempo para elaborar programas iterativos quando solues recursivas
podem ser escritas mais rapidamente. Somente deve-se evitar o uso de solues
recursivas que utilizam recurso mltipla (Fibonacci, por exemplo).

5.9 Exerccios
1. Determine o que a seguinte funo recursiva em C calcula. Escreva
uma funo iterativa para atingir o mesmo objetivo:
int func(int

5.8 Vantagens

putsto), }

Fatorial: O!

=O

={"

X
+

11

n
_n

(
)
{

n)

if( n == O)

Nmeros Triangulares: n = 1
Seqncia de Fibonacci: fib(l)

= 1 e fib(2)

return O;
return (n- funcfn-Ij),

'I

78

Estrutura de Dados com Algoritmos e C

2. Imagine vet como um vetor de inteiros. Apresente programas iterativos


e recursivos para calcular:
a) o elemento mximo do vetor;

B Lista

b) o elemento mnimo do vetor;


c) a soma dos elementos do vetor;
d) o produto dos elementos do vetor;
e) a mdia dos elementos do vetor.

"Existem

3. Uma cadeia s de caracteres palndrome se a leitura de s igual da


esquerda para a direita e da direita para a esquerda. Por exemplo, as
palavras seres, arara e ama so palndromes, assim como a sentena "A
torre da derrota". Faa um programa que fique lendo palavras do usurio e imprima uma mensagem dizendo se as palavras so palndromes
ou no. O seu programa deve ter uma funo recursiva com o seguinte
prottipo: int palindrome
( char * palavra,
int first,
int last);.
Esta funo recebe como parrnetros a palavra que est
sendo testada se palndrome ou no e os ndices que apontam para o
primeiro e ltimo caracteres da palavra. Talvez seja mais fcil fazer uma
funo com o seguinte prottipo: int checaPalindrome
(char *
palavra,
int last);.
Esta funo recebe a palavra a ser verificada e o tamanho da palavra.
4. A funo de Ackermann [2, 19] definida recursivamente nos nmeros
no negativos como segue:
a) a(m,n)

b) an,n)

a(111-1,1)Se m

c) a(m,n)

a(m-1, a(m,n-1 Se m

1 Se m

O,
<>

Oen

<>

O,
Oen

<>

Faa um procedimento recursivo para computar a funo de Ackermann.


Observao: Esta funo cresce muito rpido, assim ela deve ser impressa para
valores pequenos de m e n.

trs tipos de pessoas: as que

deixam acontecer, as que fazem acontecer


e as que perguntam

o que aconteceu:'
Provrbio

escocs

Uma lista um estrutura de dados similar a um pilha ou fila. Uma pilha ou


fila tem um tamanho fixo na memria, e o acesso a um elemento da estrutura
destri o item selecionado (operao dequeue e pop). Na lista, cada elemento
contm um elo (endereo) para o prximo elemento da lista. Desta forma a lista
pode ser acessada de maneira randmica, podendo ser retirados, acrescidos ou
inseridos elementos no meio da lista dinamicamente.
Uma lista pode ter uma entre vrias formas. Ela pode ser simplesmente
ligada ou duplamente ligada, pode ser ordenada ou no, e pode ser circular ou
no. Se uma lista simplesmente ligada, omitimos o ponteiro anterior em cada
elemento. Se uma lista ordenada, a ordem linear da lista corresponde ordem linear de chaves armazenadas em elementos da lista; o elemento minmo
o incio da lista e o elemento mximo o fim. Se a lista no ordenada, os
elementos podem aparecer em qualquer ordem. Em uma lista circular, O ponteiro anterior do incio da lista aponta para o fim, e o ponteiro prximo do fim
da lista aponta para o incio. Desse modo, a lista pode ser vista como um anel
de elementos [9].
Listas encadeadas podem ser singularmente (ou simples) ou duplamente
encadeadas (ligadas). Uma lista simplesmente encadeada contm um elo (endereo) com o prximo item da lista. Uma lista duplamente encadeada contm elos
(endereos) com o elemento anterior e com o elemento posterior a ele. O uso de
cada tipo de lista depende da sua aplicao.

Potrebbero piacerti anche