Você está na página 1de 12

Gabarito da Lista de Algoritmos e Estrutura de Dados

Questo 19) a)

void s e l e c t i o n _ s o r t ( int
int min ;
int aux ;
unsigned i , j ;
for ( i = 0 ; i < s i z e ;

min = a r r a y [ i ] ;

array ,

}
//

procurar

menor

size )

i ++) {

for ( j = i ; j < s i z e ; j++)


{
if ( a r r a y [ j ] < min )
//

unsigned

elemento

pelo

resto

array

min = a r r a y [ j ] ;

fazer

troca

aux = min ;
min = a r r a y [ i ] ;
a r r a y [ i ] = aux ;

b)
Esse exemplo de algoritmo possui o nmero de operaes constantes para
dado n (o melhor caso igual ao pior caso pois no existe entrada que
modique o nmero de iteraes dos loops, fora o tamanho do array).
Para ambos os casos:
Passo
i=0
i<size
i++
min=&array[i]
j=i
j<size
j++
array[j]<*min
min=&array[j]
aux=*min
*min=array[i]
array[i]=aux

Tempo
i1
i2
i3
i4
i5
i6
i7
i8
i9
i1 0
i1 1
i1 2

Nmero de execues
1
size + 1
size
size
size
Psize1
(size i) =
i=0
Psize1
(size
i 1) =
i=0

size(size+1)
2
size(size+1)
2

size size

melhor caso: 0; pior caso: size size


size
size
size

Questo 20) a)
O melhor caso ocorre quando a lista j est ordenada, de modo que o while
interno nunca executado (devido a condio A[i]>chave, com chave =
A[i+1] nunca ser verdadeira), Temos nesse caso (n) formado pelo loop
for externo.
1

O pior caso occorre quando a lista est inversamente ordenada de modo


que o loop while interno executar sempre j-1 vezes (sempre deslocando
todos os elementos do array para a direita at o elemento zero). Como o
loop interno tem relao linear com a entrada, temos O(n2 )
b)
No. O insertion sort exige o deslocamento de todo o array entre a posio
da chave no array ordenado e a posio original, algo que executado
linearmente (mantendo O(n2 )). Uma busca binria nesse caso reduziria
apenas o nmero de comparaes para log2 (n) o que pode ser vantajoso se
a comparao for por alguma razo lenta (embora algoritmos naturalmente
O(nlogn) como o quicksort seriam provavelmente mais apropriados). Essa
variante chamada de Binary Insertion Sort.
Questo 21) a)
Nesse caso o melhor e o pior casos so iguais, j que os loops no variam
com o contedo da lista, s o tamanho dela. O(n2 ) e (n2 ).
b)
Uma soluo simples seria adicionar um ag (varivel) que indicaria se
houve alguma troca no array (quando no h troca em uma iterao indica
que o array j est ordenado), e caso no houver interrompe o loop externo.
O melhor caso passa ento a ser O(n).
c)
O(n)

Questo 22) Acumulando o resultado na pilha:

unsigned soma ( unsigned


{
if ( n == 1)
return 1 ;
return n+soma ( n 1);

n)

A recurso termina em n == 1 com a pilha composta de n + (n 1) +


(n 2) + . . . + 1, que reversamente computado, da forma (n + ((n 1) +
((n 2) + . . . + (1)))), aps a ltima recurso ser encerrada para retornar
o resultado.
Mesmo exemplo, guardando o resultado em uma variavel:

unsigned
{
}

n)

soma_tco (

unsigned

sum += n ;
( n == 1)
sum ;
soma_tco ( n 1, sum ) ;

if

unsigned

soma_tco ( n , 0 ) ;

unsigned
{

soma (

return

n,

unsigned

sum)

Nesse caso, o resultado parcial calculado imediatamente a medida que a


funo recursiva chamada, da forma ((((n) + (n 1)) + (n 2)) + . . . + 1).
Os dois exemplos executam a mesma tarefa, embora a segunda forma (com
a chamada da recurso sendo a ltima operao feita) pode ser diretamente
mapeada para um loop:

unsigned soma_nao_recursiva ( unsigned


{
unsigned sum = 0 ;
do {
sum += n ;
if ( n == 1)
return sum ;
}

n)

} (n ) ;

Essa otimizao feita pelos compiladores de linguagens de programao recursivas para evitar estouro de pilha (e conhecida como tail call
optimization)
Questo 23)

unsigned soma_mult_3 ( unsigned n )


{
if ( n < 3)
return 0 ;
if ( ( n % 3) == 0)
return n+soma_mult_3 ( n 1);
return soma_mult_3 ( n 1);
//

multiplo

de

Questo 24)

unsigned soma_mult_3_gen ( unsigned m, unsigned


{
if ( n < m)
return 0 ;
if ( ( n % 3) == 0)
return n+soma_mult_3_gen ( n 1);
return soma_mult_3_gen ( n 1);
//

multiplo

de

Questo 25)

unsigned
{

soma_mult_k_gen (

if ( n < m)
return 0 ;
if ( ( n % 3) == 0)
return n+soma_mult_k_gen ( n 1);
return soma_mult_k_gen ( n 1);
//

unsigned m,
unsigned n ,
unsigned k )

multiplo

de

n)

Questo 26)

unsigned mais_sign ( unsigned


{
if ( n < 10)
return n ;
return mais_sign ( n / 1 0 ) ;

n)

Questo 27)

unsigned num_dig ( unsigned


{
if ( n < 10)
return 1 ;
return 1+num_dig ( n / 1 0 ) ;

n)

Questo 28)

unsigned sum_dig ( unsigned n )


{
if ( n < 10)
return n ;
return ( n%10)+sum_dig ( n / 1 0 ) ;
}

Questo 29)

