Buscar

Estruturas de Dados em C

Prévia do material em texto

Estruturas de Dados
Filippe jabour
IF Sudeste MG - Campus Juiz de Fora
Bacharelado em Sistemas de Informação
22 de novembro de 2011
http://www.jabour.com.br
Este material pode ser usado livremente, copiado ou distribuído, desde que citada a autoria.
Sumário
Lista de programas vi
Lista de figuras viii
1 Introdução 1
2 Matrizes 2
2.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
2.3 Exercícios propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3.1 Multiplicação de matriz por escalar . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3.2 Multiplicação de matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3.3 Busca em vetor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 Funções 5
3.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3.3 Exercícios propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.3.1 Aplicações de funções . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4 Ponteiros 10
4.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
ii
SUMÁRIO iii
4.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.3 Exercícios propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.3.1 Operações com números usando ponteiros . . . . . . . . . . . . . . . . . . . . . . 12
5 Alocação dinâmica de memória 13
5.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6 Estruturas 16
6.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.3 Exercícios propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.3.1 Distância entre dois pontos, com estruturas . . . . . . . . . . . . . . . . . . . . . 17
6.3.2 Distância entre dois pontos, com estruturas e ponteiros . . . . . . . . . . . . . . . 18
6.3.3 Distância do ponto à reta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.3.4 Distância entre retas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.3.5 Representação de uma figura plana . . . . . . . . . . . . . . . . . . . . . . . . . . 18
7 Listas Encadeadas 19
7.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
7.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
7.3 Exercícios propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.3.1 Inserção seletiva na lista encadeada . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.3.2 Média dos elementos da lista encadeada . . . . . . . . . . . . . . . . . . . . . . . 21
7.3.3 Transferência de dados de uma lista para outra . . . . . . . . . . . . . . . . . . . 21
7.3.4 Criar e depois percorrer uma lista encadeada, inserindo dados em outra lista se-
gundo um escopo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.3.5 Mostrar valores de variáveis e ponteiros durante uma operação e descrever a operação 21
SUMÁRIO iv
7.3.6 Mostrar graficamente, passo a passo, o que ocorre na execução do programa . . . . 22
7.3.7 O que faz a função? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.3.8 Produto do primeiro elemento pelo último . . . . . . . . . . . . . . . . . . . . . . 23
7.3.9 Mostrar valores de variáveis e ponteiros durante uma operação . . . . . . . . . . . 24
7.3.10 Mostrar graficamente, passo a passo, o que ocorre na execução do programa . . . . 24
7.3.11 Busca e exclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
7.3.12 Média na lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
7.3.13 Mostrar valores de variáveis e ponteiros durante uma operação . . . . . . . . . . . 25
7.3.14 Concatenar listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
7.3.15 Exibir os elementos das posições ímpares . . . . . . . . . . . . . . . . . . . . . . 26
7.3.16 Retirar e inserir segundo um escopo . . . . . . . . . . . . . . . . . . . . . . . . . 26
8 Pilhas 27
8.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
8.2 Exemplo gráfico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
8.3 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
9 Filas 32
9.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
9.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
9.3 Exercícios propostos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9.3.1 Retira dois elementos da fila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9.3.2 Produto do 2o pelo último elemento da fila . . . . . . . . . . . . . . . . . . . . . 37
9.3.3 Concatenação de filas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9.3.4 Roteador com 4 filas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
10 Recursividade 38
10.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
SUMÁRIO v
10.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
10.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
10.3.1 Soma dos números de 0 a n com recursividade . . . . . . . . . . . . . . . . . . . 44
10.3.2 Divisão com recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
10.3.3 Soma dos elementos do vetor usando recursividade . . . . . . . . . . . . . . . . . 44
10.3.4 Contar números ímpares da lista encadeada usando recursividade . . . . . . . . . 44
10.4 Resposta dos Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
11 Árvores 49
11.1 Definições e representações básicas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
12 Árvores Binárias 51
12.1 Definições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
12.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
12.3 Percursos na árvore binária . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.3.1 Percurso em pré-ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.3.2 Percurso em ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.3.3 Percurso em pós-ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
12.3.4 Exemplo e implementação . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
12.4 Árvores binárias de busca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
13 Árvores AVL 66
13.1 Definições . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
13.2 Exemplos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. . . . . 67
Referências Bibliográficas 68
Lista de Programas
2.1 Soma de matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
3.1 Função simples, sem argumento e sem retorno . . . . . . . . . . . . . . . . . . . . . . . . 5
3.2 Função que recebe e retorna valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3 Raízes da equação do segundo grau . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.4 Insere, busca e mostra dados de um vetor . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.1 Ponteiro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.2 Ponteiro e ponteiro para ponteiro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.1 Alocação de memória, sizeof(), free() . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6.1 Estrutura definindo um ponto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
6.2 Estrutura definindo uma reta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
7.1 Lista encadeada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
7.2 Lista encadeada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
7.3 Fragmento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.4 Código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
8.1 Pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
9.1 Fila01 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
10.1 Cálculo do fatorial com recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
10.2 Cálculo do fatorial com recursividade com mensagens . . . . . . . . . . . . . . . . . . . . 40
10.3 Lista encadeada com recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
vi
LISTA DE PROGRAMAS vii
10.4 Soma recursiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
10.5 Divisão recursiva . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
10.6 Soma recursiva dos elementos do vetor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
10.7 Conta os ímpares da lista encadeada com recursividade . . . . . . . . . . . . . . . . . . . 46
12.1 Criação e impressão de uma árvore binária . . . . . . . . . . . . . . . . . . . . . . . . . . 52
12.2 Árvore binária - inserção ordenada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
12.3 Percursos em árvores binárias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
12.4 Inserção na árvore binária, sem repetição . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
12.5 Árvore binária de busca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Lista de Figuras
11.1 Representação hierárquica de uma árvore . . . . . . . . . . . . . . . . . . . . . . . . . . 49
11.2 Análise de uma árvore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
12.1 Árvore estritamente binária . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
12.2 Árvore binária completa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
12.3 Árvore binária cheia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
12.4 Percursos em árvores binárias . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
13.1 Árvore AVL e não AVL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
viii
Capítulo 1
Introdução
N
otas de aula do professor Filippe Jabour para a disciplina Estrutura de Dados, do segundo período
do curso de Bacharelado em Sistemas de Informação do IF Sudeste MG - Campus Juiz de Fora.
Os exemplos são todos na linguagem C padrão e foram testados com o compilador gcc no sistema
operacional Linux.
Feito com o LATEX.
Alguns conceitos e técnicas que servem de embasamento para o estudo de estruturas de dados são
apresentados nos primeiros capítulos. No capítulo 2 mostramos brevemente este assunto. No capítulo 3 é
apresentada uma pequena revisão de funções. O capítulo 4 faz uma breve apresentação de ponteiros. A
alocação dinâmica de memória é vista no capítulo 5 e as estruturas no 6.
Após os conceitos preliminares, as estruturas de dados propriamente ditas são estudadas. No capítulo 7
vemos as listas encadeadas. No 8 as Pilhas. As filas são estudadas no capítulo 9.
A técnica de recursividade é apresentada no capítulo 10.
Capítulo 2
Matrizes
A gregados homogêneos de dados, com n dimensões.
2.1 Introdução
<tipo> <nome>[m][n];
Exemplo:
float matriz[4][4];
Matriz 4 x 4, de números reais.
matriz[0][0] refere-se ao elemento a11 da matriz.
matriz[2][3] refere-se quarto elemento da terceira linha (a34) da matriz.
2.2 Exemplos
Programa 2.1.
Programa 2.1: Soma de matrizes
1 /∗ s o m a m a t r i z e s . c − F i l i p p e Jabour − 2 6 / 2 / 2 0 0 7
2 Soma de m a t r i z e s
3 ∗ /
4
5 i n t main ( ) {
6
7 i n t i , j , k , ordem , m a t r i z 1 [ 1 0 ] [ 1 0 ] , m a t r i z 2 [ 1 0 ] [ 1 0 ] , ma t r i z soma [ 1 0 ] [ 1 0 ] ;
8
2.3 Exercícios propostos 3
9 p r i n t f ("\nPROGRAMA: LE DUAS MATRIZES BIDIMENSIONAIS E EFETUA A SOMA" ) ;
10 p r i n t f ("\nInforme a Ordem das Matrizes (de 1 a 10): " ) ;
11
12 s c a n f ("%i" , &ordem ) ;
13 i f ( ordem < 1 | ordem > 10 ) {
14 p r i n t f ("\n Erro na entrada de dados.\n" ) ;
15 re turn 2 ;
16 }
17
18 f o r ( i = 0 ; i < ordem ; i ++ ) {
19 p r i n t f ("\n\nMatriz 1" ) ;
20 p r i n t f ("\nLinha %i: " , i +1) ;
21 f o r ( j = 0 ; j <ordem ; j ++ )
22 s c a n f ("\t%i" ,& m a t r i z 1 [ i ] [ j ] ) ;
23 }
24
25 f o r ( i = 0 ; i < ordem ; i ++ ) {
26 p r i n t f ("\n\nMatriz 2" ) ;
27 p r i n t f ("\nLinha %i: " , i +1) ;
28 f o r ( j = 0 ; j <ordem ; j ++ )
29 s c a n f ("\t%i" ,& m a t r i z 2 [ i ] [ j ] ) ;
30 }
31
32 f o r ( i = 0 ; i < ordem ; i ++ ) {
33 f o r ( j = 0 ; j < ordem ; j ++ )
34 mat r i z soma [ i ] [ j ] = m a t r i z 1 [ i ] [ j ] + m a t r i z 2 [ i ] [ j ] ;
35 }
36
37 p r i n t f ("\n\n Matriz soma" ) ;
38 f o r ( i = 0 ; i < ordem ; i ++ ) {
39 p r i n t f ("\n" ) ;
40 f o r ( j = 0 ; j < ordem ; j ++ )
41 p r i n t f ("\t%d" , ma t r i z soma [ i ] [ j ] ) ;
42 }
43 p r i n t f ("\n" ) ;
44
45 }
2.3 Exercícios propostos
2.3.1 Multiplicação de matriz por escalar
Fazer um programa que multiplique uma matriz por um escalar.
2.3 Exercícios propostos 4
2.3.2 Multiplicação de matrizes
Fazer um programa de multiplicação de matrizes.
2.3.3 Busca em vetor
Fazer um programa que procure e exiba o valor e a posição do maior e do menor elemento de um vetor.
Capítulo 3
Funções
M uitas linguagens de programação permitem a chamada a funções e procedimentos.
3.1 Introdução
A função é como um apelido de um trecho de código. No ponto onde está a chamada à função, o fluxo
de execução do programa se desvia para a função invocada e ela é executada. Em algum momento, em
condições normais, o fluxo de execução retorna à função que a chamou. Vendo por outro ângulo, podemos
pensar como se o código da função fosse inserido no lugar da linha que a chama.
Uma vantagem interessante é que, depois de criada, uma função pode ser usada, ou chamada, inúmeras
vezes. Outra vantagem é que, se for preciso dar manutenção no código, basta modificar a função que esta
melhoria ou correção se refletirá em todos os pontos onde a mesma é chamada.
3.2 Exemplos
No programa 3.1, a função criada é muito simples. Não recebenada como argumento. Por isto, não tem
nada nos parênteses em frente ao seu nome (nem na chamada nem na declaração da função). A função não
retorna ou não devolve nenhum valor. Por isto o tipo de retorno é void (palavra que fica antes do nome da
função na declaração). Assim temos a seguinte regra sintática no C:
Tipo_que_a_função_retorna Nome_da_Função ( argumentos_que_a_função_recebe )
Programa 3.1: Função simples, sem argumento e sem retorno
3.2 Exemplos 6
1 /∗ f uncao1 . c − F i l i p p e Jabour − 7 / 8 / 2 0 0 6
2 Chamada de fu nçã o sem r e t o r n o e sem passagem de p a r â m e t r o s
3 ∗ /
4
5 void imprimemsglernum ( ) {
6 p r i n t f ("\n===============================" ) ;
7 p r i n t f ("\nDigite um número" ) ;
8 p r i n t f ("\n===============================> " ) ;
9 }
10
11 i n t main ( ) {
12 f l o a t a , b , c , media ;
13 imprimemsglernum ( ) ;
14 s c a n f ("%f" ,&a ) ;
15 imprimemsglernum ( ) ;
16 s c a n f ("%f" ,&b ) ;
17 imprimemsglernum ( ) ;
18 s c a n f ("%f" ,&c ) ;
19 p r i n t f ("Você digitou %f, %f e %f.\n" , a , b , c ) ;
20 }
No programa 3.2, a função calculaMedia recebe 3 argumentos do tipo float e retorna um valor deste
mesmo tipo.
Programa 3.2: Função que recebe e retorna valores
1 /∗ f uncao2 . c − F i l i p p e Jabour − 7 / 8 / 2 0 0 6
2 Chamada de fu nçã o com r e t o r n o e com passagem de p a r â m e t r o s
3 ∗ /
4
5 void imprimemsglernum ( ) {
6 p r i n t f ("\n===============================" ) ;
7 p r i n t f ("\nDigite um número" ) ;
8 p r i n t f ("\n===============================> " ) ;
9 }
10
11 f l o a t c a l c u l a M e d i a ( f l o a t arg_a , f l o a t arg_b , f l o a t a r g _ c ) {
12 f l o a t r e s u l t a d o = ( a r g _ a + arg_b + a r g _ c ) / 3 ;
13 re turn ( r e s u l t a d o ) ;
14 }
15
16 i n t main ( ) {
17 f l o a t a , b , c , media ;
18 imprimemsglernum ( ) ;
19 s c a n f ("%f" ,&a ) ;
20 imprimemsglernum ( ) ;
21 s c a n f ("%f" ,&b ) ;
22 imprimemsglernum ( ) ;
3.2 Exemplos 7
23 s c a n f ("%f" ,&c ) ;
24 media = c a l c u l a M e d i a ( a , b , c ) ;
25 p r i n t f ("A média entre %f, %f e %f é %f.\n" , a , b , c , media ) ;
26 }
No programa 3.3 temos mais exemplos de chamada de funções.
Programa 3.3: Raízes da equação do segundo grau
1 /∗ f uncao3 . c − F i l i p p e Jabour − 8 / 8 / 2 0 0 6
2 Chamada de fu nçã o
3 C á l c u l o das r a í z e s da equação do segundo grau
4 Compi lar com gcc funcao3 . c −lm
5 ∗ /
6
7 # i n c l u d e <math . h>
8
9 f l o a t c a l c u l a D e l t a ( f l o a t a , f l o a t b , f l o a t c ) {
10 f l o a t d e l t a = b ∗ b − 4 ∗ a ∗ c ;
11 re turn ( d e l t a ) ;
12 }
13
14 f l o a t c a l c u l a R 1 ( f l o a t a , f l o a t b , f l o a t d e l t a ) {
15 f l o a t r1 = ( −1 ∗ b + s q r t f ( d e l t a ) ) / (2 ∗ a ) ;
16 re turn ( r1 ) ;
17 }
18
19 f l o a t c a l c u l a R 2 ( f l o a t a , f l o a t b , f l o a t d e l t a ) {
20 f l o a t r2 = ( −1 ∗ b − s q r t f ( d e l t a ) ) / (2 ∗ a ) ;
21 re turn ( r2 ) ;
22 }
23
24 i n t v a l i d a D e l t a ( f l o a t a , f l o a t b , f l o a t c ) {
25 f l o a t d e l t a = b ∗ b − 4 ∗ a ∗ c ;
26 i f ( d e l t a >= 0 )
27 re turn ( 1 ) ;
28 e l s e
29 re turn ( 0 ) ;
30 }
31
32 i n t main ( ) {
33 f l o a t a , b , c , d e l t a , r1 , r2 ;
34 p r i n t f ("Digite os coeficientes da equação do segundo grau.\n" ) ;
35 p r i n t f ("a X2 + b X + c\n" ) ;
36 p r i n t f ("a = " ) ;
37 s c a n f ("%f" ,&a ) ;
38 p r i n t f ("b = " ) ;
39 s c a n f ("%f" ,&b ) ;
3.2 Exemplos 8
40 p r i n t f ("c = " ) ;
41 s c a n f ("%f" ,&c ) ;
42 i f ( a == 0) {
43 p r i n t f ("Coeficiente \"a\" nao pode ser nulo.\n" ) ;
44 re turn ( 0 ) ;
45 }
46 i f ( v a l i d a D e l t a ( a , b , c ) ) {
47 d e l t a = c a l c u l a D e l t a ( a , b , c ) ;
48 p r i n t f ("Delta = %f.\n" , d e l t a ) ;
49 r1 = c a l c u l a R 1 ( a , b , d e l t a ) ;
50 p r i n t f ("R1 = %f.\n" , r 1 ) ;
51 r2 = c a l c u l a R 2 ( a , b , d e l t a ) ;
52 p r i n t f ("R2 = %f.\n" , r 2 ) ;
53 }
54 e l s e
55 p r i n t f ("A equação não possui raízes reais\n" ) ;
56 }
No programa 3.4 temos mais exemplos de chamada de funções, manipulando dados em um vetor.
Programa 3.4: Insere, busca e mostra dados de um vetor
1 /∗ f u n c a o c o m v e t o r . c − F i l i p p e Jabour − 8 / 8 / 2 0 0 6
2 Chamada de fu nçã o com uso de v e t o r
3 ∗ /
4
5 i n t v e t o r [ 1 0 2 4 ] ;
6
7 void i n s e r e ( i n t e lemento , i n t p o s i c a o ) {
8 v e t o r [ p o s i c a o ] = e l e m e n t o ;
9 }
10
11 void menu ( ) {
12 p r i n t f ("\n+-----------------------------------------------+\n" ) ;
13 p r i n t f ("| 1-Inclui 2-Procura 3-Mostra Todos 4-Sai |\n" ) ;
14 p r i n t f ("+-----------------------------------------------+\n" ) ;
15 p r i n t f (" Digite a sua opcao: " ) ;
16 }
17
18 i n t busca ( i n t e lemento , i n t p o s i c a o ) {
19 i n t i ;
20 f o r ( i = 0 ; i < p o s i c a o ; i ++ ) {
21 i f ( v e t o r [ i ] == e l e m e n t o )
22 re turn ( i ) ;
23 }
24 re turn (−1) ;
25 }
26
3.3 Exercícios propostos 9
27 void m o s t r a t o d o s ( i n t p o s i c a o ) {
28 i n t i ;
29 f o r ( i = 0 ; i < p o s i c a o ; i ++ )
30 p r i n t f (" vetor[%d] = %d\n" , i , v e t o r [ i ] ) ;
31 }
32
33
34 i n t main ( ) {
35 i n t e lemento , p o s i c a o = 0 , i , opcao = 0 , r e s u l t a d o ;
36 whi le ( opcao != 4 ) {
37 menu ( ) ;
38 s c a n f ("%d" ,& opcao ) ;
39 sw i t ch ( opcao ) {
40 case 1 :
41 p r i n t f ("\n Digite o numero a ser incluido: " ) ;
42 s c a n f ("%d" ,& e l e m e n t o ) ;
43 i n s e r e ( e lemento , p o s i c a o ++) ;
44 break ;
45 case 2 :
46 p r i n t f ("\n Digite o numero a ser procurado: " ) ;
47 s c a n f ("%d" ,& e l e m e n t o ) ;
48 r e s u l t a d o = busca ( e lemento , p o s i c a o ) ;
49 i f ( r e s u l t a d o != −1 )
50 p r i n t f ("\n Elemento encontrado na posicao %d do
vetor." , r e s u l t a d o ) ;
51 e l s e
52 p r i n t f ("\n Elemento nao encontrado." ) ;
53 break ;
54 case 3 :
55 m o s t r a t o d o s ( p o s i c a o ) ;
56 }
57 }
58 }
3.3 Exercícios propostos
3.3.1 Aplicações de funções
Refaça os exercícios 2.3.1, 2.3.2 e 2.3.3 usando funções sempre que necessário.
Capítulo 4
Ponteiros
4.1 Introdução
V
a riáveis têm endereços de memória. Variáveis têm tipo como int, float, char etc. A definição do tipo
da variável existe para que o compilador “saiba” o tamanho de memória a ser alocada (ou reservada)
para gravar os valores que esta variável assumirá durante a execução do programa.
A sentença int x = 10; carrega as seguintes informações:
• x é inteiro
• x retorna o que está no endereço de x, ou seja, em int y = x; , y receberá 10.
• &x retorna o endereço de x, que é um endereço de memória. Em scanf(“%f”,&a); , a função scanf
receberá um valor digitado e gravará no endereço de a.
Muitas linguagens de programação possuem o tipo ponteiro. Uma variável do tipo ponteiro, como
toda variável, armazena um valor. No caso do ponteiro, o valor armazenado é um endereço de memória.
Em C, usa-se o caracter * para informar que a variável é um ponteiro.
A sentença int *p; carrega as seguintes informações:
• p é um ponteiro para inteiro
• p retorna um endereço de memória onde está gravado um inteiro
• *p retorna o que está no endereço para o qual p aponta, que é um inteiro
4.2 Exemplos 11
4.2 Exemplos
Antes que você se desespere e vá para a cantina, vamos aos exemplos.
Programa 4.1: Ponteiro
1 /∗ p o n t e i r o 1 . c − F i l i p p e Jabour − 1 3 /8 / 2 0 0 6
2 P o n t e i r o s
3 ∗ /
4
5 i n t main ( ) {
6 i n t x , y , z , k , ∗p , ∗q ;
7 x = 1 0 ;
8 y = 2 0 ;
9 p r i n t f ("\np = &x , ou seja, p aponta para x\n" ) ;
10 p = &x ;
11 p r i n t f ("q = &y , ou seja, q aponta para y\n" ) ;
12 q = &y ;
13 p r i n t f ("z = *p + *q\n" ) ;
14 z = ∗p + ∗q ;
15 p r i n t f ("z = %d\n" , z ) ;
16 p r i n t f ("k = x + y\n" ) ;
17 k = x + y ;
18 p r i n t f ("k = %d\n" , k ) ;
19 }
Outro exemplo do professor Jabour.
Programa 4.2: Ponteiro e ponteiro para ponteiro
1 /∗ p o n t e i r o 2 . c − F i l i p p e Jabour − 1 3 / 8 / 2 0 0 6
2 P o n t e i r o s
3 ∗ /
4
5 # i n c l u d e < s t d i o . h>
6
7 i n t main ( ) {
8 i n t x , ∗p , ∗∗q ;
9 x = 1 0 ;
10 p = &x ;
11 q = &p ;
12 p r i n t f ("Codigo:\nint x, *p, **q;\nx = 10;\np = &x;\nq = &p;\n\n" ) ;
13 p r i n t f ("q = %p \n" , q ) ;
14 p r i n t f ("**q = %d \n\n" ,∗∗q ) ;
15 p r i n t f ("&p = %p \n" ,&p ) ;
16 p r i n t f ("p = %p \n" , p ) ;
17 p r i n t f ("*p = %d \n\n" ,∗ p ) ;
18 p r i n t f ("x = %d \n" , x ) ;
19 p r i n t f ("&x = %p \n\n" ,&x ) ;
4.3 Exercícios propostos 12
20 p r i n t f ("x é inteiro, assim x retorna o que está no endereço de x, que é um
inteiro.\n&x retorna o endereço de x, que é um endereço de memória\n" ) ;
21 p r i n t f ("p é ponteiro, assim p retorna o que está no endereço de p, que é um
endereço, e é o endereço de x;\n *p retorna o que está no endereço para o
qual p aponta, que é o que está no endereço de x, que é 10;\n &x é o
endereço de x, que é o que está em p.\nObserve que:\nq = &p ; p = &x ; **q =
*p = x.\nPonteiro é um endereço e variável TEM um endereço.\n\n" ) ;
22 }
4.3 Exercícios propostos
4.3.1 Operações com números usando ponteiros
Faça um programa que calcula e exibe a média entre 3 números. Use apenas ponteiros, ou seja, não
pode usar diretamente (a+ b+ c)/3.
Capítulo 5
Alocação dinâmica de memória
5.1 Introdução
E
m C é possível solicitar, requisitar ou alocar memória durante a execução do programa. A aplicação
está nas situações em que não sabemos a dimensão ou quantidade de memória que serão necessários
durante a execução do programa. A partir do capítulo 7, na parte de Estruturas de Dados propriamente dita,
ficará clara a motivação do uso de alocação dinâmica.
Esta alocação em tempo de execução se chama alocação dinâmica. Ela é feita através da função mal-
loc da biblioteca stdlib.h.
void* malloc (unsigned int num);
A função malloc recebe o número de bytes a serem alocados (num) e retorna um ponteiro para void que
aponta para o primeiro byte desta área de memória ou retorna NULL se a alocação não teve sucesso.
A função free() libera a memória alocada. free(v) libera a área para onde v aponta.
A função sizeof retorna o tamanho de uma variável, ou seja, quanta memória um tipo (int, float, double,
etc) ocupa na memória. Ela é útil para ser usada como argumento da função malloc. Assim, alocaremos
exatamente o espaço necessário para gravar o valor da variável. Veja como se faz:
ponteiro = malloc(sizeof(float));
Como vimos, a função malloc retorna ou devolve um ponteiro para void. Para gravar e manipular
outros tipos no endereço alocado, temos que converter o tipo retornado. Em C, podemos fazer a chamada
conversão explícita de tipo, ou type cast. Para isto, devemos colocar antes da expressão a ser convertida,
o novo tipo entre parênteses.
5.2 Exemplos 14
int *ponteiro;
ponteiro = (int*)malloc(sizeof(int));
Em caso de falha na alocação de memória, a função malloc retornará NULL. Deste modo, basta com-
parar o ponteiro com NULL após a tentativa de alocação e verificar se houve sucesso:
if (ponteiro) { . . . }
ou
if (ponteiro != NULL) { . . . }
Os dois trechos acima têm o mesmo efeito.
5.2 Exemplos
Programa 5.1: Alocação de memória, sizeof(), free()
1 /∗ AlocaMemoria . c − F i l i p p e Jabour − 1 0 / 0 9 / 2 0 0 6
2 Alocação de Memória , mal loc , s i z e o f , f r e e , t y p e c a s t
3 ∗ /
4
5 i n t main ( ) {
6 void ∗pontParaVoidUm , ∗ p o n t P a r a V o i d D o i s ;
7 f l o a t ∗ p o n t P a r a F l o a t ;
8 double ∗ p o n t P a r a D o u b l e ;
9
10 pontParaVoidUm = ma l l oc ( 4 ) ;
11 i f ( ! pontParaVoidUm )
12 p r i n t f ("\nFalha ao alocar memória para pontParaVoidUm.\n\n" ) ;
13 e l s e
14 p r i n t f ("\n\npontParaVoidUm aponta para 4 bytes alocados.\nEsta area de
memoria comeca no endereco %p\n\n" , pontParaVoidUm ) ;
15
16 p o n t P a r a V o i d D o i s = ma l lo c ( 4 0 ) ;
17 i f ( ! p o n t P a r a V o i d D o i s )
18 p r i n t f ("\nFalha ao alocar memoria para pontParaVoidDois.\n\n" ) ;
19 e l s e
20 p r i n t f ("\n\npontParaVoidDois aponta para 40 bytes alocados.\nEsta area
de memoria comeca no endereco %p\n\n" , p o n t P a r a V o i d D o i s ) ;
21
22 p r i n t f ("\n\n\tA funcao sizeof()" ) ;
23 p r i n t f ("\nUm real (float) ocupa %u bytes na memoria." , s i z e o f ( f l o a t ) ) ;
24 p r i n t f ("\nUm real de dupla precisao (double) ocupa %u bytes na memoria." , s i z e o f (
double ) ) ;
25 p r i n t f ("\nUm caracter (char) ocupa %u byte na memoria." , s i z e o f ( char ) ) ;
5.2 Exemplos 15
26
27 p o n t P a r a F l o a t = ( f l o a t ∗ ) m a l lo c ( s i z e o f ( f l o a t ) ) ;
28 i f ( ! p o n t P a r a F l o a t )
29 p r i n t f ("\nFalha ao alocar memoria para pontParaFloat.\n\n" ) ;
30 e l s e {
31 p r i n t f ("\n\npontParaFloat aponta para %u bytes alocados.\nEsta area de
memoria comeca no endereco %p\n\n" , s i z e o f ( f l o a t ) , p o n t P a r a F l o a t ) ;
32 ∗ p o n t P a r a F l o a t = 3 . 1 4 ;
33 p r i n t f ("\nGravamos o valor %f no endereco para onde pontParaFloat aponta
" ,∗ p o n t P a r a F l o a t ) ;
34 }
35
36 p o n t P a r a D o u b l e = ( double ∗ ) m a l lo c ( s i z e o f ( double ) ) ;
37 i f ( ! p o n t P a r a D o u b l e )
38 p r i n t f ("\nFalha ao alocar memoria para pontParaDouble.\n\n" ) ;
39 e l s e {
40 p r i n t f ("\n\npontParaDouble aponta para %u bytes alocados.\nEsta area de
memoria comeca no endereco %p\n\n" , s i z e o f ( double ) , p o n t P a r a D o u b l e ) ;
41 ∗ p o n t P a r a D o u b l e = ∗ p o n t P a r a F l o a t ∗ 2 ;
42 p r i n t f ("\nO endereco para onde pontParaDouble aponta recebeu o dobro do
valor\nque esta\’ no endereco para onde *pontParaFloat aponta. Seu
valor e\’: %lf\n\n" ,∗ p o n t P a r a D o u b l e ) ;
43 }
44
45 f r e e ( pontParaVoidUm ) ;
46 f r e e ( p o n t P a r a V o i d D o i s ) ;
47 f r e e ( p o n t P a r a F l o a t ) ;
48 f r e e ( p o n t P a r a D o u b l e ) ;
49
50 }
Capítulo 6
Estruturas
6.1 Introdução
E
s truturas são objetos que contém dados mais simples em seu interior. Quando definimos uma estru-
tura, criamos um novo tipo de dado (como uma classe de coisas). Podemos então ter várias variáveis
deste tipo (que seriam vários objetos desta classe de dados).
6.2 Exemplos
Programa 6.1: Estrutura definindo um ponto
1 # i n c l u d e < s t d i o . h>
2
3 /∗ e s t r u t u r a s 1 . c − F i l i p p e Jabour − 2 1 / 8 / 2 0 0 6
4 E s t r u t u r a s
5 ∗ /
6
7 i n t main ( ) {
8
9 s t r u c t PontoNoPlano {
10 f l o a t x ;
11 f l o a t y ;
12 } ;
13
14 s t r u c t PontoNoPlano ponto_A ;
15
16 p r i n t f ("Informe as coordenadas: \n" ) ;
17 p r i n t f ("\tx = " ) ;
18 s c a n f ("%f" ,& ponto_A . x ) ;
6.3 Exercícios propostos 17
19 p r i n t f ("\ty = " ) ;
20 s c a n f ("%f" ,& ponto_A . y ) ;
21 p r i n t f ("As coordenadas são %f , %f \n" , ponto_A . x , ponto_A . y ) ;
22 }
Programa 6.2: Estrutura definindo uma reta
1 # i n c l u d e < s t d i o . h>
2
3 /∗ e s t r u t u r a s 2 . c − F i l i p p eJabour − 2 1 / 8 / 2 0 0 6
4 E s t r u t u r a s
5 ∗ /
6
7 i n t main ( ) {
8
9 s t r u c t PontoNoPlano {
10 f l o a t x ;
11 f l o a t y ;
12 } ;
13
14 s t r u c t Reta {
15 s t r u c t PontoNoPlano a , b ;
16 } retaUm ;
17
18 p r i n t f ("Informe as coordenadas do primeiro ponto: \n" ) ;
19 p r i n t f ("\tx = " ) ;
20 s c a n f ("%f" ,& retaUm . a . x ) ;
21 p r i n t f ("\ty = " ) ;
22 s c a n f ("%f" ,& retaUm . a . y ) ;
23
24 p r i n t f ("Informe as coordenadas do segundo ponto: \n" ) ;
25 p r i n t f ("\tx = " ) ;
26 s c a n f ("%f" ,& retaUm . b . x ) ;
27 p r i n t f ("\ty = " ) ;
28 s c a n f ("%f" ,& retaUm . b . y ) ;
29
30 p r i n t f ("A reta é definida pelos pontos A (%.2f,%.2f) e B (%.2f,%.2f) \n" , retaUm .
a . x , retaUm . a . y , retaUm . b . x , retaUm . b . y ) ;
31 }
6.3 Exercícios propostos
6.3.1 Distância entre dois pontos, com estruturas
Faça um programa que calcule a distância entre dois pontos. Represente cada ponto como uma estrutura.
6.3 Exercícios propostos 18
6.3.2 Distância entre dois pontos, com estruturas e ponteiros
Faça um programa que calcule a distância entre dois pontos. Represente cada ponto como uma estrutura.
Referencie as estruturas com ponteiros para estruturas.
6.3.3 Distância do ponto à reta
Faça um programa que calcule a distância de um ponto a uma reta. Represente cada ponto como uma
estrutura. Represente a reta como uma estrutura formada por duas estruturas do tipo ponto.
6.3.4 Distância entre retas
Faça um programa que calcule a distância entre duas retas. Represente cada ponto como uma estrutura.
Represente a reta como uma estrutura formada por duas estruturas do tipo ponto.
6.3.5 Representação de uma figura plana
Faça um programa que represente uma figura plana da seguinte forma: os vértices são pontos represen-
tados por estruturas; as arestas são representadas por ponteiros de um ponto (vértice (estrutura)) para outro
(o próximo).
Capítulo 7
Listas Encadeadas
7.1 Introdução
E
s truturas como vetores tem sua dimensão, ou tamanho, definida em tempo de compilação, ou seja,
definida quando criamos o programa. Existe uma forma mais flexível para criar estruturas de dados
que cresçam conforme precisamos armazenar mais elementos e diminuam quando liberamos ou retiramos
estes elementos. Isto é feito com o uso de ponteiros (capítulo 4), alocação dinâmica de memória (capítulo
5) e estruturas (capítulo 6). São as chamadas Listas Encadeadas.
7.2 Exemplos
Programa 7.1: Lista encadeada
1 /∗ l i s t a E n c a d e a d a 1 − F i l i p p e Jabour − 2 3 / 8 / 2 0 0 6
2 L i s t a Encadeada , sem f u n ç õ e s , i n s e r ç ã o e e x i b i ç ã o de dados
3 ∗ /
4
5 # i n c l u d e < s t d i o . h>
6 # i n c l u d e < s t d l i b . h>
7
8 s t r u c t TipoNota {
9 f l o a t n o t a ;
10 i n t numChamada ;
11 s t r u c t TipoNota ∗proximo ;
12 } ;
13
14 t y p e d e f s t r u c t TipoNota Nota ;
15
16 i n t main ( ) {
7.2 Exemplos 20
17
18 f l o a t auxNota = 0 ;
19 i n t auxNumChamada = 0 ;
20 Nota ∗ b o l e t i m , ∗novoNo ;
21 b o l e t i m = NULL;
22
23 p r i n t f ("Digite o numero de chamada (-999 para encerrar) e em seguida a nota" ) ;
24
25 whi le ( auxNumChamada != −999) {
26 p r i n t f ("\nNumero de chamada: " ) ;
27 s c a n f ("%d" ,&auxNumChamada ) ;
28 i f ( auxNumChamada != −999) {
29 p r i n t f (" Nota: " ) ;
30 s c a n f ("%f" ,& auxNota ) ;
31 novoNo = ( Nota ∗ ) ( m a l loc ( s i z e o f ( Nota ) ) ) ;
32 i f ( ! novoNo )
33 p r i n t f ("\nFalha de alocação de memória." ) ;
34 e l s e {
35 novoNo−>n o t a = auxNota ;
36 novoNo−>numChamada = auxNumChamada ;
37 novoNo−>proximo = b o l e t i m ;
38 b o l e t i m = novoNo ;
39 p r i n t f ("Nota inserida com sucesso.\n" ) ;
40 }
41 }
42 }
43
44 p r i n t f ("\nDigitação de notas encerrada. Tecle algo . . ." ) ;
45 g e t c h a r ( ) ; g e t c h a r ( ) ;
46
47 p r i n t f ("\nNotas serão exibidas.\n" ) ;
48 Nota ∗p ;
49 i f ( b o l e t i m == NULL)
50 p r i n t f ("\nNão há notas (lista vazia)\n" ) ;
51 e l s e {
52 f o r ( p = b o l e t i m ; p != NULL ; p = p−>proximo ) {
53 p r i n t f ("Aluno: %d" , p−>numChamada ) ;
54 p r i n t f ("\t Nota: %.1f\n" , p−>n o t a ) ;
55 }
56 }
57
58 p r i n t f ("\nVamos ver os endereços . . ." ) ;
59 g e t c h a r ( ) ;
60
61 i f ( b o l e t i m == NULL)
62 p r i n t f ("\nNão há notas (lista vazia)\n" ) ;
63 e l s e {
64 f o r ( p = b o l e t i m ; p != NULL ; p = p−>proximo )
7.3 Exercícios propostos 21
65 p r i n t f ("%p\n" , p ) ;
66 p r i n t f ("%p\n" , p ) ;
67 }
68
69 p r i n t f ("\n\n" ) ;
70
71 }
7.3 Exercícios propostos
7.3.1 Inserção seletiva na lista encadeada
Receber numeros digitados pelo usuário e inserir os números pares em uma lista encadeada e os números
ímpares em outra.
7.3.2 Média dos elementos da lista encadeada
No exemplo das notas, após digitadas todas as notas, calcular a média da turma.
Não iniciar o cálculo ou acúmulo de somatórios durante a leitura dos dados, inicie os cálculos após receber
todas as notas.
7.3.3 Transferência de dados de uma lista para outra
Fazer um programa que crie uma lista e depois transfira seus dados para outra lista.
7.3.4 Criar e depois percorrer uma lista encadeada, inserindo dados em outra lista
segundo um escopo
Faça um programa que receba (leia) alguns números inteiros, inserindo-os em uma lista encadeada. Em
seguida, o programa percorre esta lista e insere os números maiores que 100 em outra lista encadeada.
7.3.5 Mostrar valores de variáveis e ponteiros durante uma operação e descrever a
operação
Na lista encadeada abaixo, a inserção é feita em ordem crescente. Mostre, passo a passo, os valores que
as variáveis abaixo recebem, desde a digitação até o fim da inclusão, quando é inserido o valor 11 na lista.
7.3 Exercícios propostos 22
q e ant→ ponteiros usados para percorrer a lista.
p.
auxInfo→ variável onde será armazenado o valor 11 quando digitado pelo usuário.
info e prox→ campos da estrutura nó da lista. (Mostrar apenas para o novo nó criado).
p→ 5 ∗ → 9 ∗ → 13 ∗ → 14 ∗ → 18 ∗ → NULL
Além dos valores das variáveis e ponteiros, explique passo a passo como é feita esta inserção.
7.3.6 Mostrar graficamente, passo a passo, o que ocorre na execução do programa
Considere o código a seguir.
Programa 7.2: Lista encadeada
1 # i n c l u d e < s t d l i b . h>
2 s t r u c t TipoNo {
3 i n t v a l o r ;
4 s t r u c t TipoNo ∗proximo ;
5 } ;
6 t y p e d e f s t r u c t TipoNo No ;
7 i n t main ( ) {
8 i n t i = 1 ;
9 No ∗ l i s t a , ∗novoNo , ∗p ;
10 l i s t a = NULL;
11 whi le ( i < 4 ) {
12 novoNo = ( No∗ ) ( m a l loc ( s i z e o f ( No ) ) ) ; / / 1
13 novoNo−>v a l o r = i ; / / 2
14 novoNo−>proximo = l i s t a ; / / 3
15 l i s t a = novoNo ; / / 4
16 i ++; / / 5
17 }
18 p r i n t f ("\nA_lista_criada.\n" ) ;
19 p r i n t f ("->" ) ;
20 f o r ( p = l i s t a ; p != NULL ; p = p−>proximo )
21 p r i n t f ("%d->" , p−>v a l o r ) ;
22 p r i n t f ("NULL" ) ;
23 g e t c h a r ( ) ;
24 }
Mostre graficamente, passo a passo, o que ocorre na execução do programa. Nos seus desenhos, mostre as
estruturas e os ponteiros e relacione os passos com os rótulos de 1 a 5 (//1, //2, etc), existentes no programa.
Ao final deve ser mostrada a estrutura de dados que o programa cria (ainda graficamente).
7.3 Exercícios propostos 23
7.3.7 O que faz a função?
Considere o fragmento de código a seguir:
Programa 7.3: Fragmento
1 Est ru tu raEmUso ∗ t r e c h o F u l a n o ( Es t ru tu raEmUso ∗pont , i n t v ) {
2 Est ru tu raEmUso ∗ a n t = NULL, ∗p = pon t ;
3 whi le ( p != NULL && p−>i n fo != v ) {
4 a n t = p ;
5 p = p−>prox ;
6 }
7 i f ( p == NULL)
8 re turn pon t ;
9
10 i f ( a n t == NULL)
11 pon t = p−>prox ;
12 e l s e
13 an t−>prox = p−>prox ;
14 f r e e ( p ) ;
15 re turn pon t ;
16 }
1. O que ele é?
2. O que ele faz?
3. O que o trecho do while faz?
4. O que o trecho do primeiro if faz e quando é executado?
5. O que o trecho do segundo if faz e quando é executado?
6. O que o trecho do else faz e quando é executado?
7. O que o trecho free faz?
8. O que o return faz?
9. Explique as partes e funções da primeira linha do código?
7.3.8 Produto do primeiro elemento pelo último
Faça um programa que receba (leia) alguns números inteiros, inserindo-os em uma lista encadeada. Em
seguida, o programa acessa a lista, calcula e exibe o produto do primeiro elemento pelo último.
7.3 Exercícios propostos 24
7.3.9 Mostrar valores de variáveis e ponteiros durante uma operação
Na lista encadeada abaixo, mostre, passo a passo, os valores que as variáveis e ponteiros assumem,
desde a digitação até o fim da execução, quando o usuário pede a remoção (exclusão) do elemento 13.
q e ant→ ponteiros usados para percorrer a lista.
p.
auxInfo→ variável onde será armazenado o valor 13 quando digitado pelo usuário.
Obs.: info e prox são os campos da estrutura nó da lista.
p→ 5 ∗ → 9 ∗ → 13 ∗ → 14 ∗ → 18 ∗ → NULL
Além dos valores das variáveis e ponteiros, explique passo a passo como é feita esta exclusão.
7.3.10 Mostrar graficamente, passo a passo, o que ocorre na execução do programa
Considere o código a seguir.
Programa 7.4: Código
1 # i n c l u d e < s t d l i b . h>
2 s t r u c t TipoNo {
3 i n t v a l o r ;
4 s t r u c t TipoNo ∗proximo ;
5 } ;
6 t y p e d e f s t r u c t TipoNo No ;
7 i n t main ( ) {
8 i n t i = 1 ;
9 No ∗ l i s t a , ∗novoUm , ∗novoDois , ∗p ;
10 l i s t a = NULL;
11 whi le ( i < 4 ) {
12
13 novoUm = ( No∗ ) ( m a l lo c ( s i z e o f ( No ) ) ) ; / / 1
14 novoUm−>v a l o r = i ; / / 2
15 novoUm−>proximo = l i s t a ; / / 3
16 l i s t a = novoUm ; / / 4
17
18 novoDois = ( No∗ ) ( m a l lo c ( s i z e o f ( No ) ) ) ; / / 5
19 novoDois−>v a l o r = i ∗ i ; / / 6
20 novoDois−>proximo = l i s t a ; / / 7
21 l i s t a = novoDois ; / / 8
22
23 i ++; / / 9
24 }
25 p r i n t f ("\nA_lista_criada.\n" ) ;
7.3 Exercícios propostos 25
26 p r i n t f ("->" ) ;
27 f o r ( p = l i s t a ; p != NULL ; p = p−>proximo )
28 p r i n t f ("%d->" , p−>v a l o r ) ;
29 p r i n t f ("NULL" ) ;
30 g e t c h a r ( ) ;
31 }
Mostre graficamente (com desenhos), passo a passo, o que ocorre na execução do programa. Nos seus
desenhos, mostre as estruturas e os ponteiros e relacione os passos com os rótulos de 1 a 9 (//1, //9, etc),
existentes no programa. Ao final deve ser mostrada a estrutura de dados que o programa cria (ainda grafi-
camente).
7.3.11 Busca e exclusão
Com relação às listas encadeadas, responda:
1. Na busca, quando se constata que o valor buscado (procurado) não existe na lista?
2. Por que usamos o ponteiro ant ou anterior na exclusão?
7.3.12 Média na lista
Faça um programa que receba (leia) alguns números inteiros, inserindo-os em uma lista encadeada. Em
seguida, o programa acessa a lista, calcula e exibe a média aritmética dos números armazenados na lista.
7.3.13 Mostrar valores de variáveis e ponteiros durante uma operação
Mostre, passo a passo, os valores que as variáveis abaixo recebem, desde a digitação até o fim da exe-
cução, quando o usuário pede a busca do elemento 13.
q→ ponteiro usado para percorrer a lista.
p.
auxInfo→ variável onde será armazenado o valor 13 quando digitado pelo usuário.
Obs.: info e prox são os campos da estrutura nó da lista.
p→ 5 ∗ → 2 ∗ → 13 ∗ → 10 ∗ → 1 ∗ → NULL
Além dos valores das variáveis e ponteiros, explique passo a passo como é feita (ou como funciona) a busca.
7.3 Exercícios propostos 26
7.3.14 Concatenar listas
Dadas duas listas encadeadas independentes, o que seria necessário para concatená-las, ou seja, para
colocar a segunda no final da primeira?
7.3.15 Exibir os elementos das posições ímpares
Faça um programa que receba (leia) alguns números inteiros, inserindo-os em uma lista encadeada. Em
seguida, o programa percorre esta lista e mostra (exibe) os elementos das posições ímpares.
Exemplo: Dada a lista X,Y, Z,K,L,M,P,A,B serão exibidos os valores X,Z,L, P,B
7.3.16 Retirar e inserir segundo um escopo
Faça um programa que receba (leia) alguns números inteiros, inserindo-os em uma lista encadeada.
Em seguida, o programa percorre esta lista, retira os números maiores que 50 e os insere em outra lista
encadeada
Capítulo 8
Pilhas
8.1 Introdução
N
as pilhas os dados são sempre inseridos e retirados do topo. É comum dizer que as pilhas seguem o
princípio LIFO (Last In, First Out) (último a entrar, primeiro a sair).
É comum o uso dos nomes push para a função que insere dados na pilha (empilhar) e pop para a que
retira (desempilhar).
8.2 Exemplo gráfico
push(15) topo→ 15
↓
NULL
Empilhou o 15
push(10) topo→ 10
↓
15
↓
NULL
Empilhou o 10
8.2 Exemplo gráfico 28
push(23) topo→ 23
↓
10
↓
15
↓
NULL
Empilhou o 23
push(6) topo→ 6
↓
23
↓
10
↓
15
↓
NULL
Empilhou o 6
pop( ) topo→ 23
↓
10
↓
15
↓
NULL
Desempilhou o 6
A função pop( ) não recebe argumento (pois sempre retira do topo). Ela retorna o valor que está no topo da
lista
pop( ) topo→ 10
↓
15
↓
NULL
Desempilhou o 23
8.3 Exemplos 29
push(45) topo→ 45
↓
10
↓
15
↓
NULL
Empilhou o 45
8.3 Exemplos
Programa 8.1: Pilha
1 /∗ P i l h a 0 1 . c − F i l i p p e Jabour − 2 0 / 0 9 / 2 0 1 1
2 P i l h a
3 ∗ /
4
5 # i n c l u d e < s t d i o . h>
6 # i n c l u d e < s t d l i b . h>
7
8 /∗ Nó ( e l e m e n t o ) da p i l h a ( e s t r u t u r a ) ∗ /
9 s t r u c t TipoElemento {
10 i n t i n f o r m a c a o ;
11 s t r u c t TipoElemento ∗proximo ;
12 } ;
13 t y p e d e f s t r u c t TipoElemento Elemento ;
14
15 /∗ A e s t r u t u r a P i l h a ∗ /
16 s t r u c t T i p o P i l h a {
17 Elemento ∗ t opo ;
18 } ;
19 t y p e d e f s t r u c t T i p o P i l h a P i l h a ;
20
21 /∗ I n s e r ç ã o de e l e m e n t o ( sempre no topo da p i l h a ) ∗ /
22 void push ( P i l h a ∗p , i n t dado ) {
23 Elemento ∗novo = ( Elemento ∗ ) m a l lo c ( s i z e o f ( Elemento ) ) ;
24 i f ( ! novo ) {
25 p r i n t f ("Erro criando novo elemento." ) ;
26 re turn ;
27 }
28 novo−>i n f o r m a c a o = dado ;
29 novo−>proximo = p−>topo ;
30 p−>topo = novo ;
31 }
8.3 Exemplos 30
32
33 /∗ remoção de e l e m e n t o ( sempre do i n i c i o da p i l h a ) ∗ /
34 i n t pop ( P i l h a ∗p ) {
35 Elemento ∗aux ;
36 i n t dado ;
37 i f ( ! p−>topo ) {
38 p r i n t f ("\nPilha vazia. Programa será encerrado.\n" ) ;
39 g e t c h a r ( ) ;
40 e x i t ( 1 ) ;
41 }
42 aux = p−>topo ;
43 dado = p−>topo−>i n f o r m a c a o ;
44 p−>topo = p−>topo−>proximo ;
45 f r e e ( aux ) ;
46 re turn ( dado ) ;
47 }
48
49 void m o s t r a P i l h a ( P i l h a ∗p ) {
50 Elemento ∗aux = p−>topo ;
51 p r i n t f ("\nA pilha\n" ) ;
52 f o r ( aux ; aux ; aux = aux−>proximo )
53 p r i n t f ("%d\n" , aux−>i n f o r m a c a o ) ;
54 p r i n t f ("\n" ) ;
55 }
56
57 i n t main ( void ) {
58 i n t numero = 0 , opcao = 0 ;
59 P i l h a ∗ p i l h a = ( P i l h a ∗ ) m a l loc ( s i z e o f ( P i l h a ) ) ;
60 i f ( ! p i l h a ) {
61 p r i n t f ("\nErro ao alocar memória.\n" ) ;
62 g e t c h a r ( ) ;
63 e x i t ( 1 ) ;
64 }
65 p i l h a −>topo = NULL;
66
67 whi le ( opcao ! = 4 ) {
68 p r i n t f ("\n1-Push.\n2-Pop.\n3-Mostra.\n4-Sai.\n" ) ;
69 p r i n t f ("Opcao: " ) ;
70s c a n f ("%d" ,& opcao ) ;
71 sw i t ch ( opcao ) {
72 case 1 :
73 p r i n t f ("\nInformacao: " ) ;
74 s c a n f ("%d" ,&numero ) ;
75 push ( p i l h a , numero ) ;
76 break ;
77 case 2 :
78 numero = pop ( p i l h a ) ;
79 p r i n t f ("\nRetirado %d\n" , numero ) ;
8.3 Exemplos 31
80 break ;
81 case 3 :
82 m o s t r a P i l h a ( p i l h a ) ;
83 break ;
84 }
85 }
86 }
A implementação proposta tem uma pequena diferença do que vínhamos fazendo. Existe um estrutura
Pilha que contém apenas um ponteiro para uma estrutura do tipo Elemento.
Algumas consequências interessantes podem ser notadas. Quando o ponteiro para a pilha é passado
como argumento para uma função, não é necessário que ele seja retornado pela função após serem feitas as
modificações (push e pop). Isto ocorre porque as modificações são feitas a partir do segundo ponteiro, ou
seja, o único campo da estrutura Pilha, que aponta para o topo da pilha.
Vamos discutir mais o funcionamento:
Pilha *pilha = (Pilha *) malloc( sizeof(Pilha) );
pilha aponta para uma estrutura do tipo Pilha. Esta estrutura contém um campo chamado topo que é
um ponteiro para uma estrutura do tipo Elemento. Quando o ponteiro pilha é passado como argumento
para a função push, por exemplo, um elemento é empilhado. O ponteiro topo passa a apontar para este
novo elemento e o novo elemento passa a pontar para o antigo topo da pilha. O tempo todo (antes e depois
da chamada da função push), o ponteiro pilha permanece apontando para a estrutura Pilha e, consequente-
mente, para o ponteiro topo. Assim, após a execução da função, a pilha já está atualizada no programa
principal.
O mesmo ocorre com a função pop, permitindo ainda que seja retorna um int, o número desempilhado,
sem a necessidade de se retornar um ponteiro atualizado, como fazíamos nas listas encadeadas (Capítulo 7).
Capítulo 9
Filas
9.1 Introdução
F ila é uma lista linear em que a inserção é feita numa extremidade e a eliminação na outra. Deste modo,dizemos que funciona no esquema FIFO: first in, first out ou PCPS: primeiro a chegar, primeiro a sair.
Para lembrar, pense nas filas que vemos no dia a dia: filas de banco, de supermercado, etc.
9.2 Exemplos
Programa 9.1: Fila01
1 # i n c l u d e < s t d i o . h>
2 # i n c l u d e < s t d l i b . h>
3
4 /∗ Nó ( e l e m e n t o ) da f i l a ( e s t r u t u r a ) ∗ /
5 s t r u c t TipoElemento {
6 i n t i n f o r m a c a o ;
7 s t r u c t TipoElemento ∗proximo ;
8 } ;
9
10 t y p e d e f s t r u c t TipoElemento Elemento ;
11
12 /∗ A e s t r u t u r a F i l a ∗ /
13 s t r u c t T i p o F i l a {
14 Elemento ∗ i n i c i o , ∗ f im ;
15 } ;
16
17 t y p e d e f s t r u c t T i p o F i l a F i l a ;
18
9.2 Exemplos 33
19 /∗ I n s e r ç ã o de e l e m e n t o ( sempre no f i m da f i l a ) ∗ /
20 void f i l a I n s e r e ( F i l a ∗ f , i n t dado ) {
21
22 Elemento ∗novo = ( Elemento ∗ ) m a l lo c ( s i z e o f ( Elemento ) ) ;
23
24 i f ( ! novo ) {
25 p r i n t f ("\nErro criando novo elemento." ) ;
26 re turn ;
27 }
28
29 novo−>i n f o r m a c a o = dado ;
30 novo−>proximo = NULL;
31
32 i f ( f−>fim ) / / o mesmo que ( p−>f i m != NULL) , i n d i c a F i l a não v a z i a
33 f−>fim−>proximo = novo ;
34 e l s e / / F i l a v a z i a
35 f−> i n i c i o = novo ;
36
37 f−>fim = novo ;
38 }
39
40 /∗ Remoção de e l e m e n t o ( sempre do i n i c i o da f i l a ) ∗ /
41 i n t f i l a R e t i r a ( F i l a ∗ f ) {
42
43 Elemento ∗p ;
44 i n t dado ;
45
46 p = f−> i n i c i o ;
47 dado = p−>i n f o r m a c a o ;
48 f−> i n i c i o = p−>proximo ;
49
50 i f ( ! f−> i n i c i o ) / / F i l a f i c o u v a z i a
51 f−>fim = NULL;
52
53 f r e e ( p ) ;
54
55 re turn ( dado ) ;
56 }
57
58 /∗ Ex ibe o menu e r e t o r n a a opção e s c o l h i d a ∗ /
59 i n t menu ( ) {
60
61 i n t opcao ;
62 p r i n t f ("\n" ) ;
63 p r i n t f ("\n +-------------------------+" ) ;
64 p r i n t f ("\n | Fila |" ) ;
65 p r i n t f ("\n |-------------------------|" ) ;
66 p r i n t f ("\n | 1 - Insere |" ) ;
9.2 Exemplos 34
67 p r i n t f ("\n | 2 - Retira |" ) ;
68 p r i n t f ("\n | 3 - Exibe a fila |" ) ;
69 p r i n t f ("\n | 4 - Limpa a fila |" ) ;
70 p r i n t f ("\n | 5 - Sai do programa |" ) ;
71 p r i n t f ("\n +-------------------------+" ) ;
72 p r i n t f ("\n\n Digite sua opcao: " ) ;
73
74
75 s c a n f ("%d" , &opcao ) ;
76
77 re turn ( opcao ) ;
78 }
79
80 /∗ Lê e r e t o r n a um número i n t e i r o ∗ /
81 i n t l e I n t e i r o ( ) {
82
83 i n t numero ;
84
85 p r i n t f ("\nDigite um numero: " ) ;
86 s c a n f ("%d" ,&numero ) ;
87
88 re turn ( numero ) ;
89 }
90
91 /∗ Exibe a F i l a ( p o s i ç ã o c o r r e t a do " f i m da f i l a " só f u n c i o n a se a f i l a c o n t i v e r apenas
92 ∗ números p o s i t i v o s e n t r e 0 e 999) e se não houver quebra de l i n h a ∗ /
93 void m o s t r a F i l a ( F i l a ∗ f ) {
94
95 Elemento ∗p ;
96
97 /∗ p o s i c i o n a a p a l a v r a f i m ∗ /
98 p r i n t f ("\n " ) ;
99 f o r ( p = f−> i n i c i o ; p ; p = p−>proximo ) {
100 i f ( p−>i n f o r m a c a o < 10 )
101 p r i n t f (" " ) ;
102 e l s e {
103 i f ( p−>i n f o r m a c a o < 100)
104 p r i n t f (" " ) ;
105 e l s e
106 p r i n t f (" " ) ;
107 }
108 }
109 p r i n t f ("fim" ) ;
110
111 /∗ p o s i c i o n a o " p i p e " ∗ /
112 p = f−> i n i c i o ;
113 p r i n t f ("\n " ) ;
114 f o r ( p = f−> i n i c i o ; p ; p = p−>proximo ) {
9.2 Exemplos 35
115 i f ( p−>i n f o r m a c a o < 10 )
116 p r i n t f (" " ) ;
117 e l s e {
118 i f ( p−>i n f o r m a c a o < 100)
119 p r i n t f (" " ) ;
120 e l s e
121 p r i n t f (" " ) ;
122 }
123 }
124 p r i n t f ("|" ) ;
125
126 /∗ p o s i c i o n a o V ( " pon ta da s e t a pra b a i x o " ) ∗ /
127 p r i n t f ("\n " ) ;
128 f o r ( p = f−> i n i c i o ; p ; p = p−>proximo ) {
129 i f ( p−>i n f o r m a c a o < 10 )
130 p r i n t f (" " ) ;
131 e l s e {
132 i f ( p−>i n f o r m a c a o < 100)
133 p r i n t f (" " ) ;
134 e l s e
135 p r i n t f (" " ) ;
136 }
137 }
138 p r i n t f ("V" ) ;
139
140 p r i n t f ("\ninicio->" ) ;
141 f o r ( p = f−> i n i c i o ; p ; p = p−>proximo )
142 p r i n t f ("%d->" , p−>i n f o r m a c a o ) ;
143 p r i n t f ("NULL\n" ) ;
144
145 } / / f i m m o s t r a F i l a
146
147 /∗ Limpa a f i l a ∗ /
148 void l i m p a F i l a ( F i l a ∗ f ) {
149
150 Elemento ∗p = f−>i n i c i o , ∗ a n t ;
151
152 f−> i n i c i o = f−>fim = NULL;
153
154 do {
155 a n t = p ;
156 p = p−>proximo ;
157 f r e e ( a n t ) ;
158 } whi le ( p ) ;
159
160 }
161
162 /∗ Programa p r i n c i p a l ∗ /
9.2 Exemplos 36
163 i n t main ( void ) {
164
165 i n t numero = 0 , opcao = 0 ;
166
167 F i l a ∗ f i l a = ( F i l a ∗ ) m a l loc ( s i z e o f ( F i l a ) ) ;
168
169 i f ( ! f i l a ) {
170 p r i n t f ("\nErro inicializando a fila.\n" ) ;
171 re turn ( 0 ) ;
172 }
173
174 f i l a −> i n i c i o = f i l a −>fim = NULL;
175
176 whi le ( opcao ! = 5 ) {
177
178 opcao = menu ( ) ;
179
180 sw i t ch ( opcao ) {
181
182 case 1 :
183 numero = l e I n t e i r o ( ) ;
184 f i l a I n s e r e ( f i l a , numero ) ;
185 break ;
186
187 case 2 :
188 i f ( ! f i l a −> i n i c i o ) / / o mesmo que ( f−>i n i c i o ==
NULL) , i n d i c a F i l a v a z i a
189 p r i n t f ("\nFila vazia." ) ;
190 e l s e
191 p r i n t f ("\n Elemento retirado da fila: %d" ,
f i l a R e t i r a ( f i l a ) ) ;
192 break ;
193
194 case 3 :
195 m o s t r a F i l a ( f i l a ) ;
196 break ;
197
198case 4 :
199 i f ( f i l a −> i n i c i o )
200 l i m p a F i l a ( f i l a ) ;
201 break ;
202
203 case 5 :
204 p r i n t f ("\n" ) ;
205 break ;
206
207 d e f a u l t :
208 p r i n t f ("\n Opcao invalida." ) ;
9.3 Exercícios propostos 37
209 }
210 }
211 }
9.3 Exercícios propostos
9.3.1 Retira dois elementos da fila
Faça um programa que receba números inteiros e os insira em uma fila. Deve haver uma função apara
que retira dois elementos da fila de cada vez (o primeiro e o último), e retorna a soma deles. Mostre no
programa o uso da referida função.
Exemplo: Inseridos X, Y, Z, K, M, L, P. Ao se chamar a função apara, ela retira X e P, e retorna (X+P).
9.3.2 Produto do 2o pelo último elemento da fila
Faça um programa que receba (leia) alguns números inteiros, inserindo-os em uma Fila. Em seguida, o
programa calcula e exibe o produto do segundo elemento da fila pelo último elemento da fila.
9.3.3 Concatenação de filas
Faça um programa que insira os números 9, 6, 3 em uma fila filaC, insira os números 8, 6, 4 na fila filaB e
os números 0, 11, 121 na fila filaA. Nenhum número deve ser pedido ao usuário ou digitado via teclado.
Depois de criadas as 3 filas, as filas filaB e filaA devem ser colocadas no final da filaC, gerando a fila 9, 6,
3, 8, 6, 4, 0, 11, 121.
9.3.4 Roteador com 4 filas
Simule um roteador de rede que receba pacotes por uma interface de entrada e envie por uma de três
interfaces de saída que ele possui segundo algum critério. Use estruturas de dados dinâmicas para gerenciar
o processo.
http://www.jabour.com.br
Capítulo 10
Recursividade
10.1 Introdução
N
este capítulo estudaremos o conceito e aplicações da recursividade.
No Capítulo 3 estudamos as funções. Para relembrar, no programa 3.2, tínhamos a situação em que
a função principal main chamava outra função, a função calculaMedia. Esta era executada e quando
terminava, retornava o fluxo de execução para a main.
Agora imagine a situação em que um função chama a si mesma dentro do seu código. Isto é permitido,
muito usado e se chama Recursividade.
Assim, podemos ter a seguinte situação:
Função main em execução
⇒ main chama a funçãoXYZ
⇒ instância 1 da funçãoXYZ em execução
⇒ instância 1 da funçãoXYZ chama a si mesma
⇒ instância 2 da funçãoXYZ em execução
⇒ instância 2 da funçãoXYZ chama a si mesma
⇒ instância 3 da funçãoXYZ em execução
⇒ instância 3 da funçãoXYZ termina
⇒ fluxo de execução retorna para a instância 2 de execução da funçãoXYZ
⇒ instância 2 da funçãoXYZ termina
⇒ fluxo de execução retorna para a instância 1 da funçãoXYZ
⇒ instância 1 da funçãoXYZ termina
⇒ fluxo de execução volta para a função principal main.
10.1 Introdução 39
A seguir, apresentaremos o “Hello World” dos programas recursivos (Programa 10.1).
Programa 10.1: Cálculo do fatorial com recursividade
1 /∗ f a t o r i a l − F i l i p p e Jabour − 5 / 1 1 / 2 0 0 6
2 C a l c u l a o f a t o r i a l de forma r e c u r s i v a
3 ∗ /
4
5 # i n c l u d e < s t d i o . h>
6
7 f l o a t f a t o r i a l ( i n t argumento ) {
8
9 f l o a t r e s u l t a d o L o c a l = 1 ;
10
11 i f ( a rgumento > 1)
12 r e s u l t a d o L o c a l = argumento ∗ f a t o r i a l (−−argumento ) ;
13
14 re turn ( r e s u l t a d o L o c a l ) ;
15 }
16
17 i n t main ( ) {
18
19 f l o a t r e s u l t a d o = 1 ;
20 i n t numero ;
21
22 p r i n t f ("\nCalculo do Fatorial" ) ;
23 p r i n t f ("\nDigite o numero: " ) ;
24 s c a n f ("%d" , &numero ) ;
25
26 i f ( numero == 0 ) {
27 p r i n t f ("O fatorial de %d eh %.0f\n" , numero , r e s u l t a d o ) ;
28 re turn ;
29 }
30
31 i f ( numero < 1 )
32 re turn ;
33
34 r e s u l t a d o = f a t o r i a l ( numero ) ;
35
36 p r i n t f ("O fatorial de %d eh %.0f\n\n" , numero , r e s u l t a d o ) ;
37 }
Observe que a função main faz a primeira chamada à função fatorial, passando como argumento o
número digitado pelo usuário. A função fatorial, sempre que recebe um argumento maior que 1, chama a si
mesma novamente, passando como argumento o número que recebeu, decrementado em uma unidade. Isto
acontece tantas vezes quantas forem necessárias (em função do número cujo fatorial desejamos calcular).
Quando a função fatorial recebe 1 como argumento, ela não entra do if e retorna o valor 1. A função
10.1 Introdução 40
que chamou esta última instância que retornou 1, estava parada dentro do if, aguardando o retorno da
chamada recursiva. Quando recebe o valor 1, faz a multiplicação do argumento que havia recebido (2)
pelo 1 que recebeu, retorna o resultado (2) para quem a chamou, terminando a sua execução. A instância
imediatamente anterior, recebe o 2, multiplica por 3 e retorna o 6. Este processo se repete, até o fluxo de
execução voltar à função main, que exibe o fatorial calculado. Neste retorno das diversas instâncias das
chamadas recursivas, dizemos que as funções estão sendo desempilhadas.
O Programa 10.2) imprime mensagens a cada chamada recursiva e a cada término de função. Talvez ele
esclareça o funcionamento da recursividade.
Programa 10.2: Cálculo do fatorial com recursividade com mensagens
1 # i n c l u d e < s t d i o . h>
2
3 i n t i n s t a n c i a ;
4
5 f l o a t f a t o r i a l ( i n t argumento ) {
6
7 i n t j ;
8 p r i n t f ("\n\n" ) ;
9 f o r ( j =1 ; j <= i n s t a n c i a ; j ++) p r i n t f ("\t" ) ;
10 p r i n t f ("Instancia %d da funcao fatorial em execucao." ,++ i n s t a n c i a ) ;
11
12 f l o a t r e s u l t a d o L o c a l = 1 ;
13
14 i f ( a rgumento > 1) {
15
16 p r i n t f ("\n" ) ;
17 f o r ( j =1 ; j <= i n s t a n c i a ; j ++) p r i n t f ("\t" ) ;
18 p r i n t f ("Argumento maior que 1, instancia %d da funcao fatorial farah uma
chamada recursiva." , i n s t a n c i a ) ;
19
20 r e s u l t a d o L o c a l = argumento ∗ f a t o r i a l (−−argumento ) ;
21
22 p r i n t f ("\n\n" ) ;
23 f o r ( j =1 ; j <= i n s t a n c i a −1; j ++) p r i n t f ("\t" ) ;
24 p r i n t f ("Instancia %d da funcao fatorial recebeu retorno, multiplicacao
deu %.0f.\n" , i n s t a n c i a , r e s u l t a d o L o c a l ) ;
25 f o r ( j =1 ; j <= i n s t a n c i a −1; j ++) p r i n t f ("\t" ) ;
26 p r i n t f ("Este valor serah retornado para a instancia %d" , i n s t a n c i a −1) ;
27 }
28 e l s e {
29 p r i n t f ("\n" ) ;
30 f o r ( j =1 ; j <= i n s t a n c i a ; j ++) p r i n t f ("\t" ) ;
31 p r i n t f ("Argumento igual a 1" ) ;
32 }
33
10.2 Exemplos 41
34 p r i n t f ("\n" ) ;
35 f o r ( j =1 ; j <= i n s t a n c i a −1; j ++) p r i n t f ("\t" ) ;
36 p r i n t f ("Instancia %d da funcao fatorial irah terminar." , i n s t a n c i a −−) ;
37
38 re turn ( r e s u l t a d o L o c a l ) ;
39 }
40
41 i n t main ( ) {
42
43 p r i n t f ("\nFuncao main em execucao." ) ;
44
45 f l o a t r e s u l t a d o = 1 ;
46 i n t numero ;
47
48 p r i n t f ("\nCalculo do Fatorial" ) ;
49 p r i n t f ("\nDigite o numero: " ) ;
50 s c a n f ("%d" , &numero ) ;
51
52 i f ( numero == 0 ) {
53 p r i n t f ("\n\nO fatorial de %d eh %.0f\n" , numero , r e s u l t a d o ) ;
54 re turn ;
55 }
56
57 i f ( numero < 1 )
58 re turn ;
59
60 r e s u l t a d o = f a t o r i a l ( numero ) ;
61
62 p r i n t f ("\n\nO fatorial de %d eh %.0f\n\n" , numero , r e s u l t a d o ) ;
63 }
10.2 Exemplos
No Programa 10.3 temos um exemplo de uso da lista encadeada com as funções implementadas com
recursividade.
A variável i conta as chamadas recursivas à função busca. A função limpa mostra a lista após a remoção
de cada elemento.
Programa 10.3: Lista encadeada com recursividade
1 # i n c l u d e < s t d i o . h>
2 # i n c l u d e < s t d l i b . h>3
4 i n t i =0 ;
5
10.2 Exemplos 42
6 s t r u c t no {
7 i n t i n f o ;
8 s t r u c t no∗ prox ;
9 } ;
10 t y p e d e f s t r u c t no No ;
11
12 No∗ i n s e r e ( No∗ l i s t a , i n t i ) {
13 No∗ novo = ( No∗ ) m a l lo c ( s i z e o f ( No ) ) ;
14 novo−>i n f o = i ;
15 novo−>prox = l i s t a ;
16 re turn novo ;
17 }
18
19 void imprime ( No∗ l i s t a ) {
20 i f ( l i s t a ) {
21 p r i n t f ("%d->" , l i s t a −>i n f o ) ;
22 imprime ( l i s t a −>prox ) ;
23 }
24 e l s e
25 p r i n t f ("NULL\n" ) ;
26 }
27
28 No∗ busca ( No∗ l i s t a , i n t v ) {
29 p r i n t f ("\n\t%d" ,++ i ) ;
30 No∗ achou = NULL;
31 i f ( l i s t a ) {
32 i f ( l i s t a −>i n f o == v ) {
33 p r i n t f ("\n\t%d" , i−−) ;
34 re turn ( l i s t a ) ;
35 }
36 e l s e {
37 i f ( l i s t a −>prox ) {
38 achou = busca ( l i s t a −>prox , v ) ;
39 p r i n t f ("\n\t%d" , i−−) ;
40 re turn ( achou ) ;
41 }
42 e l s e {
43 p r i n t f ("\n\t%d" , i−−) ;
44 re turn (NULL) ;
45 }
46 }
47 }
48 e l s e
49 re turn (NULL) ;
50 }
51
52 No∗ l impa ( No∗ l i s t a ) {
53 No∗ temp ;
10.2 Exemplos 43
54 i f ( l i s t a ) {
55 temp = l i s t a −>prox ;
56 f r e e ( l i s t a ) ;
57 p r i n t f ("\n" ) ;
58 imprime ( temp ) ;
59 l impa ( temp ) ;
60 }
61 re turn (NULL) ;
62 }
63
64 i n t main ( void ) {
65
66 No ∗ l i s t a , ∗ p r o c u r a d o = NULL;
67 l i s t a = NULL;
68 i n t numero , opcao = 0 ;
69
70 whi le ( opcao != 5 ) {
71 p r i n t f ("\n1-Insere.\n2-Imprime.\n3-Limpa.\n4-Busca\n5-Sai.\n" ) ;
72 p r i n t f ("Opcao: " ) ;
73 s c a n f ("%d" ,& opcao ) ;
74 sw i t ch ( opcao ) {
75 case 1 :
76 p r i n t f ("\nDigite um número: " ) ;
77 s c a n f ("%d" ,&numero ) ;
78 l i s t a = i n s e r e ( l i s t a , numero ) ;
79 break ;
80 case 2 :
81 p r i n t f ("Lista->" ) ;
82 imprime ( l i s t a ) ;
83 p r i n t f ("\n" ) ;
84 break ;
85 case 3 :
86 l i s t a = l impa ( l i s t a ) ;
87 break ;
88 case 4 :
89 i =0 ;
90 p r i n t f ("\nDigite um número: " ) ;
91 s c a n f ("%d" ,&numero ) ;
92 p r o c u r a d o = busca ( l i s t a , numero ) ;
93 i f ( p r o c u r a d o )
94 p r i n t f ("\nAchou o número %d.\n" , p rocu rado−>i n f o )
;
95 e l s e
96 p r i n t f ("\nNão Achou.\n" ) ;
97 break ;
98 case 5 :
99 l i s t a = l impa ( l i s t a ) ;
100 }
10.3 Exercícios 44
101 }
102 }
10.3 Exercícios
10.3.1 Soma dos números de 0 a n com recursividade
Faça um programa recursivo que calcula a soma dos números de 0 a n.
Resposta: Programa 10.4.
10.3.2 Divisão com recursividade
Faça um programa que calcula x÷ y usando recursividade.
Resposta: Programa 10.5.
10.3.3 Soma dos elementos do vetor usando recursividade
Faça um programa recursivo que calcula a soma dos elementos de um vetor.
Resposta: Programa 10.6.
10.3.4 Contar números ímpares da lista encadeada usando recursividade
Faça um programa recursivo que conta quantos números ímpares existem em uma lista encadeada.
Resposta: Programa 10.7.
10.4 Resposta dos Exercícios
Resposta do exercício 10.3.1
Programa 10.4: Soma recursiva
1 # i n c l u d e < s t d i o . h>
2
3 i n t somaRecurs iva ( i n t n ) {
4 i f ( n > 0)
10.4 Resposta dos Exercícios 45
5 re turn ( n + somaRecur s iva ( n − 1) ) ;
6 e l s e
7 re turn 0 ;
8 }
9
10 i n t main ( ) {
11 i n t n , soma ;
12
13 p r i n t f ("\n n (positivo) = " ) ;
14 s c a n f ("%d" ,&n ) ;
15
16 i f ( n < 0 )
17 n = −1 ∗ n ;
18
19 p r i n t f ("\n\tSoma dos números de 0 a %d = %d\n\n" , n , somaRecur s iva ( n ) ) ;
20 }
Resposta do exercício 10.3.2
Programa 10.5: Divisão recursiva
1 # i n c l u d e < s t d i o . h>
2
3 i n t d i v i s a o R e c u r s i v a ( i n t numerador , i n t denominador ) {
4 i f ( numerador < denominador )
5 re turn 0 ;
6 e l s e
7 re turn ( d i v i s a o R e c u r s i v a ( numerador − denominador , denominador ) + 1 ) ;
8 }
9
10 i n t main ( ) {
11 i n t numerador , denominador , q u o c i e n t e ;
12
13 p r i n t f ("\n numerador = " ) ;
14 s c a n f ("%d" ,& numerador ) ;
15
16 p r i n t f ("\n denominador (positivo) = " ) ;
17 s c a n f ("%d" ,& denominador ) ;
18
19 i f ( denominador <= 0 ) {
20 p r i n t f ("\n\tDenominador deve ser positivo.\n\n" ) ;
21 re turn 0 ;
22 }
23
24 q u o c i e n t e = d i v i s a o R e c u r s i v a ( numerador , denominador ) ;
25
26 p r i n t f ("\n\t%d / %d = %d (resto %d)\n\n" , numerador , denominador , q u o c i e n t e ,
numerador − denominador ∗ q u o c i e n t e ) ;
10.4 Resposta dos Exercícios 46
27 }
Resposta do exercício 10.3.3
Programa 10.6: Soma recursiva dos elementos do vetor
1 # i n c l u d e < s t d i o . h>
2
3 i n t s o m a V e t o r R e c u r s i v a ( i n t v e t o r [ ] , i n t p o s i c a o ) {
4 i f ( p o s i c a o >= 0 )
5 re turn ( v e t o r [ p o s i c a o ] + s o m a V e t o r R e c u r s i v a ( v e t o r , −−p o s i c a o ) ) ;
6 e l s e
7 re turn 0 ;
8 }
9
10 i n t main ( ) {
11 i n t p o s i c a o ;
12
13 i n t vetorUm [ 1 0 ] = {1 , 3 , 5 , 7 , 9 , 0 , 2 , 4 , 6 , 8 } ;
14 p r i n t f ("\nSoma dos elementos do vetor = %d\n" , s o m a V e t o r R e c u r s i v a ( vetorUm , 9 ) ) ;
15
16 i n t v e t o r D o i s [ 1 ] = { 2 0 } ;
17 p r i n t f ("\nSoma dos elementos do vetor = %d\n" , s o m a V e t o r R e c u r s i v a ( v e t o r D o i s , 0 ) ) ;
18
19 i n t v e t o r T r e s [ 2 ] = {67 , −67};
20 p r i n t f ("\nSoma dos elementos do vetor = %d\n" , s o m a V e t o r R e c u r s i v a ( v e t o r T r e s , 1 ) ) ;
21 }
Resposta do exercício 10.3.4
Programa 10.7: Conta os ímpares da lista encadeada com recursividade
1 # i n c l u d e < s t d i o . h>
2 # i n c l u d e < s t d l i b . h>
3
4 s t r u c t t i p o L i s t a {
5 i n t numero ;
6 s t r u c t t i p o L i s t a ∗proximo ;
7 } ;
8
9 t y p e d e f s t r u c t t i p o L i s t a L i s t a ;
10
11 i n t c o n t a I m p a r e s ( L i s t a ∗ l i s t a ) {
12 i f ( ! l i s t a )
13 re turn 0 ;
14 e l s e {
15 i f ( l i s t a −>numero % 2 == 1 )
16 re turn ( c o n t a I m p a r e s ( l i s t a −>proximo ) + 1) ;
17 e l s e
10.4 Resposta dos Exercícios 47
18 re turn ( c o n t a I m p a r e s ( l i s t a −>proximo ) ) ;
19 }
20 }
21
22 i n t main ( ) {
23 i n t i ;
24 L i s t a ∗ l i s t a = NULL, ∗novo , ∗ p e r c o r r e , ∗aux ;
25
26 / / T e s t e um
27 f o r ( i = 0 ; i < 5 ; i ++ ) {
28 novo = ( L i s t a ∗ ) ( m a l lo c ( s i z e o f ( L i s t a ) ) ) ;
29 i f ( novo ) {
30 novo−>numero = i ;
31 novo−>proximo = l i s t a ;
32 l i s t a = novo ;
33 }
34 }
35 p e r c o r r e = l i s t a ;
36 p r i n t f ("\n\nLista => " ) ;
37 f o r ( ; p e r c o r r e ; p e r c o r r e = p e r c o r r e −>proximo )
38 p r i n t f ("\t%d" , p e r c o r r e −>numero ) ;
39 p r i n t f ("\nQuantidade de ímpares = %d\n" , c o n t a I m p a r e s ( l i s t a ) ) ;
40 whi le ( l i s t a ) {
41 p e r c o r r e = l i s t a −>proximo ;
42 f r e e ( l i s t a ) ;
43 l i s t a = p e r c o r r e ;
44 }
45 / / Fim t e s t e Um
46
47 / / T e s t e Dois
48 f o r ( i = 0 ; i < 10 ; i = i + 2 ) {
49 novo = ( L i s t a ∗ ) ( m a l loc ( s i z e o f ( L i s t a ) ) ) ;
50 i f ( novo ) {
51 novo−>numero = i ;
52 novo−>proximo = l i s t a ;
53 l i s t a = novo ;
54 }
55 }
56 p e r c o r r e = l i s t a ;
57 p r i n t f ("\n\nLista => " ) ;
58 f o r ( ; p e r c o r r e ; p e r c o r r e = p e r c o r r e −>proximo )
59 p r i n t f ("\t%d" , p e r c o r r e −>numero ) ;
60 p r i n t f ("\nQuantidade de ímpares = %d\n" , c o n ta I m p a r e s ( l i s t a ) ) ;
61 whi le ( l i s t a ) {
62 p e r c o r r e = l i s t a −>proximo ;
63 f r e e ( l i s t a ) ;
64 l i s t a = p e r c o r r e ;
65 }
10.4 Resposta dos Exercícios 48
66 / / Fim t e s t e Dois
67
68 / / T e s t e Três
69 l i s t a = ( L i s t a ∗ ) ( m a l lo c ( s i z e o f ( L i s t a ) ) ) ;
70 i f ( l i s t a ) {
71 l i s t a −>numero = 3 ;
72 l i s t a −>proximo = NULL;
73 }
74 p e r c o r r e = l i s t a ;
75 p r i n t f ("\n\nLista => " ) ;
76 f o r ( ; p e r c o r r e ; p e r c o r r e = p e r c o r r e −>proximo )
77 p r i n t f ("\t%d" , p e r c o r r e −>numero ) ;
78 p r i n t f ("\nQuantidade de ímpares = %d\n" , c o n t a I m p a r e s ( l i s t a ) ) ;
79 whi le ( l i s t a ) {
80 p e r c o r r e = l i s t a −>proximo ;
81 f r e e ( l i s t a ) ;
82 l i s t a = p e r c o r r e ;
83 }
84 / / Fim t e s t e Três
85
86 / / T e s t e Quatro
87 l i s t a = ( L i s t a ∗ ) ( m a l lo c ( s i z e o f ( L i s t a ) ) ) ;
88 i f ( l i s t a ) {
89 l i s t a −>numero = 4 ;
90 l i s t a −>proximo = NULL;
91 }
92 p e r c o r r e = l i s t a ;
93 p r i n t f ("\n\nLista => " ) ;
94 f o r ( ; p e r c o r r e ; p e r c o r r e = p e r c o r r e −>proximo )
95 p r i n t f ("\t%d" , p e r c o r r e −>numero ) ;
96 p r i n t f ("\nQuantidade de ímpares = %d\n" , c o n t a I m p a r e s ( l i s t a ) ) ;
97 whi le ( l i s t a ) {
98 p e r c o r r e = l i s t a −>proximo ;
99 f r e e ( l i s t a ) ;
100 l i s t a = p e r c o r r e ;
101 }
102 / / Fim t e s t e Quatro
103
104 / / T e s t e Cinco
105 p r i n t f ("\n\nLista => " ) ;
106 p r i n t f ("\nQuantidade de ímpares = %d\n" , c o n t a I m p a r e s ( l i s t a ) ) ;
107 / / Fim t e s t e Cinco
108
109 p r i n t f ("\n\n" ) ;
110 }
Capítulo 11
Árvores
E
m diversas aplicações, necessita-se de estruturas mais complexas do que as puramente sequenciais.
Entre essas, destacam-se as árvores, por existirem inúmeros problemas práticos que podem ser mod-
elados através delas. Além disso, as árvores, em geral, admitem um tratamento computacional simples e
eficiente.
11.1 Definições e representações básicas
A forma mais comum de representar graficamente uma árvore é através de sua representação hierárquica.
A representação da Figura 11.1, com a raiz no topo (nó A), é a mais empregada na literatura da computação.
A
C
ED
B
Figura 11.1: Representação hierárquica de uma árvore
Seja v o nó raiz da subárvore Tv de T . Os nós raízes w1, w2, . . . , wj das subárvores de Tv são chama-
dos filhos de v; v é chamado pai de w1, w2, . . . , wj . Os nós w1, w2, . . . , wj são irmãos. Se z é filho de
w1, então w2 é tio de z e v é avô de z. O número de filhos de um nó é chamado grau de saída desse nó.
x ∈ Tv → x é descendente de v ∧ v é ancestral de x. Nesse caso, sendo x 6= v, x é descendente próprio
de v, e v é ancestral próprio de x. Um nó que não possui descendentes próprios é chamado folha.
Um sequência de nós distintos v1, v2, . . . , vk | ∃ sempre entre nós consecutivos (v1 e v2, v2 e v3, . . . ,
vk−1 e vk) a relação “é filho de” ou “é pai de”, é denominado um caminho da árvore. Diz-se que v1
11.1 Definições e representações básicas 50
alcança vk e vice-versa. Um caminho de k vértices (nós) é obtido pela sequência de k − 1 pares da relação
citada acima. O valor k−1 é o comprimento do caminho. Nível de um nó v é o número de nós do caminho
da raiz até o nó v. O nível da raiz é 1. A altura de um nó v é o número de nós do maior caminho de v até
um de seus descendentes. As folhas têm altura 1. A altura da árvore T é igual ao nível máximo de seus nós.
Representa-se a altura de T por h(T ), enquanto h(v) é a altura da subárvore de raiz v.
Observe a árvore T da Figura 11.2. O vértice C é ancestral próprio de G, de H e de F , entre outros. O
nó D é descendente próprio de A. O nível do vértice F é 3 e sua altura é 2; o nível do vértice A é 1 e sua
altura é 4. A altura da árvore é 4.
A
C
F
I
ED
HG
B
Figura 11.2: Análise de uma árvore
Uma árvore ordenada é aquela na qual os filhos de cada nó estão ordenados. Assume-se que tal orde-
nação se desenvolva da esquerda para a direita.
Capítulo 12
Árvores Binárias
D
entre as árvores, as binárias são, sem dúvida, as mais comuns em computação.
12.1 Definições
Uma árvore binária T é um conjunto finito de elementos denominados nós ou vértices, tal que:

T = ∅ (Árvore vazia), ou
∃ r (nó raiz de T) e os demais nós podem ser divididos em dois subconjuntos disjuntos TEr e TDr
TEr e T
D
r são, respectivamente, a subárvore esquerda e direita de r
TEr e T
D
r são também árvores binárias
O nó raiz da subárvore esquerda (direita) de v, se existir, é denominado filho esquerdo (direito) de v.
Pode existir apenas o filho esquerdo, apenas o direito, ou ambos.
Uma árvore estritamente binária é uma árvore binária em que cada nós possui 0 ou 2 filhos. Uma
árvore binária completa é aquela que possui a seguinte propriedade: se v é um nó tal que alguma subárvore
de v é vazia, então v se localiza ou no último (maior) ou no penúltimo nível da árvore. Uma árvore
binária cheia é aquela em que, se v é um nó com alguma de suas subárvores vazias, então v se localiza no
último nível. Toda árvore binária cheia é completa e estritamente binária. Como exemplo, a Figura 12.1
é estritamente binária, mas não completa. A árvore da Figura 12.2 é completa, mas não cheia e a da
Figura 12.3 é cheia.
12.2 Exemplos 52
A
C
GD
FE
B
Figura 12.1: Árvore estritamente binária
A
E
IF
HG
B
DC
Figura 12.2: Árvore binária completa
12.2 Exemplos
O Programa 12.1 cria a estrutura do nó da árvore binária com a informação a ser armazenada no nó
(info) e com os ponteiros para os filhos esquerdo e direito. Na função main, a árvore é criada de forma
estática no código fonte. Em seguida, a árvore é impressa na tela de duas formas. Na primeira, é feita uma
formatação manual da impressão e na segunda é usada uma função recursiva mostra_arvore que imprime
a árvore “deitada”.
Programa 12.1: Criação e impressão de uma árvore binária
A
I
M
ON
J
LK
B
F
HG
C
ED
Figura 12.3: Árvore binária cheia
12.2 Exemplos 53
1 # i n c l u d e < s t d l i b . h>
2 # i n c l u d e < s t d i o . h>
3
4 s t r u c t t i poNo {
5 char i n f o ;
6 s t r u c t t i poNo ∗ e s q u e r d a ;
7 s t r u c t t i poNo ∗ d i r e i t a ;
8 } ;
9
10 t y p e d e f s t r u c t t i poNo no ;
11
12 void m o s t r a _ a r v o r e ( no ∗ r , i n t l ) {
13 i n t i ;
14
15 i f ( ! r )
16 re turn ;
17
18 m o s t r a _ a r v o r e ( r−> d i r e i t a , l +1) ;
19 f o r ( i =0 ; i < l ; ++ i )
20 p r i n t f ("\t" ) ;
21 p r i n t f ("%c\n" , r−>i n f o ) ;
22 m o s t r a _ a r v o r e ( r−>esque rda , l +1) ;
23 }
24
25 i n t main ( void ) {
26 char a u x I n f o ;
27
28 no ∗ r a i z , ∗ temp = NULL;
29
30 r a i z = ( no ∗ ) m a l lo c ( s i z e o f ( no ) ) ;
31 r a i z −>i n f o = ’A’ ;
32 r a i z −>e s q u e r d a = NULL;
33 r a i z −> d i r e i t a = NULL;
34
35 temp = ( no ∗ ) m a l lo c ( s i z e o f ( no ) ) ;
36 temp−>i n f o = ’B’ ;
37 temp−>e s q u e r d a = NULL;
38 temp−> d i r e i t a = NULL;
39
40 r a i z −>e s q u e r d a = temp ;
41
42 temp = ( no ∗ ) m a l lo c ( s i z e o f ( no ) ) ;
43 temp−>i n f o = ’C’ ;
44 temp−>e s q u e r d a = NULL;
45 temp−> d i r e i t a = NULL;
46
47 r a i z −> d i r e i t a = temp ;
48
12.2 Exemplos 54
49 temp = ( no ∗ ) m a l lo c ( s i z e o f ( no ) ) ;
50 temp−>i n f o = ’D’ ;
51 temp−>e s q u e r d a = NULL;
52 temp−> d i r e i t a = NULL;
53
54 r a i z −>esque rda−>e s q u e r d a = temp ;
55
56 temp = (

Outros materiais

Materiais relacionados

Perguntas relacionadas

Perguntas Recentes