#include <s t d i o . h>


#include <s t r i n g . h>
#define BUFFER_SIZE 100
unsigned e_palindromo_str ( char
if ( ( fim i n i c i o ) <= 1)
return 1 ;
return ( i n i c i o == fim ) &&
unsigned
{

char

fim ) {

e_palindromo_str ( i n i c i o +1, fim 1);

}
//

inicio ,

para

e_palindromo (
palindrome ;

unsigned
0

para

n)

nao

palindrome

char

b u f f e r [ BUFFER_SIZE ] ;
s n p r i n t f ( b u f f e r , BUFFER_SIZE, "%u" , n ) ;

return
}

e_palindromo_str ( b u f f e r ,
&( b u f f e r [ s t r l e n ( b u f f e r ) 1 ] ) ) ;

Para simplicar, consideraremos as entradas das questes seguintes como


strings.

Questo 30)

#include <s t r i n g . h>


unsigned t e s t a r _ s e q ( char
if ( m == ' \0 ' )
return 1 ;

m,

char

n ) {

return

( n == m) && t e s t a r _ s e q (m+1 , n +1);

unsigned p e r t e n c e _ s t r ( char m, char n ) {


if ( s t r l e n ( n ) < s t r l e n (m) )
return 0 ;
return t e s t a r _ s e q (m, n ) ? 1 : p e r t e n c e _ s t r

(m, n +1);

Questo 31)

#include <s t r i n g . h>


unsigned pertence_str_n_contig ( char m, char
if ( n == ' \0 ' )
return 0 ;
if ( ( m == n ) && ((++m) == ' \0 ' ) )
return 1 ;
return pertence_str_n_contig (m, n +1);

n ) {

Questo 32)

unsigned u l t i m o _ d i g i t o ( unsigned
if ( n < 10)
return n ;
}

Questo 33)

ultimo_digito (n \10);

unsigned
//

nao

crescente ,

unsigned
1

crescente

crescente (
crescente_loop (n , 0 ) ;

n) {

unsigned c r e s c e n t e _ l o o p ( unsigned
if ( ( n%10) < max)
return 0 ;
if ( n < 10)
return 1 ;
}
Questo 34)

n) {

n,

unsigned

c r e s c e n t e _ l o o p ( n \10 , n%10);

#include <s t d i o . h>


#include <s t r i n g . h>
#define BUFFER_SIZE 100
unsigned e_palindromo_str ( char i n i c i o ,
char fim ,
unsigned sum) {
if ( ( fim i n i c i o ) <= 1)
return 1 ;
return ( ( i n i c i o ' 0 ' )+( fim ' 0 ' ) ) == sum)
}

max) {

e_palindromo_str ( i n i c i o +1, fim 1);

&&

unsigned
//

}
Questo 35)

para

e_palindromo (
palindrome ;

unsigned
0

para

n)

nao

palindrome

unsigned sum ;
char i n i c i o , fim ;
char b u f f e r [ BUFFER_SIZE ] ;

s n p r i n t f ( b u f f e r , BUFFER_SIZE, "%u" , n ) ;
inicio = buffer ;
fim = &( b u f f e r [ s t r l e n ( b u f f e r ) 1 ] ) ;
sum = ( i n i c i o ' 0 ' )+( fim ' 0 ' ) ;
e_palindromo_str ( i n i c i o , fim , sum ) ;

return

unsigned revert_num ( unsigned n ) {


if ( n < 10)
return n ;
return 10 revert_num ( n/10)+n%10;
}

Questo 36)

unsigned dig_pares ( unsigned n ) {


if ( n < 10)
return ! ( n%2);
return ( ! ( n%2)) && dig_pares ( n / 1 0 ) ;
}

Questo 37) Por simplicidade usando n como string em vez de unsigned (informao
de como converter na questo 29). Soluo usando apenas a recurso em
num_dig (questo 27);

#include <math . h>


unsigned r o t a t e ( unsigned number ) {
unsigned s i z e , l a s t _ d i g i t , l a s t _ d i g i t _ m u l t i p l i e r ;
}

s i z e = num_dig ( n ) ;
l a s t _ d i g i t = number % 1 0 ;
l a s t _ d i g i t _ m u l t i p l i e r = pow ( 1 0 , s i z e 1);
l a s t _ d i g i t l a s t _ d i g i t _ m u l t i p l i e r+number / 1 0 ;

return

unsigned rotate_k ( unsigned n , unsigned


if ( k == 0)
return n ;
return rotate_k ( r o t a t e ( n ) , k 1);

k) {

Questo 38) Por simplicidade usando n como string em vez de unsigned (informao
de como converter na questo 29). Soluo usando apenas a recurso em
num_dig (questo 27);

unsigned d e s l _ d i r e i t a ( unsigned n , unsigned


if ( k == 0)
return n ;
return d e s l _ d i r e i t a ( n /10 , k 1);

k) {

Questo 39)

unsigned dig_pot_2 ( unsigned n )


{
if ( n < 10)
return ! ( n % 2 ) ;
return ! ( n % 2) && num_dig ( n / 1 0 ) ;
}

Questo 40) Uma soluo genrica possvel simplesmente transformar o nmero em


uma string, ordenarusando algoritmos recursivos, como o quicksort, e retornar o k-simo elemento.
Questo 41) A soluo com string trivial caso essa no seja constante substituindo
serialmente os valores

unsigned sub_dig_1 ( unsigned n ) {


if ( n < 10)
return n 1;
return ( ( n%10) 1)+10 sub_dig_1 ( n / 1 0 ) ;
}

Questo 42) A soluo com string tambm trivial caso essa no seja constante substituindo serialmente os valores

unsigned sum_dig ( unsigned n )


{
if ( n < 10)
return n ;
return ( n%10) sum_dig ( n / 1 0 ) ;
}

Questo 43)

unsigned count ( unsigned n , unsigned d i g i t )


{
if ( n < 10)
return ( n == d i g i t ) ? 1 : 0 ;
return ( ( ( n%10) == d i g i t ) ? 1 : 0)+ count ( n / 1 0 ) ;
}

Questo 44)

#include <s t d i o . h>


#include <s t r i n g . h>
#define BUFFER_SIZE 100
void opposites_sum_str (
char i n i c i o ,
char fim ,
unsigned max_sum) {
7

unsigned current_sum ;
if ( fim == i n i c i o )
return 1 ;
if ( ( fim i n i c i o ) == 1) {
current_sum = ( i n i c i o ' 0 ' ) ;
if ( max_sum < current_sum )
max_sum = current_sum ;
return ;
}
else
current_sum = ( ( i n i c i o ' 0 ' )
if ( max_sum < current_sum )
}

+ ( fim ' 0 ' ) ) ;

max_sum = current_sum ;
opposites_sum_str ( i n i c i o +1, fim 1, max_sum ) ;

unsigned opposites_sum ( unsigned


{
char b u f f e r [ BUFFER_SIZE ] ;
unsigned max_sum = 0 ;

n)

s n p r i n t f ( b u f f e r , BUFFER_SIZE, "%u" , n ) ;

opposites_sum_str (
buffer ,
&( b u f f e r [ s t r l e n ( b u f f e r ) 1]) ,
&max_sum ) ;
max_sum ;

return

Questo 45) Usando as funes do exerccio 37.

unsigned
return
}

unsigned

compare r o t a t i o n s (
n) {
compare_rotations_rec ( n , r o t a t e ( n ) , 1 )

unsigned compare_rotations_rec (
unsigned n ,
unsigned nrot ,
unsigned k ) {
if ( n == r o t )
return k ;
return rotate_k ( n , r o t a t e ( n r o t ) ,
}

k +1);

Questo 46)

#include <s t d i o . h>


#include <s t r i n g . h>
#define BUFFER_SIZE 100
unsigned o p p o s i t e s _ c r e s _ s t r (
char i n i c i o ,
char fim ,
unsigned max_sum) {
unsigned current_sum ;
if ( fim == i n i c i o )
return 1 ;
if ( ( fim i n i c i o ) == 1) {
current_sum = ( i n i c i o ' 0 ' ) ;
if ( max_sum < current_sum )
return 1 ;
return 0 ;
}
else
current_sum = ( ( i n i c i o ' 0 ' )
if ( max_sum < current_sum ) {
max_sum = current_sum ;
return o p p o s i t e s _ c r e s _ s t r (
}

+ ( fim ' 0 ' ) ) ;

i n i c i o +1,
fim 1,
max_sum ) ;

unsigned o p p o s i t e s _ c r e s ( unsigned
{
char b u f f e r [ BUFFER_SIZE ] ;
unsigned max_sum = 0 ;

n)

s n p r i n t f ( b u f f e r , BUFFER_SIZE, "%u" , n ) ;

}
Questo 47)

opposites_cres_str (
buffer ,
&( b u f f e r [ s t r l e n ( b u f f e r ) 1]) ,
&max_sum ) ;
max_sum ;

return

#include <s t d i o . h>


#include <s t r i n g . h>
#define BUFFER_SIZE 100
unsigned opposites_even_str ( char
{
unsigned current_sum ;
if ( fim == i n i c i o )
return 1 ;
9

inicio ,

char

fim )

if

( ( fim i n i c i o ) == 1) {
current_sum = ( i n i c i o ' 0 ' ) ;
( ! ( current_sum %2))
1;
0;

if
return
return
}
else
current_sum = ( ( i n i c i o ' 0 ' ) + ( fim ' 0 ' ) ) ;
if ( ! current_sum%2)
{
return opposites_even_str ( i n i c i o +1, fim 1);
}
return 0 ;

unsigned o p p o s i t e s _ c r e s ( unsigned
{
char b u f f e r [ BUFFER_SIZE ] ;

n)

s n p r i n t f ( b u f f e r , BUFFER_SIZE, "%u" , n ) ;

return
}

opposites_even_str (
buffer ,
&( b u f f e r [ s t r l e n ( b u f f e r ) 1 ] ) ) ;

Questo 48) a)
Caso base:
n = 1 ou n = 2 ou n = 3
Pn1

= 0
i=0 i(i 1)(i 2)
n(n 1)(n 2)(n 3)/4 = 0

Passo indutivo:
012+101+210+321+432+. . .+(n1)(n2)(n3) =
n(n 1)(n 2)(n 3)/4
[0 1 2 + 1 0 1 + 2 1 0 + 3 2 1 + 4 3 2 + . . . + (n 1)(n
2)(n 3)] + n(n 1)(n 2) =
= n(n 1)(n 2)(n 3)/4 + n(n 1)(n 2) =
= n(n 1)(n 2)[(n 3)/4 + 1] =
= n(n 1)(n 2)[(n + 1)/4] =
= (n + 1)n(n 1)(n 2)/4 =
= (n + 1)[(n + 1) 1][(n + 1) 2][(n + 1) 3]/4

b)
Caso base:
n=1
Pn1
n2

i=0

(2i 1)

= 1
= 1

10

Passo indutivo:
(0 + 1) + (2 + 1) + (4 + 1) + (6 + 1) + . . . + (2(n 1) + 1) = n2
[(0 + 1) + (2 + 1) + (4 + 1) + (6 + 1) + . . . + (2(n 1) + 1)] + (2n + 1) =
= n2 + 2n + 1 =
= (n + 1)2 =

c)
Caso base:
n=1
Pn

= 1
i=i i)
n(n + 1)/2 = 1

Passo indutivo:
1 + 2 + . . . + n = n(n + 1)
[1 + 2 + . . . + n] + n + 1 =
= n(n + 1)/2 + n + 1 =
= n2 /2 + n/2 + n + 1 =
= (n2 + 3n + 2)/2 =
((n + 1)[(n + 1) + 1]/2

d)
Caso base:
n=0
n5 n = 5 0

Passo indutivo:
(n + 1)5 (n + 1) = n5 n + K

K necessariamente divisvel por 5 (assim como n5 n de acordo com a


hiptese)
Expandindo:
k = 5n4 + 10n3 + 10n2 + 5n que claramente mltiplo de 5 para qualquer
n inteiro
e)
Caso base:
n=0
Pn

i=0 Fi
F2 1 = 1 1

= 0
= 0

Passo indutivo:
(F0 + F1 + . . . + Fn ) + Fn+1 =
(Fn+2 1) + Fn+1 =
(Fn+2 + Fn+1 ) 1 =
Fn+3 1 =
F(n+1)+2 1

11

Questo 49) Hiptese


g(n) = 5n 3n
n = 0 retorna 0 e n = 1 retorna 2 (primeiro if), os valores corretos para
50 30 e 51 31 respectivamentes

Passo indutivo
n >= 2
g(n) = 8g(n 1) 15g(n 2) =
= 8 (5n1 3n1 ) 15 (5n2 3n2 ) =

Separando os fatores envolvendo 5n e 3n


5n :
= 8 5n1 15 5n2 =
= 8 5n1 3 5n1 =
= 5 5n1 =
= 5n
3n :
= 8 3n1 + 15 3n2 =
= 8 3n1 + 5 3n1 =
= 3 3n1 =
= 3n

juntando tudo temos que:


g(n) = 8g(n 1) 15g(n 2) =
5n 3n

e obviamente:
g(n + 1) = 5( n + 1) 3( n + 1)

12