Você está na página 1de 138

01_laboratorio_de_estrutura_de_dados_i.

qxp 5/8/2008 15:48 Page 1

Laboratório de
Estrutura de Dados I
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 2

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

2
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 3

Universidade do Estado do Amazonas

Tecnologia em Análise e Desenvolvimento de Sistemas


(Sistema Presencial Mediado)

Danielle Gordiano Valente


Danielle Pompeu Noronha Pontes
Salvador Ramos Bernardino da Silva

Laboratório de
Estrutura de Dados I

Manaus - AM

2008
3
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 4

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Ficha Técnica

Governo do Estado do Amazonas

Carlos Eduardo de Souza Braga


Governador do Estado

Omar José Abdel Aziz


Vice-Governador do Estado

Universidade do Estado do Amazonas

Marilene Corrêa da Silva Freitas


Reitora

Carlos Eduardo de Souza Gonçalves


Vice-Reitor

Fares Franc Abinader Rodrigues


Pró-Reitor de Administração

Osail Medeiros de Souza


Pró-Reitor de Planejamento

Edinea Mascarenhas Dias


Pró-Reitora de Ensino de Graduação

José Luiz de Souza Pio


Pró-Reitor de Pós-Graduação e Pesquisa

Rogelio Casado Marinho Filho


Pró-Reitor de Extensão e Assuntos Comunitários

Escola Superior de Tecnologia

Vicente de Paulo Queiroz Nogueira


Diretor

Curso Superior de Tecnologia em Análise e Desenvolvimento de Sistemas


(Sistema Presencial Mediado por Tecnologia)

Ednaldo Coelho Pereira


Coordenador Geral

Ângela Timótia Pereira Lima


Coordenadora Pedagógica

Nilo Barreto Falcão Neto


Coordenador de Tecnologia Educacional

Érica Lima
Projeto gráfico

Diana Maria da Câmara Gorayeb


Revisão

Valente, Danielle Gordiano.

V154lab Laboratório de estrutura de dados I / Danielle Gordiano Valente, Danielle


Pompeu Noronha Pontes, Salvador Ramos Bernardino da Silva – Manaus/AM: UEA
Edições, 2008.

138 p.: il. ; 23 cm.

Inclui bibliografia e anexo.


ISBN 978-85-89453-87-5

1.Estrutura de dados. 2. Programação (Computadores). I. Pontes, Danielle Pompeu


Noronha. II. Silva, Salvador Ramos Bernardino da. III. Título.
CDU (1997): 004.422.63

4
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 5

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Perfil dos Autores

Danielle Gordiano Valente


Professora da Escola Superior de Tecnologia (EST/UEA)
Mestre em Ciência da Computação
pela Universidade de Minas Gerais (UFMG)

Danielle Pompeu Noronha Pontes


Professora da Escola Superior de Tecnologia (EST/UEA)
Especialista em Informática
pela Universidade Federal do Ceará (UFC)

Salvador Ramos Bernardino da Silva


Professor da Escola Superior de Tecnologia (EST/UEA)
Especialista em Desenvolvimento de Sistemas pela Universidade
Federal do Amazonas (UFAM)

5
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 6

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

6
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 7

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas
Palavra da Reitora

Nós últimos anos, o avanço da tecnologia da informática mudou os conceitos de


ensino e de trabalho. A preocupação com o que se denominou de "inclusão digital"
passou a ser um problema urgente a ser enfrentado pelos dirigentes do País, já que
todos os processos de novas tecnologias deságuam no conhecimento de informática.
No Amazonas, a dificuldade de locomoção na região, por falta de rodovias, por sua
grande extensão territorial, pela baixa densidade demográfica e pelo subdesenvolvi-
mento secular imposto à população ribeirinha, torna-se árduo o esforço do Governo
para tornar realidade à inclusão digital.

A UEA, que já nasceu moderna, incorporando tecnologias educacionais de


ponta, utilizando-se particularmente da informática pela massificação do uso de
microcomputadores combinados com uma rede complexa de acesso à Internet, não
poderia ficar alheia a essa necessidade premente. Por isso, propôs e realizou o
primeiro vestibular para levar a 12 municípios um curso que formasse a mão-de-obra
inicial que tornasse a inclusão digital uma realidade em nosso Estado.

A proposta do curso de Tecnologia em Análise e Desenvolvimento de Sistemas


oferecido pela UEA vislumbra criar mão-de-obra qualificada em um número significa-
tivo de localidades do Estado, cabendo às pessoas beneficiadas com essa iniciativa
a tarefa de irradiar o uso de tecnologias de informática, abrindo caminhos novos e
suscitando novos empregos para a população local, consolidando, assim, o exercício
da cidadania.

a a
Prof. Dr. Marilene Corrêa da Silva Freitas
Reitora da Universidade do Estado do Amazonas

7
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 8

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

8
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 9

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas
Sumário

Lista de Figuras ........................................................................11


Lista de Algoritmos....................................................................13
Lista de Programas ....................................................................15

CAPÍTULO 1 - IMPLEMENTANDO TIPOS ABSTRATOS DE DADOS ................19


1.1 INTRODUÇÃO.....................................................................19
1.2 DEFININDO UMA ESTRUTURA (STRUCT) ......................................19
1.3 TIPOS DEFINIDOS PELO USUÁRIO..............................................23
1.4 UTILIZANDO FUNÇÕES PARA AS OPERAÇÕES DO TAD.......................25
1.5 INDEPENDÊNCIA DE REPRESENTAÇÃO.........................................27

CAPÍTULO 2 - PONTEIROS E ALOCAÇÃO DINÂMICA DE MEMÓRIA .............33


2.1 INTRODUÇÃO.....................................................................33
2.2 DECLARAÇÃO DE VARIÁVEL TIPO PONTEIRO.................................33
2.3 ALOCAÇÃO DE MEMÓRIA........................................................37
2.3.1 ALOCAÇÃO DE VETOR E REGISTRO .........................................39

CAPÍTULO 3 - LISTAS ..................................................................45


3.1 INTRODUÇÃO.....................................................................45
3.2 IMPLEMENTAÇÃO DE LISTA ESTÁTICA .........................................45
3.3 IMPLEMENTAÇÃO DE LISTA SIMPLESMENTE ENCADEADA ...................53

CAPÍTULO 4 - PILHAS .................................................................59


4.1 INTRODUÇÃO.....................................................................59
4.2 PILHAS IMPLEMENTADAS POR VETORES ......................................59
4.3 PILHAS IMPLEMENTADAS POR VARIÁVEIS DINÂMICAS .......................65

CAPÍTULO 5 - FILAS ...................................................................69


5.1 INTRODUÇÃO.....................................................................69
5.2 FILAS IMPLEMENTADAS POR VETORES ........................................69
5.3 FILAS IMPLEMENTADAS POR VARIÁVEIS DINÂMICAS .........................74

CAPÍTULO 6 - RECURSIVIDADE ......................................................81


6.1 INTRODUÇÃO.....................................................................81
6.2 REVISANDO O CONCEITO DE RECURSIVIDADE ...............................81

EXERCÍCIOS..............................................................................89

9
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 10

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

ANEXO A - Implementação do TAD Conta utilizando vetores. - ...............95


ANEXO B - Implementação do TAD Lista utilizando vetores. ...................99
ANEXO C - Implementação do TAD Lista utilizando variáveis dinâmicas......103
ANEXO D- Implementação do TAD Pilha utilizando vetores. ....................111
ANEXO E - Implementação de pilha utilizando alocação dinâmica. ...........115
ANEXO F - Implementação de fila utilizando vetores............................121
ANEXO G - Implementação de fila utilizando alocação dinâmica..............127
ANEXO H - Implementação de fila circular. .......................................135

10
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 11

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Lista de Figuras

Figura 2.1: Representação esquemática de espaços de memória


Figura 2.2: Valor lido pelo Programa 2.2

Figura 3.1: Esquema da variável lista


Figura 3.2: Exemplo de valores constantes da lista

11
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 12

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

12
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 13

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Lista de Algoritmos

Algoritmo 2.1: Atribuição de endereços de variáveis a ponteiros


Algoritmo 2.2: Operador CONTEUDO.
Algoritmo 2.3: Alocação dinâmica de memória.
Algoritmo 2.4: Alocação de um vetor de inteiros.
Algoritmo 2.5: Alocação de um registro.
Algoritmo 2.6: Alocação de vetor de registro.
Algoritmo 3.1: Estrutura da lista
Algoritmo 3.2: Criação da lista vazia.
Algoritmo 3.3: Verifica se a lista está vazia.
Algoritmo 3.4: Estrutura para lista encadeada.

13
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 14

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

14
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 15

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Lista de Programas
Programa 1.1: Forma geral para definição de uma estrutura.
Programa 1.2: Aplicação da forma geral para definição de uma
estrutura de cliente.
Programa 1.3: Aplicação declarando duas variáveis do mesmo
tipo.
Programa 1.4: Declaração de variáveis do tipo estrutura como
variáveis locais.
Programa 1.5: Forma geral de referenciar um campo de uma var-
iável estrutura.
Programa 1.6: Criando 100 conjuntos de variáveis.
Programa 1.7: Percurso em todos os elementos de uma matriz de
estruturas.
Programa 1.8: Forma geral de definição de tipo – typedef.
Programa 1.9: Exemplo de utilização do typedef.
Programa 1.10: Exemplo de utilização do typedef com struct.
Programa 1.11: Forma geral da definição de uma função.
Programa 1.12: Exemplo de TAD básico.
Programa 1.13: Arquivo tadconta.h.
Programa 1.14: Arquivo tadconta.c.
Programa 1.15: Arquivo contendo o programa com a função prin-
cipal, main().

Programa 2.1: Atribuição de endereços de variáveis a ponteiros.


Programa 2.2: Operador CONTEUDO.
Programa 2.3: Alocação dinâmica de memória.
Programa 2.4: Alocação dinâmica de um vetor.
Programa 2.5: Alocação de um registro.
Programa 2.6: Declaração de tipo de variável registro.
Programa 2.7: Alocação de um vetor de registros.

15
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 16

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Programa 3.1: Estrutura da lista, no arquivo de cabeçalho


“lista.h”.
Programa 3.2: Criação da lista vazia.
Programa 3.3: Lista vazia.
Programa 3.4: Inserção de nós na lista.
Programa 3.5: Lista itens cadastrados.
Programa 3.6: Módulo principal.
Programa 3.7: Estrutura da lista encadeada.
Programa 3.8: Procedimento para apagar toda a lista.
Programa 3.9: Inserir dados na lista.
Programa 3.10: Imprime os nós da lista.

Programa 4.1. Definições de tipo e interface das operações do


TAD Pilha.
Programa 4.2. Procedimento Cria_Pilha.
Programa 4.3. Função Empilha.
Programa 4.4: Função Desempilha.
Programa 4.5: Função Consulta_Topo.
Programa 4.6: Função Pilha_Vazia.
Programa 4.8: Procedimento Cria_Pilha.
Programa 4.7: Definições de tipo e interface das operações do
TAD Pilha.
Programa 4.8: Procedimento Cria_Pilha.
Programa 4.9: Função Empilha com alocação dinâmica.
Programa 4.10: Função Desempilha com alocação dinâmica.
Programa 4.11. Função Consulta_Topo com alocação dinâmica.
Programa 4.12: Função Pilha_Vazia com alocação dinâmica.

Programa 5.1: Definições de tipo e interface das operações do


TAD Fila.
Programa 5.2: Procedimento Cria_Fila.
Programa 5.3: Função Enfileira.
Programa 5.4: Função Desenfileira.
Programa 5.5: Função Consulta_Frente.
16
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 17

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Programa 5.6: Função Quantidade_Fila.


Programa 5.7: Função Fila_Vazia.
Programa 5.8: Definições de tipo e interface das operações do
TAD Fila.
Programa 5.9: Procedimento Cria Fila.
Programa 5.10: Procedimento Enfileira.
Programa 5.11: Função Desenfileira.
Programa 5.12: Função Consulta_Frente.
Programa 5.13: Função Quantidade_Fila.
Programa 5.14. Função Fila Vazia.

Programa 6.1: Programa não recursivo em C.


Programa 6.2: Programa Recursivo em C.
Programa 6.3: Fatorial com recursão em C.
Programa 6.4: Máximo recursivo em C.
Programa 6.5: MDC recursivo em C.
Programa 6.6: Soma recursiva em C.

17
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 18

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

18
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 19

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Tecnologia em Ánalise
Desenvolvimento e
de Sistemas
Desenvolvimento de Sistemas

CAPÍTULO 1

Implementando
Tipos Abstratos de Dados
1.1 Introdução

Como foi apresentado em Estrutura de Dados I o conceito de Tipo


de Dados pode ser visto, não em termos do que um computador pode
fazer, mas em termos do que os usuários desejam fazer. Este conceito
de Tipo de Dados independente do hardware é chamado Tipo
Abstrato de Dados - TAD. Neste capítulo iremos tratar como imple-
mentar esta estrutura na Linguagem C.
Para implementar um TAD é necessário definir uma Estrutura de
Dados (ED) para representá-lo. A ED é definida a partir dos tipos
primitivos (inteiro, real, caractere, lógico) ou dos tipos compostos
(vetor, registro e matriz) da linguagem de programação, mais as oper-
ações definidas sobre a estrutura definida.
A Linguagem C permite ao programador criar tipos diferentes de
dados, que podem ser agrupados de diversas formas. Com este recur-
so é possível implementar TAD usando os “tipos de dados definidos
pelo programador” conhecidos como: estruturas e tipos definidos pelo
usuário (typedef).

1.2 Definindo uma estrutura (struct)

Uma estrutura é uma coleção de tipos, possivelmente diferentes,


referenciada por um nome, isto é, uma estrutura é uma forma de se
agrupar informações relacionadas. Estas informações são chamadas de
membros, elementos ou campos. Podem ser variáveis de tipos de
dados primitivos, vetores (tal como strings) ou até mesmo outras
estruturas.
O comando struct da Linguagem C é um tipo de dado, não existe
um espaço reservado na memória para ela até que seja declarada uma
variável para armazenar o tipo definido.
19
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 20

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

O Programa 1.1 apresenta a forma geral para definição de uma


estrutura. Esta estrutura é a base de um TAD. A lista de variáveis é
opcional.

struct nome_estrutura {
tipo nome_do_campo1;
tipo nome_da_campo2;
...
}[<lista_de_variáveis>];

Programa 1.1: Forma geral para definição de uma estrutura.

Observe, no exemplo no Programa 1.2, que TipoCliente é o nome


da estrutura. Na última linha do exemplo encontramos a definição da
variável cliente que será do tipo de estrutura TipoCliente. De acordo
com a definição da estrutura a variável possui três elementos: nome e
endereco ambos do tipo string e saldo do tipo ponto flutuante.

struct TipoCliente {
char nome[25];
char endereco[15];
float saldo;
} cliente;

Programa 1.2: Aplicação da forma geral para definição de uma estrutura de cliente

O Programa 1.3 mostra que se existirem duas ou mais variáveis,


que sejam do mesmo tipo de estrutura, é possível declará-las juntas:

struct TipoCliente {
char nome[25];
char endereco[15];
float saldo;
} clientePessoa, clienteEmpresa;

Programa 1.3: Aplicação declarando duas variáveis do mesmo tipo.

Outra forma de declarar uma variável estrutura é fora da


definição da estrutura. Preferencialmente, são declaradas como
variáveis locais de alguma função, como mostra o Programa 1.4.

20
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 21

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

struct cliente {
char nome[25];
char endereco[15];
float saldo;
};

main(){
struct cliente cliente1, cliente2, cliente3;

}

Programa 1.4: Declaração de variáveis do tipo estrutura como variáveis locais.

Quando é necessário referenciar os elementos da estrutura uti-


liza-se o ponto como operador, conforme exemplo do Programa 1.5.

nome_da_variavel.nome_do_campo;

Programa 1.5: Forma geral de referenciar um campo de uma variável estrutura.

Baseado no Programa 1.3 observe como são referenciadas as


variáveis:

scanf(“%s”, clientePessoa.nome);
strcpy(clienteEmpresa.nome, “MinhaEmpresa”);
clientePessoa.saldo = 2050.50;
clienteEmpresa.saldo = 2000400;
gets(cliempresa.nome);
scanf(“%s”, clienteEmpresa.endereco);

21
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 22

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Agora observe como é definido um vetor baseado em estruturas.


O Programa 1.6 define um vetor de estruturas que cria 100 conjuntos
de variáveis.

struct TipoCliente {
char nome[25];
char endereco[15];
float saldo;
} clientes[100];

Programa 1.6: Criando 100 conjuntos de variáveis.

Para entender como são referenciados os valores, observe a


matriz abaixo, onde as linhas são os registros dos vetores e as colunas
são as variáveis da estrutura.

Para referenciar cada elemento da matriz pode-se utilizar:


clientes[0].nome
clientes[0].saldo
clientes[2].nome
clientes[1].endereco

22
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 23

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

De acordo com o exemplo anterior os respectivos valores das


referências são:

Para percorrer toda a estrutura podemos utilizar a estrutura do


for, como no exemplo do Programa 1.7:

for (x = 0; x < 100; x++)


{
gets(clientes[x].nome);
gets(clientes[x].endereco);
scanf(“%f”, clientes[x].saldo);
}

Programa 1.7: Percurso em todos os elementos de uma matriz de estruturas.

1.3 Tipos definidos pelo usuário

Um TAD pode ser considerado uma generalização dos tipos primi-


tivos de dados já conhecidos e por isso podem ser usados para
encapsular os tipos de dados primitivos. Esta estratégia facilita qual-
quer tipo de alteração sobre o TAD, pois estão localizados em uma
única seção do programa. Na Linguagem C é permitido ao usuário
definir um novo nome para o tipo de dado que ele deseja declarar.
Essa forma de declaração é freqüentemente utilizada para tornar os
programas mais portáveis e também para documentação e
padronização. O Programa 1.8 mostra a forma geral para uso
do typedef.

23
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 24

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

typedef tipo novo_tipo;

Programa 1.8: Forma geral de definição de tipo – typedef.

No Programa 1.9 homem e mulher são variáveis do tipo idade,


onde o tipo idade é um outro nome para o tipo primitivo inteiro.

typedef int idade;


idade homem, mulher;

Programa 1.9: Exemplo de utilização do typedef.

O recurso do typedef pode ser usado em conjunto com o


comando struct para padronizar um tipo de dado do tipo estrutura,
como mostrado no Programa 1.9

typedef struct {
int dia;
int mes;
int ano;
}TipoData;

Programa 1.10: Exemplo de utilização do typedef com struct.

Para referenciar no programa usa-se:

24
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 25

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Após a execução dos comandos acima, os campos da variável data


terão os seguintes valores:

Fundamentalmente, um TAD significa uma representação dos


dados e as operações que serão efetuadas sobre essa representação.
Para isso, a definição de um TAD envolve duas partes: a definição dos
dados e a definição das operações. Até aqui foi apresentado como
implementar a definição dos dados através dos comandos struct e
typedef. Agora será apresentado como definir as operações de um
TAD.

1.4 Utilizando funções para as operações do TAD

Na linguagem de programação C é possível implementar as


operações dos TADs através de funções. A função é um seguimento
independente do programa que executa uma tarefa específica,
tornando assim o programa modular. Além desta vantagem
destacam-se ainda a repetição das mesmas instruções de programa em
diferentes pontos do programa e clareza na representação de lógica.
Todo programa em C é formado por uma ou mais funções. Uma
dessas funções é a função main(). As funções adicionais do programa
estarão subordinadas à função main() ou a alguma outra função. Se um
programa contém várias funções, suas definições podem aparecer em
qualquer ordem. Uma função será executada quando for chamada.
Após a execução, o controle retorna para o ponto no qual a função foi
chamada. O Programa 1.11 mostra a forma geral de uma função em C.

25
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 26

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

tipo nome_da_funcao ([<lista_de_parametros>])


{
// corpo da função
}

Programa 1.11: Forma geral da definição de uma função.

Onde:
tipo - define o tipo da informação que a função vai retornar,
podendo ser qualquer tipo válido. Se nenhum tipo for
especificado o compilador assume que a função devolve um
resultado inteiro (default), quando a função não retorna nenhum
resultado coloca-se void;
nome_da_função – identificador criado pelo programador;
lista_de_parâmetros – são as informações passadas para a
função, também conhecidas como argumentos. Uma função pode
não conter argumentos, neste caso, uma lista vazia entre parên-
teses. Todos os parâmetros da função devem conter o tipo e o
nome da variável.

As variáveis declaradas dentro de uma função não podem


interagir com o código ou os dados definidos em outra função, são
chamadas de variáveis locais daquela função.
O padrão ANSI expandiu a declaração de funções colocando-se a
utilização de protótipos. Sua finalidade é a de informar ao compilador
a existência de outras funções no programa além da função main().
Isto faz com que o compilador avalie os tipos especificados nos
parâmetros evitando incompatibilidade de tipo na chamada a função.
Uma vez apresentado como a linguagem C implementa as
definições de dados e de funções, será apresentado como é definido
um TAD em C. Em uma forma básica de implementação, considere a
estrutura ContaCliente apresentada no início do Programa 1.12. Ela é
composta pelas variáveis numero, nome e saldo. Logo em seguida é
criada a variável conta do tipo ContaCliente.
Após a criação da variável clienteEmpresa encontra-se a definição
dos protótipos das operações, seguido de suas implementações. Na
última parte do programa está a implementação da função main().

26
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 27

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

#include <stdio.h>

/* DEFINIÇÃO DA ESTRUTURA */
struct ContaCliente {
int numero;
char nome[50];
float saldo;
};

ContaCliente conta;

/* DEFINIÇÃO DO PROTÓTIPO DAS OPERAÇÕES */


void CadastrarConta(void);
void ExcluirConta(void);
void AlterarConta(void);

/* IMPLEMENTAÇÃO DAS OPERAÇÕES */


void CadastrarConta()
{
printf("Digite o numero da conta a ser incluída:");
scanf("%d",&conta.numero);
}

void ExcluirConta ()
{ ... }

void AlterarConta ()
{ ... }

/* CORPO DA FUNÇÃO PRINCIPAL DO PROGRAMA */


main()
{ ... }

Programa 1.12: Exemplo de TAD básico.

1.5 Independência de representação

Esta é a forma mais simples de implementar um TAD. Entretanto,


a chave para se conseguir verdadeiramente implementar TAD é aplicar
o conceito de independência de representação. A aplicação deste
conceito é possível em linguagens de programação que suportem
módulos.

27
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 28

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Um TAD pode ser implementado usando um módulo da seguinte


maneira:

1. O nome do módulo é o nome do TAD;


2. Apenas as operações da especificação abstrata são visíveis
externamente ao módulo, e
3. A representação concreta do TAD e outros componentes
auxiliares ficam ocultos dentro do módulo.

Com a linguagem C é possível implementar TAD usando o conceito


de módulos através de arquivos de programas separados em três
arquivos:
• Um arquivo de cabeçalho (header) “.h” para declaração das
estruturas, definições de tipo e dos protótipos das operações
(NomeTAD.h);
• Um arquivo fonte “.c” para implementação das funções
(NomeTAD.c);
• Um arquivo fonte “.c” para o programa principal (contendo a
função main()).

Exemplo

Problema:
Utilizando TADs e registros construa um algoritmo, que realize o
cadastro de contas bancárias. São dadas as seguintes informações:
a) Número da conta;
b) Nome do cliente;
c) Saldo da conta.
O banco permitirá o cadastramento de apenas 10 contas e não
pode haver mais de uma conta com o mesmo número. Crie o menu de
opções abaixo:

28
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 29

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Menu
1. Cadastro de contas;
2. Mostrar todas as contas de um determinado cliente;
3. Excluir a conta com menor saldo (supondo que não existam
saldos iguais);
4. Sair.

Resolução:

Passo1
• Crie um arquivo .h;
• Crie um registro e a definição de tipo;
• Crie o protótipo das operações.

Passo2
• Crie o arquivo .c;
• Crie um procedimento de cadastro de contas dos clientes
(número, nome e saldo);
• Crie um procedimento para mostrar as contas do cliente solici-
tado;
• Crie um procedimento para excluir a conta com o menor saldo.

Passo3
• Crie o arquivo main.c;
• Crie um menu de opções.

Acompanhe nos Programas de 1.13 a 1.15 a resolução do


exercício. O Programa 1.13 mostra o arquivo de cabeçalho,
o Programa 1.14 exibe o corpo das operações do TAD e finalmente, o
programa principal está mostrado no Programa 1.15.

29
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 30

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

#define max 100


typedef struct tipo_conta {
int numero;
char nome[50];
float saldo;
}TConta;

void CadastrarConta (TConta c[]);


int VisualizarConta (TConta c]);
void ExcluirConta (TConta c[]);
Programa 1.13: Arquivo tadconta.h.

30
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 31

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

#include <stdio.h>
#include <string.h>
#include <values.h>
#include "tadconta.h"

void CadastrarConta(TConta c[]) {


int num_conta;

printf("\nDigite o número da conta: ");


scanf("%d",&num_conta);
if (c[num_conta-1] != 0) //conta já existe
printf(“\nErro: Já existe conta com este número!”);
else {
printf("Informe nome do cliente: ");
scanf("%s", c[num_conta-1].nome);
printf("Informe saldo do cliente: ");
scanf("%f", &c[num_conta-1].saldo);
printf(“\nConta cadastrada com sucesso!”);
}
}

void VisualizarConta(TConta c[]){


int i;
char nome_cli[50];

printf("Digite o nome do Cliente a ser Consultado: ");


scanf(“%s”, nome_cli);
for(i = 0; i < 10; i++) {
if (! strcmp(c[i].nome, nome_cli) {
printf("\n\nNúmero da Conta: %d", c[i].numero);
printf("\nNome...........: %s", c[i].nome);
printf("\nSaldo..........: R$%.2f", c[i].saldo);
}
}
}

void ExcluirConta(TConta c[]){


int posicao = -1, i;
float menor_saldo = MAXFLOAT;

for(i = 0; i < 10; i++) {


if (c[i].numero != 0) { //conta já existe
if (c[i].saldo < menor_saldo) {
menor_saldo = conta[i].saldo;
posicao = i;
}
}
}
if (posicao == -1) {
printf("Nenhuma Conta foi Cadastrada");
else {
c[posicao].numero = 0;
c[posicao].saldo = 0;
strcpy(c[posicao].nome, “ ”);
printf("Conta excluída com sucesso", posicao+1);
}
}
Programa 1.14: Arquivo tadconta.c.

31
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 32

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

#include <stdio.h>
#include <string.h>
#include "tadconta.h"

main(void)
{
TConta contas[max];
int i, op;

for(i = 0; i < 10; i++) {


contas[i].numero = 0;
strcpy(contas[i].nome, “ ”);
contas[i].saldo = 0;
}

while(op != 4) {
printf("\n\nMenu de Opções:");
printf("\n1 - Cadastrar Contas");
printf("\n2 - Visualizar Contas Cliente");
printf("\n3 - Excluir Conta de menor saldo");
printf("\n4 - Sair");
printf("\n\nDigite a sua Opção:");
scanf(“%d”, &op);

switch (op){
case 1:
CadastrarConta(contas); break;
case 2:
VisualizarConta(contas); break;
case 3:
ExcluirConta(contas); break;
default:
printf("\nErro: Opção Inválida");
}
}
}

Programa 1.15: Arquivo contendo o programa com a função principal, main().

32
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 33

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

CAPÍTULO 2

Ponteiros e Alocação
Dinâmica de Memória
2.1 Introdução
Neste capítulo será estudado como declarar uma variável do tipo
ponteiro, bem como os diversos usos que se pode fazer desse tipo de
variável, como alocação dinâmica de memória e alocação de um vetor.

2.2 Declaração de variável tipo ponteiro

Ponteiros (ou apontadores) são variáveis que armazenam


endereço de memória e são associados a tipos de dados, ou seja, um
ponteiro endereça (ou aponta para) um dado de determinado tipo.
O Algoritmo 2.1 mostra exemplos de declarações de variáveis tipo
ponteiro e a atribuição de endereços de variáveis a esses ponteiros.

var
i : inteiro
r : real
c : caractere
pi : Ponteiro inteiro
pr : Ponteiro real
pc : Ponteiro caractere
inicio
pi <- ENDERECO i
pr <- ENDERECO r
pc <- ENDERECO c
fimalgoritmo
Algoritmo 2.1: Atribuição de endereços de variáveis a ponteiros.

33
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 34

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

A declaração de uma variável tipo ponteiro na linguagem C é feita


de acordo com a seguinte sintaxe:

tipo *nome_da_variável;

Onde:
• tipo é um tipo primitivo da linguagem (int, char, etc.) ou
um tipo definido pelo programador, como um registro,
por exemplo.
• nome_da_variável é um descritor (nome de variável),
definido pelo programador, obedecendo às regras de definição de
descritores. Exemplo: int *pi;

O Algoritmo 2.1 mostra as declarações de uma variável simples e


uma variável tipo ponteiro, ambas do tipo inteiro, em linhas
diferentes. Como se tratam de variáveis do mesmo tipo, podem ser
declaradas no mesmo comando de declaração de variável. Exemplo:
int i, *pi;
As declarações de variáveis abaixo são equivalentes :
int * pi;
int *pi;
int* pi;
int*i;

O operador ENDEREÇO – & – já é utilizado desde que se aprendeu


o comando de leitura (scanf(“%d”, &i)), onde esse operador faz
com que o valor lido seja armazenado no endereço da variável, ou
seja, a variável é passada por referência para a função scanf, onde
terá o seu conteúdo modificado.
Ao trabalhar com ponteiro, esse operador pode ser usado para
atribuir a um ponteiro o endereço de uma variável.
Por exemplo: para as variáveis declaradas no exemplo acima,
o comando pi = &i; faz com que o endereço da variável i seja
armazenado no ponteiro pi.

34
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 35

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

O Algoritmo 2.1 pode ser codificado, em linguagem C, conforme o


Programa 2.1.

#include <stdio.h>
int i, *pi;
float r, *pr;
char c, *pc;
main()
{ pi = &i;
pr = &r;
pc = &c;
}

Programa 2.1: Atribuição de endereços de variáveis a ponteiros

Outro operador utilizado com ponteiros é o operador de indireção


(ou desreferenciação) CONTEUDO. Esse operador, aplicado a um
ponteiro, acessa o conteúdo de um espaço de memória apontado por
esse ponteiro.
Um exemplo de uso do operador conteúdo, considerando as
variáveis declaradas no Algoritmo 2.1 está no Algoritmo 2.2.

inicio
...
escreva(“Digite um valor inteiro”)
leia(CONTEUDO pi)
escreva(i) //escreve o valor lido
fimalgoritmo

Algoritmo 2.2: Operador CONTEUDO.

O comando de leitura do Algoritmo 2.2 faz com que o valor lido


seja armazenado na posição de memória endereçada (apontada) pelo
ponteiro pi.
Vamos supor que a memória do computador possui o
endereçamento conforme o exemplo da Figura 2.1, onde estão
representas apenas as variáveis i e pi, do Programa 2.1. O comando
pi <- ENDERECO i, (Algoritmo 2.1), faria a variável pi assumir o
valor 10533 e o comando leia(CONTEUDO pi), (Algoritmo 2.2),
guardaria o valor lido no espaço de memória endereçado por pi.

35
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 36

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Figura 2.1: Representação esquemática de espaços de memória.

Acrescentando-se o Algoritmo 2.2 ao Programa 2.1, temos o


Programa 2.2, conforme abaixo:

#include <stdio.h>

int i, *pi;
float r, *pr;
char c, *pc;

main() {
pi = &i;
pr = &r;
pc = &c;
printf(“Digite um valor inteiro”);
scanf(“%d”,pi);
printf(“Valor lido: %d%”,*pi);
}

Programa 2.2: Operador CONTEUDO

O valor armazenado na variável i pode ser acessado e alterado


através do ponteiro pi. Supondo que o valor lido pelo Programa 2.2
(linha 12) tenha sido 27, o esquema da Figura 2.1 assumiria a seguinte
configuração mostrada na Figura 2.2.

36
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 37

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Figura 2.2: Valor lido pelo Programa 2.2.

A visualização do conteúdo do apontado pelo ponteiro pi


(Figura 2.2) pode ser obtida pelo comando printf(“Conteúdo do
ponteiro: %p”, *pi), que gera como saída o valor 27.
A impressão do conteúdo de um ponteiro pode ser feita usando-se
a string de tipo “%p”. Dependendo das características do sistema
operacional, esse valor poderá ser em base hexadecimal.

2.3 Alocação de memória

Para fazer alocação dinâmica de memória, deve-se fazer uso de 3


recursos:

1. Ponteiro para o tipo escolhido;


2. Função de alocação de memória (ALOCAR);
3. Função para retornar o tamanho de um tipo (TAMANHO_DE).

Considere o exemplo de algoritmo de alocação de memória a


seguir:

algoritmo “exemplo de alocação”


var
P: Ponteiro inteiro
inicio
P <- ALOCAR(TAMANHO_DE(inteiro))

...

Algoritmo 2.3: Alocação dinâmica de memória.


37
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 38

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

A codificação do Algoritmo 2.3, em linguagem C, pode ser da


seguinte forma:

#include <stdio.h>
#include <stdlib.h>

main()
{
int *p;

p = (int *) malloc(sizeof(int));
...
}

Programa 2.3: Alocação dinâmica de memória.

O trecho do Programa 2.3 faz com que um espaço de memória do


tamanho ocupado por uma variável tipo inteiro seja reservado e o
endereço desse espaço seja armazenado na variável tipo ponteiro p.
Cabe destacar que, quando se trabalha com alocação dinâmica
de memória, os locais (espaços de memória) onde se guardam os
valores não são referenciados por um nome de variável, e sim, apenas
por um ponteiro.
As funções de alocação de memória malloc(), calloc() e
realloc() e a função de liberação de memória free (vista mais
adiante), são funções constantes no arquivo de cabeçalho stdlib.h,
o qual necessita ser declarado em uma diretiva de pré-processamen-
to #include.

38
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 39

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

2.3.1 Alocação de vetor e registro

Para fazer alocação de um vetor dinamicamente, declare um pon-


teiro do tipo que se quer criar o vetor. No comando de alocação de
memória multiplique a quantidade de posições do vetor pelo tamanho
do tipo.
Exemplo: para alocar um vetor de inteiros com 50 posições,
primeiro é feita a declaração do ponteiro tipo inteiro. Na alocação do
ponteiro, multiplica-se o tamanho de inteiro por 50. Observe, no
Algoritmo 2.4, o comando de alocação de um vetor, cujo tamanho
dependerá do valor informado em tempo de execução.

algoritmo “Alocação de Vetor”


var
p: Ponteiro inteiro
tam, i: inteiro
inicio
leia(tam)
p <- ALOCAR(TAMANHO_DE(inteiro) * tam)
para i de 1 ate tam faca
leia (p[i])
fimpara
fimalgoritmo
...

Algoritmo 2.4: Alocação de um vetor de inteiros.

No exemplo acima, se for informado o valor 100 para a variável


tam, o vetor ocupará TAMANHO_DE(inteiro) * tam. Caso um
inteiro ocupe 2 bytes, o vetor ocupará 2 x 100 = 200 bytes.
Um ponteiro para um espaço desse tipo guarda o endereço da primeira
posição e as demais são alocadas contiguamente.

39
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 40

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

1. /* Programa para alocação de vetor */


2. #include <stdio.h>
3. main(){
4. int *p, tam, i;
5. printf(“Informe o tamanho do vetor: “);
6. scanf("%d", &tam);
7. p = (int *)malloc(sizeof(int) * tam);
8. if(p == NULL)
9. printf("Vetor não alocado");
10. else
11. {
12. printf("informe os valores do vetor:\n");
13. for (i = 0 ;i < tam; i++)
14. scanf("%i", &p[i]);
15. }
16.}

Programa 2.4: Alocação dinâmica de um vetor.

No Programa 2.4 é feito um teste na linha 8: if p == NULL.


Esse teste é necessário para detectar algum possível problema
durante a alocação do vetor, como falta de memória para o vetor
requerido, por exemplo.
Ressalta-se que a linguagem de algoritmos é genérica.
Um algoritmo pode ser codificado em diversas linguagens de
programação. No momento da implementação deve-se observar as
particularidades de cada uma. A linguagem C realiza a indexação a
partir do valor zero. Por isso, o índice do vetor, que no algoritmo
começa em 1 (para i de 1 ate tam faca), no Programa 2.4
foi implementado com a variável i iniciando com valor zero
(for(i = 0; i < tam; i++). Portanto, o índice vetor começa
com valor zero e termina em n – 1 (condição de parada do laço é
i >= tam).

40
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 41

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Outro detalhe é que depois da alocação do ponteiro p, o vetor


passa a ser usado como se tivesse sido declarada uma variável vetor
de inteiro. Por isso, na linha 14 do Programa 2.4, não foi usado o
operador de indireção CONTEUDO. Em outras palavras, a forma como
o vetor p foi criado no Programa 2.4 é equivalente à declaração de
variável int p[tam];. Conclui-se que a declaração de uma variável
tipo vetor é a declaração de um ponteiro para a primeira posição do
vetor.
Para fazer a alocação dinâmica de um registro, primeiro
declara-se o registro desejado. Essa declaração cria um novo tipo de
variável. Depois, declara-se uma variável ponteiro do tipo (registro)
criado. A seguir, é possível alocar um espaço de memória do tamanho
do registro, que será endereçado (apontado) pela variável ponteiro, a
qual foi declarada do tipo desse registro.
O Algoritmo 2.5 exemplifica a alocação de um registro.

algoritmo “Alocação de Registro”


var
TFuncionario = registro
nome : caractere
salario: real
idade : inteiro
fimregistro

PF: Ponteiro TFuncionario

inicio
...
PF <- ALOCAR(TAMANHO_DE(TFuncionario))
leia(PF->nome, PF->salario, PF->idade)
...

Algoritmo 2.5: Alocação de um registro.

Usando essa forma, a codificação do Algoritmo 2.5, em linguagem


C, pode ser feita como no Programa 2.5.
O acesso aos campos de um registro criado por alocação dinâmica
é feito usando uma seta na direção do campo, e não mais o ponto.
41
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 42

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Exemplo: PF->nome, acessa o campo nome do registro


apontado por PF.

#include <stdio.h>
#include <stdlib.h>

struct TFuncionario
{ char nome[40];
float salario;
int idade;
};

main()
{
struct TFuncionario *PF;

PF = (struct TFuncionario *)malloc(sizeof(struct TFuncionario));


printf("\nDigite os dados do funcionário ");
printf("\nNome: ");
scanf("%s", PF->nome);
printf("Salario: ");
scanf("%f",&PF->salario);
printf("Idade: ");
scanf("%d",&PF->idade);

printf("\nConfira os dados digitados: ");


printf("\n\nNome: %s", PF->nome);
printf("\nSalario = %7.2f” ,PF->salário);
printf("\nIdade = %d", PF->idade);
return 0;
}

Programa 2.5: Alocação de um registro.

Como visto no Capítulo 1, codificando em linguagem C, pode-se


utilizar a criação de tipos de estrutura, com o uso de typedef.
Tem-se, portanto, uma declaração conforme mostrado no Programa 2.6.

42
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 43

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

typedef struct Funcionario


{ char nome[40];
float salario;
int idade;
}TFuncionario;

TFuncionario *PF;

Programa 2.6: Declaração de tipo de variável registro.

O uso de variável tipo registro resolve a situação de permitir


manter, em uma mesma estrutura, informações de tipos diferentes.
Entretanto, a manipulação de muitas informações continua sendo uma
limitação para o programador. Uma forma de superar esse aspecto é
criar um vetor de registros.
O Algoritmo 2.6 é um exemplo de alocação de vetor de registro.

algoritmo “Alocação de Vetor de Registros”


var
TFuncionario = registro
nome: caractere
salario: real
idade: inteiro
fimregistro

vet: Ponteiro TFuncionario


tam, i: inteiro

inicio
...
leia (tam)
vet <- ALOCAR(TAMANHO_DE(TFuncionario) * tam)
para i de 1 ate tam faca
leia(vet[i].nome, PF[i].salario, PF[i].idade)
fimpara
...

Algoritmo 2.6: Alocação de vetor de registro.

43
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 44

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

A codificação do Algoritmo 2.6 é realizada pelo Programa 2.7, a


seguir. É importante notar que os campos de cada posição do vetor são
referenciados pelo nome da variável “ponto” nome do campo, mesmo
que o vetor tenha sido alocado dinamicamente. Isto acontece pois o
índice do vetor já identifica o registro. A partir daí, é necessário ape-
nas identificar o campo.

/* Programa para alocação de vetor de registro */


#include <stdio.h>
#include <stdlib.h>

typedef struct
{
char nome[40];
float salario;
int idade;
} TFuncionario;

main()
{
TFuncionario *vet;
int tam, i;

printf("Informe o tamanho do vetor");


scanf("%d", &tam);
vet = (TFuncionario *)malloc(sizeof(TFuncionario) * tam);
for (i = 0; i < tam; i++)
{
__fpurge(stdin); //Limpa o buffer do teclado
printf("\nDigite o nome: ");
scanf("%s", vet[i].nome);
printf("\nDigite o salario: ");
scanf("%f",&vet[i].salario);
printf("\nDigite a idade: ");
scanf("%d",&vet[i].idade);
}
return 0;
}

Programa 2.7: Alocação de um vetor de registros.

44
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 45

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

CAPÍTULO 3

Listas

3.1 Introdução

Listas são estruturas de dados constituídas por um conjunto de


informações e um conjunto de operações sobre os dados. Podem ser
construídas através de estruturas estáticas, como o vetor, ou de
alocação dinâmica de memória.
Vamos supor uma situação em que se deseja gerenciar as
informações dos produtos de uma empresa. Dispõem-se do código de
cada produto, da especificação (nome do produto), do preço unitário
de venda e da quantidade em estoque. A lista deverá permitir as
seguintes operações:
• Inserir um novo nó na lista;
• Listar os produtos constantes da lista;
• Verificar se um produto consta da lista, dado o código;
• Retirar um produto da lista, dado o código;
• Atualizar os dados de um produto, dado o código;
• Informar a quantidade de produtos constante da lista.

3.2 Implementação de lista estática

Será usado um vetor para fazer a implementação estática da lista


proposta.
O primeiro passo é criar a estrutura da lista. Como se trata de
mais de uma informação a respeito de cada produto e de tipos
diferentes, deve-se utilizar um vetor de registros, onde cada registro
conterá todas as informações de um produto.

45
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 46

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

O Algoritmo 3.1 cria a estrutura da lista.

Max = 100 : constante inteiro


var TipoItem = registro
cod : inteiro
especif : caractere
preco : real
quant : inteiro
fimregistro

TipoLista = registro
item : vetor[1..max] de TipoItem
tamanho : inteiro
fimregistro

Algoritmo 3.1: Estrutura da lista

O registro TipoItem contém os campos com informações do pro-


duto. O registro TipoLista contém dois campos, o campo tamanho,
que conterá o número de itens da lista, e o campo item um vetor de
tamanho determinado pela variável max, onde cada posição tem três
campos. Se tamanho tiver valor zero indica que a lista está vazia.
Declarar uma variável lista, por exemplo, do tipo TipoLista,
significa que essa variável será composta de um vetor item e uma
variável inteira tamanho. Esquematicamente essa variável está
representada na Figura 3.1.

Figura 3.1: Esquema da variável lista.

46
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 47

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

A implementação da definição da estrutura da lista pode ser feita


como consta do Programa 3.1.

#define max 100 //def. da constante com o valor maximo de itens

typedef struct tipo_item { // definicao da estrutura


int cod;
char especif[30];
float preco;
int quant;
}TItem;

typedef struct tipo_lista { //definição da estrutura do vetor


TItem item[max];
int tamanho;
}TLista;

void cria_lista_vazia(TLista *lista); //passagem por referencia


int vazia(TLista lista); //passagem por valor
void inserir(TLista *lista);
void listar(TLista lista);

Programa 3.1: Estrutura da lista, no arquivo de cabeçalho “itens.h”.

A variável lista pode ser declarada no módulo principal do


programa. A criação da lista vazia pode ser feita através de um
procedimento, no qual é atribuído o valor zero para o campo da
variável lista chamado tamanho. O Algoritmo 3.2 mostra uma forma
de fazer isto.

procedimento cria_lista_vazia(var lista : TipoLista)


inicio
lista->tamanho <- 0
fimprocedimento

Algoritmo 3.2: Criação da lista vazia.

47
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 48

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

O Programa 3.2 corresponde ao Algoritmo 3.2. Como a atualização


do campo tamanho deve retornar ao módulo que chama esse
procedimento, a passagem do parâmetro se dá por referência.

void cria_lista_vazia(TLista *lista){


lista->tamanho = 0;
}

Programa 3.2: Criação da lista vazia.

Em vários pontos do programa será necessário verificar se a lista


está vazia. Um exemplo de uma situação em que se fará essa verifi-
cação é antes de tentar imprimir a lista. Antes de iniciar a busca de
um item para eliminar é outro caso onde se deve verificar se a lista
está vazia. Em situações como essas, recomenda-se evitar reescrever
o mesmo trecho de código. Uma função para fazer tal verificação está
sendo apresentada no Algoritmo 3.3.

funcao vazia(lista : TipoLista): logico


inicio
se lista.tamanho = 0 entao
retorne VERDADEIRO
senao
retorne FALSO
fimse
fimfuncao

Algoritmo 3.3: Verifica se a lista está vazia.

A idéia usada no Algoritmo 3.3 é que na linguagem C o zero tem


valor lógico FALSO e qualquer valor diferente de zero resulta em
VERDADEIRO.
A implementação desse algoritmo pode ser vista no Programa 3.3.
Uma maneira de chamar esse procedimento é em forma de teste
lógico

48
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 49

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int vazia(TLista lista)


{
if (lista.tamanho == 0)
return 1;
else
return 0;
}

Programa 3.3: Lista vazia.

Uma observação importante: no Algoritmo 3.2 para referenciar o


campo tamanho, da variável lista, foi utilizado o operador de
indireção ->, enquanto no Algoritmo 3.3 foi utilizado o ponto.
A diferença se deve ao fato da variável lista ter sido passada por
referência no primeiro procedimento e por valor no segundo.
Um procedimento para acrescentar informações na lista está
sendo apresentado no Programa 3.4. Entretanto, as informações estão
sendo armazenadas na ordem em que são digitadas. Fica a título de
exercício modificar o procedimento inserir para realizar a
construção da lista ordenada por ordem crescente de código, uma vez
que um critério de ordenação é uma das características da lista. Uma
forma de realizar essa tarefa é receber o código e buscar em que
posição será inserido. Caso não seja inserido no final da lista, deve-se
abrir um espaço, avançando uma posição no vetor todos os nós que
ficarão após o novo nó.

void inserir(TLista *l)


{
printf("\nDigite o codigo do produto: ");
scanf("%d", &l->item[l->tamanho].cod);
printf("Especificacao: ");
scanf("%s", l->item[l->tamanho].especif);
printf("Digite o preco: ");
scanf("%f", &l->item[l->tamanho].preco);
printf("Digite a quantidade: ");
scanf("%d", &l->item[l->tamanho].quant);
l->tamanho ++;
}

Programa 3.4: Inserção de nós na lista.


49
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 50

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Exemplo:
Existem no vetor os códigos 344, 356, 363, 365 e deseja-se inserir
o código 347, que passará a ocupar a posição dois no vetor.
Faz-se necessário, portanto, deslocar os valores das posições 2, 3
e 4 para as posições 3, 4 e 5, respectivamente.
Para que não ocorra perda de nenhum valor, o vetor deve ser per-
corrido do final até a posição que deve resultar vazia.
No caso desse exemplo, deve-se copiar primeiro o valor da posição
4 para a posição cinco, depois da posição 3 para 4 e, por fim, da
posição 2 para 3.
Para realizar essa cópia, não é necessário copiar campo a campo
do registro de cada posição do vetor. É suficiente fazer a atribuição de
um registro a outro: lista.item[x] <- lista.item[y] e todos os
campos do registro item serão copiados da posição x para a posição y
do vetor.
A Figura 3.2 traz um exemplo de informações digitadas para duas
posições do vetor. O campo lista.tamanho tem valor dois,
significando que dois registros foram implantados.

Figura 3.2: Exemplo de valores constantes da lista.

50
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 51

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Outra funcionalidade da estrutura lista é realizar a impressão


(listagem) das informações constantes da mesma. Um procedimento
com essa finalidade está sendo mostrado no Programa 3.5.

void listar(TLista l)
{
int i;

if (vazia(l))
printf("Nao ha produto cadastrado");
else {
printf("\n\nProdutos cadastrados:");
for (i = 0; i < l.tamanho; i++){
printf("\nCodigo: %5d",l.item[i].cod);
printf(" Especificacao: %s",l.item[i].especif);
printf(" Preco: %6.2f ", l.item[i].preco);
printf("Qtd: %3i, l.item[i].quant);
}
}
}

Programa 3.5: Lista itens cdastrados

O módulo principal do programa deve declarar a variável lista e


conter um menu de opções que disponibilize ao usuário todas as fun-
cionalidades da lista, conforme especificado no início deste capítulo.
Uma versão do módulo principal que realiza a lista estática, com
as opções de inserir e imprimir dados, é apresentada a seguir, no
Programa 3.6.

51
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 52

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

#include <stdio.h>
#include "lista.h"

main(void) {
char op = ' ';
TLista lista;

cria_lista_vazia(&lista);
while (op != '3') {
printf("\n\n\t\tCadastro de produtos");
printf("\n\n\t\t1 - Inserir dados
printf("\n\t\t2 - Listar");
printf("\n\t\t3 - Encerrar programa");
printf("\n\n\t\tOpcao escolhida: ");
__fpurge(stdin);
scanf("%c", &op);
switch(op) {
case '1':
inserir(&lista); //argumento passado por ref.
break;
case '2':
listar(lista); //argumento passado por valor
break;
}
}
return 0;
}

Programa 3.6: Módulo principal.

52
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 53

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

3.3 Implementação de lista simplesmente encadeada

A implementação estática, por um lado, impõe a limitação do


tamanho do vetor e por outro lado, aloca memória que poderá não ser
usada durante a execução do programa.
A alocação dinâmica evita essas duas situações, já que aloca
memória somente quando for necessário e libera espaço de memória
alocado quando não necessitar de uma informação na estrutura (quan-
do remover uma informação).
Será usada como exemplo de implementação de uma lista simples-
mente encadeada a estrutura da lista estática. Faz-se necessário
acrescentar um ponteiro ao registro TipoItem. Esse ponteiro será o elo
de ligação de um registro com outro. A estrutura da lista está repre-
sentada no Algoritmo 3.4.

var TipoItem = registro


cod : inteiro
especif : caractere
preco : real
quant : inteiro
proximo : Ponteiro TipoItem
fimregistro

TipoLista = registro
inicio : Ponteiro TipoItem
fimregistro

Algoritmo 3.4: Estrutura para lista encadeada.

Nota-se que o ponteiro proximo é do tipo do registro onde ele está


sendo declarado. Significa que endereçará uma estrutura TipoItem.
Haverá um ponteiro que guardará o primeiro nó (registro) da lista.
A partir do segundo nó o encadeamento será feito pelo nó anterior. Por
esse motivo, não é possível acessar diretamente um determinado nó,
exceto o primeiro.
De forma esquemática, a lista terá a representação mostrada na
Figura 4.

53
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 54

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Figura 3.3: Esquema da lista encadeada.

O Programa 3.7 implementa a estrutura da lista. O ponteiro Início,


para o início da lista, do tipo TipoLista, será declarado no módulo prin-
cipal. Caso Início tenha valor nulo, significa que a lista está vazia.
Cada nó (ou célula) terá quatro campos de informação e um campo
ponteiro para o próximo nó, sendo que o último ponteiro terá valor
nulo, indicando que não há nó posterior.

typedef int TipoChave;

typedef struct {
TipoChave cod;
char especif[30];
float preco;
int quant;
} TipoDado;

struct Celula {
TipoDado Dado;
struct Celula *Proximo;
}TipoCelula;

typedef struct {
TipoCelula *Inicio;
} TipoLista;

void CriaLista (TipoLista *lista);


int ListaVazia (TipoLista *lista);
int InsereOrdenadoLista (TipoLista *lista, TipoDado dado);
int RetiraLista (TipoLista *lista, TipoChave cod, TipoDado *dado);
void ListarItens(TipoLista *lista);
int ConsultaItem (TipoLista *lista, TipoChave cod, TipoDado *dado);
void ApagarLista (TipoLista *lista);

Programa 3.7: Estrutura da lista encadeada.

54
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 55

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Para cada nó que se deseja acrescentar à lista, será alocada na


memória uma estrutura do tipo TipoCelula, definida no Programa
3.7. A cada eliminação de um nó da lista, o espaço de memória
correspondente será liberado.
Cabe observar que o ponteiro Proximo poderia ter sido
declarado na estrutura TipoDado. Entretanto, como exemplo da
flexibilidade que a linguagem possui, foi criada a estrutura Celula,
com os mesmos campos da estrutura TipoDado mais o ponteiro
Proximo.
Ao final da execução do programa, devem ser desalocados da
memória todos os nós. Caso essa providência não seja tomada, mesmo
após o encerramento do programa a memória permanecerá ocupada.
A liberação do espaço de memória é feita pelo comando
free(argumento), onde argumento é um ponteiro. No exemplo
abaixo, Programa 3.8, consta uma rotina com essa finalidade.

void ApagarLista(TLista *lista)


{
TipoCelula *noatual, *aux;
noatual = lista->Inicio;

while (noatual != NULL){ // laço para desalocar todos os nós


aux = noatual->Proximo;
free(noatual); // liberando a memória.
noatual = aux;
}
lista->Inicio = NULL;
}

Programa 3.8: Procedimento para apagar toda a lista.

A inserção de nós na lista será feita pelo procedimento constante


do Programa 3.9, InsereOrdenadoLista. Como é necessário que as
alterações feitas na lista permaneçam após o encerramento do
módulo de inserção, a passagem do parâmetro com o endereço do iní-
cio da lista deve ocorrer por referência.

55
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 56

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

int InsereOrdenadoLista(TipoLista *lista, TipoDado dado) {


TipoCelula *aux1, *aux2, *novo;

novo = (TipoCelula *) malloc(sizeof(TipoCelula));


if (novo == NULL) {
printf("\n\nErro de alocacao de memoria!");
return 0;
}
else {
novo->Dado = dado;
// busca do local de insercao
if (ListaVazia(*lista)) { //eh o primeiro item?
lista->Inicio = novo;
novo->Proximo = NULL;
}
else {
if (lista->Inicio->Dado.cod > novo->Dado.cod) {
novo->Proximo = lista->Inicio;
lista->Inicio = novo;
}
else { // insere no meio ou no fim da lista
aux1 = lista->Inicio;
aux2 = lista->Inicio->Proximo;
while((aux2 != NULL) && (aux2->Dado.cod < novo->Dado.cod)) {
aux1 = aux2;
aux2 = aux2->Proximo;
} //ao fim do while, insere entre aux1 e aux2
aux1->Proximo = novo;
novo->Proximo = aux2;
}
}
}
return 1;
}

Programa 3.9: Inserir dados na lista.

56
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 57

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

O ponteiro lista recebe o início da lista. A inserção de um nó


está ocorrendo de forma ordenada.
A Figura 3.4.a mostra uma lista com três registros e a Figura 3.4.b
ilustra a inserção do quarto registro entre dois nós. Observa-se que é
necessário atualizar o ponteiro do nó anterior para encadear com o
novo nó e o ponteiro deste último encadeará com o próximo.
Caso a inserção seja no início da lista, o ponteiro lista terá que ser
atualizado para endereçar (apontar) o novo nó e caso seja no final, o
ponteiro do novo nó receberá valor nulo.

Figura 3.4: Inserção ordenada de nós.

Para fazer a impressão das informações constantes da lista


deve-se cuidar para que o nó que guarda a referência (endereço) do
primeiro nó da lista não seja alterado. A chamada ao módulo de
impressão (listar) é feita passando a lista por valor, pois, dessa
forma, uma eventual alteração dos dados será considerada apenas a
nível local ao procedimento.
A fim de evitar qualquer alteração do ponteiro que contém o
início da lista, mesmo sendo passado ao módulo chamado por valor,
lança-se mão de um ponteiro auxiliar para percorrer os nós da
estrutura. No exemplo foi usado o ponteiro noatual, que permite o
acesso às informações constantes de cada nó da lista.

57
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 58

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

void ListarItens(TipoLista lista) {


TipoCelula *aux;

if (ListaVazia(lista))
printf("Erro: Nao ha produtos cadastrados!");
else {
aux = lista.Inicio;
printf("\n\nProdutos cadastrados:");
do {
printf("\nCodigo: %5d", aux->Dado.cod);
printf("\nEspecificacao: %s", aux->Dado.especif);
printf("\nPreco: %6.2f ", aux->Dado.preco);
printf("\nQuantidade: %3i", aux->Dado.quant);
noatual = aux->Proximo;
} while (aux != NULL);
}
}

Programa 3.10: Imprime os nós da lista.

58
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 59

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

CAPÍTULO 4

Pilhas

4.1 Introdução
Para a implementação do Tipo Abstrato de Dados Pilha, é preciso,
inicialmente, definir os tipos necessários para a sua criação. Seguindo
a disciplina de acesso “o último que entra é o primeiro a sair” ou do
inglês LIFO (Last In, First Out), será mostrado o conteúdo dos
arquivos deste TAD:
• Arquivo de cabeçalho (pilha.h). Contém as definições de tipo
(typedef) e a interface das funções;
• Arquivo fonte (pilha.c). Armazena a implementação das
operações definidas sobre o TAD Pilha.

As operações detalhadas neste capítulo são:


• Função Empilha;
• Função Desempilha;
• Função Consulta_Topo;
• Função Pilha_Vazia.

Nas próximas seções serão mostradas as implementações


utilizando as abordagens estática (com o uso de vetores) e dinâmica
(utilizando apontadores e alocação dinâmica de memória).

4.2 Pilhas implementadas por vetores

O TAD Pilha será mostrado nesta seção com a utilização de vetores


para o armazenamento dos dados a serem empilhados e
desempilhados. O código será mostrado em partes. O trecho de códi-
go mostrado no programa 4.1 mostra as definições de tipo. Note que
o TipoChave é definido como uma estrutura, de forma a facilitar a
59
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 60

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

personalização desta informação para cada aplicação. A mesma idéia


é vista na estrutura TipoDado. A Pilha propriamente dita é formada
pelo índice Topo e o vetor de dados, com tamanho definido com a
constante simbólica Max, descrita pela estrutura TipoPilha.

#ifndef PILHA_H_
#define PILHA_H_

#define Max 3
typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct {
int Topo;
TipoDado Dados[Max];
} TipoPilha;

void Cria_Pilha(TipoPilha *pilha);


int Pilha_Vazia(TipoPilha pilha);
int Empilha(TipoPilha *pilha, TipoDado dado);
int Desempilha(TipoPilha *pilha, TipoDado *dado);
int Consulta_Topo(TipoPilha pilha, TipoDado *dado);

#endif /*PILHA_H_*/

Programa 4.1: Definições de tipo e interface das operações do TAD Pilha.

O procedimento Cria_Pilha (Programa 4.2) é necessário a fim de


inicializar a variável Topo logo após a criação da variável Pilha. Na
Linguagem C, o primeiro elemento dos vetores é o 0 (zero), portanto,
o Topo inicia com uma unidade a menos, -1, indicando que a pilha
está vazia. A variável pilha é recebida por referência, possibilitando a
atualização permanente dos seus dados.

60
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 61

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

void Cria_Pilha(TipoPilha *pilha)


{
pilha->Topo = -1;
}

Programa 4.2: Procedimento Cria_Pilha.

O processo de empilhar um dado foi implementado como uma


função a fim de permitir o retorno de um código de sucesso
(VERDADEIRO) ou insucesso (FALSO). A função Empilha (PUSH), é
mostrada no Programa 4.3. A variável pilha é passada por referência
à função e o dado é copiado do parâmetro dado para a próxima
posição livre na pilha (Topo).
Primeiramente a função testa se a pilha está cheia. Em caso afir-
mativo, é mostrada uma mensagem de erro e é retornado um código
de erro, FALSO (0). Caso haja espaço no vetor, a variável Topo é incre-
mentada, representando a próxima posição livre no vetor, e o novo
dado é inserido no topo da pilha. Neste caso o sucesso é sinalizado
pelo valor de retorno VERDADEIRO (1).

int Empilha(TipoPilha *pilha, TipoDado dado)


{
if (pilha->Topo == (Max - 1)) //pilha cheia
{
printf("\n\nErro: Pilha Cheia!");
return 0;
}
else
{
pilha->Topo++;
pilha->Dados[pilha->Topo] = dado;
return 1;
}
}

Programa 4.3: Função Empilha

61
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 62

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

A fim de desempilhar (POP) os elementos da pilha, a função


Desempilha, mostrada no Programa 4.4, recebe por referência a
variável pilha e uma variável de apoio dado, que retornará, como
parâmetro o dado desempilhado. O valor de retorno trata do sucesso
ou insucesso da operação.
De início, a função testa se a pilha está vazia. Neste caso, sendo
impossível desempilhar um dado inexistente, uma mensagem de erro
é mostrada e o valor FALSO (0) é retornado.
Se houver ao menos um dado da pilha, o dado a ser removido é
copiado para o parâmetro dado1 e a variável Topo é decrementada,
indicando que o novo elemento Topo é o item anterior. Nesta situação
o valor de retorno é o VERDADEIRO (1).

int Desempilha(TipoPilha *pilha, TipoDado *dado)


{
if (Pilha_Vazia(*pilha)) //pilha vazia
{
printf("\n\nErro: Pilha Vazia!");
return 0;
}
else
{
*dado = pilha->Dados[pilha->Topo];
pilha->Topo--;
return 1;
}
}

Programa 4.4: Função Desempilha.

A função lógica Consulta_Topo (Programa 4.5) pode ser utilizada


por aplicações que precisam conhecer o elemento do topo da pilha,
sem contudo, removê-lo. Sendo uma função lógica, retorna VER-
DADEIRO (1) quando a consulta pode ser efetivada e FALSO (0) caso
contrário. O elemento consultado é retornado por parâmetro na
variável dado, passada por referência. Note que a pilha, por não ser
modificada pela função, não foi passada por referência, e sim, por
valor.
1Lembre-se de que a idéia de se retornar o item removido é poder utilizá-lo pela função que solicitou a remoção.

62
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 63

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Consulta_Topo(TipoPilha pilha, TipoDado *dado)


{
if (Pilha_Vazia(pilha)) //pilha vazia
{
printf("\n\nErro: Pilha Vazia!");
return 0;
}
else
{
*dado = pilha.Dados[pilha.Topo];
return 1;
}
}

Programa 4.5: Função Consulta_Topo.

A função Pilha_Vazia, mostrada no Programa 4.6, auxilia a


implementação das demais funções. Ela testa se a pilha está vazia,
retornando o valor lógico VERDADEIRO (1) ou FALSO (0) conforme o
caso. Lembre-se de que o valor do Topo para a pilha vazia corresponde
ao -1. Esta função lógica é utilizada nas funções Consulta_Topo e
Desempilha.

int Pilha_Vazia(TipoPilha pilha)


{
if (pilha.Topo == -1)
return 1;
else
return 0;
}

Programa 4.6: Função Pilha_Vazia

No Anexo A é apresentada a implementação completa do


TAD Pilha utilizando vetores e um programa principal (aplicação)
exemplo.

63
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 64

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

4.3 Pilhas implementadas por variáveis dinâmicas

Para implementar esta versão do TAD pilha, são necessários as


definições de tipo e interfaces das operações presentes no arquivo de
cabeçalho do TAD. Este arquivo é mostrado no Programa 4.7.

#ifndef PILHAD_H_
#define PILHAD_H_

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct Celula {


TipoDado Dado;
struct Celula *Anterior;
}TipoCelula;

typedef struct {
TipoCelula *Topo;
} TipoPilha;

void Cria_Pilha(TipoPilha *pilha);


int Pilha_Vazia(TipoPilha pilha);
int Empilha(TipoPilha *pilha, TipoDado dado);
int Desempilha(TipoPilha *pilha, TipoDado *dado);
int Consulta_Topo(TipoPilha pilha, TipoDado *dado);

#endif /*PILHAD_H_*/

Programa 4.7: Definições de tipo e interface das operações do TAD Pilha.

64
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 65

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

O procedimento Cria_Pilha, no Programa 4.8, inicializa o ponteiro


Topo com o valor NULL. Significa que este apontador não está
apontando para nenhuma área de memória. A variável pilha é passada
por referência ao procedimento.

void Cria_Pilha(TipoPilha *pilha)


{
pilha->Topo = NULL;
}

Programa 4.8: Procedimento Cria_Pilha.

A função Empilha (PUSH) recebe a variável pilha por referência


e copia o dado para uma nova célula, recém alocada. Esta alocação é
testada para o caso de acontecer um erro, ocasionando o envio de
uma mensagem na tela e o retorno de um código FALSO (0),
indicando o insucesso. Caso a alocação seja bem-sucedida, a nova
célula é empilhada (aponta para a célula Topo) e o Topo recebe o
endereço da nova célula. Note que ao empilhar a primeira célula,
Novo irá apontar para NULL, valor inicial de Topo. Após o
empilhamento, a função, mostrada no Programa 4.9, retorna
VERDADEIRO (1).

65
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 66

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

int Empilha(TipoPilha *pilha, TipoDado dado)


{
TipoCelula *novo;

if((novo = (TipoCelula *) malloc(sizeof(TipoCelula))) == NULL)


{
printf("\n\nErro de alocacao de memoria!");
return 0;
}
else
{
novo->Dado = dado;
novo->Anterior = pilha->Topo;
pilha->Topo = novo;
return 1;
}
}

Programa 4.9: Função Empilha com alocação dinâmica.

A função Desempilha (POP) é vista no Programa 4.10. De início, é


verificado se a pilha está vazia. Caso afirmativo, uma mensagem de
erro é mostrada na tela e a função retorna FALSO. Isto acontece por
não ser possível desempilhar um item de uma pilha vazia. Caso a pilha
não esteja vazia, o dado a ser desempilhado (armazenado na célula
topo) é salvo no parâmetro dado. Em seguida, o endereço da célula
topo é salvo em um ponteiro auxiliar (aux), que é desalocado após o
Topo apontar para a célula anterior (de “baixo”). O Programa 4.10
mostra a função Desempilha. Perceba que ao remover a última
célula, o Topo passará a ser automaticamente igual a NULL.

66
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 67

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Desempilha(TipoPilha *pilha, TipoDado *dado)


{
TipoCelula *aux;

if (Pilha_Vazia(*pilha)) //pilha vazia


{
printf("\n\nErro: Pilha Vazia!");
return 0;
}
else
{
*dado = pilha->Topo->Dado;
aux = pilha->Topo;
pilha->Topo = pilha->Topo->Anterior;
free(aux);
return 1;
}
}

Programa 4.10: Função Desempilha com alocação dinâmica.

Para consultar a célula Topo a função vista no Programa 4.11


retorna por referência o dado daquela célula, mas apenas se houver
algum elemento na pilha. A função retorna VERDADEIRO ou FALSO,
indicando sucesso ou falha de consulta, respectivamente.

int Consulta_Topo(TipoPilha pilha, TipoDado *dado)


{
if (Pilha_Vazia(pilha)) //pilha vazia
{
printf("\n\nErro: Pilha Vazia!");
return 0;
}
else
{
*dado = pilha.Topo->Dado;
return 1;
}
}

Programa 4.11: Função Consulta_Topo com alocação dinâmica.

67
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 68

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

A função Pilha_Vazia testa e retorna VERDADEIRO caso o


apontador Topo seja igual a NULL. Esta função é utilizada como apoio
aos demais procedimentos de manipulação de pilha. Esta função pode
ser vista no Programa 4.12.

int Pilha_Vazia(TipoPilha pilha)


{
if (pilha.Topo == NULL)
return 1;
else
return 0;
}

Programa 4.12: Função Pilha_Vazia com alocação dinâmica.

68
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 69

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

CAPÍTULO 5

Filas

5.1 Introdução

Nas Filas (em inglês queue), a disciplina de acesso é o primeiro


elemento que entra é o primeiro que sai. Trata-se da organização FIFO
(First In, Fist Out). A implementação deste Tipo Abstrato de Dados
inclui os arquivos:
• Arquivo de cabeçalho “fila.h”, contendo as definições de tipo e
as interfaces das operações do tipo abstrato de dados;
• Arquivo fonte “fila.c” com a implementação das operações de
acesso à fila.

As próximas seções detalham a implementação de filas utilizando


vetores e ponteiros com alocação dinâmica.
As operações do TAD Fila implementadas neste capítulo são:
• Função Enfileira;
• Função Desenfileira;
• Função Consulta_Frente;
• Função Fila_Vazia;
• Função Quantidade_Fila.

5.2 Filas implementadas por vetores

Para a implementação do TAD Fila utilizando vetores, são


necessárias as definições de tipo (typedef) , estruturas (structs) e as
interfaces das operações do TAD. O Programa 5.1 mostra estas
declarações de tipo inseridas no arquivo de cabeçalho (.h).

69
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 70

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

#ifndef FILA_H_
#define FILA_H_

#define Max 100

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct {
int Frente, Tras;
TipoDado Dados[Max];
} TipoFila;

void Cria_Fila(TipoFila *fila);


int Fila_Vazia(TipoFila fila);
int Enfileira(TipoFila *fila, TipoDado dado);
int Desenfileira(TipoFila *fila, TipoDado *dado);
int Consulta_Frente(TipoFila fila, TipoDado *dado);

#endif /*FILA_H_*/

Programa 5.1: Definições de tipo e interface das operações do TAD Fila.

O procedimento Cria_Fila, mostrado no Programa 5.2 inicializa


as variáveis do TAD fila->Frente e fila->Tras. Este procedimen-
to deve ser chamado pela aplicação antes de iniciar o uso da fila.

void Cria_Fila(TipoFila *fila) {


fila->Frente = 0;
fila->Tras = -1;
}

Programa 5.2: Procedimento Cria_Fila.

70
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 71

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Para realizar o enfileiramento de um elemento, uma aplicação


utiliza a função mostrada no Programa 5.3. Esta função lógica recebe
a variável fila por referência e o dado a ser inserido por valor. O dado
será inserido se a fila não estiver cheia. Caso a fila estiver cheia, uma
mensagem de erro será exibida e a função retorna um código de
insucesso (0). Caso haja espaço na fila, o elemento é inserido e a
função retorna um código de sucesso (1).

int Enfileira(TipoFila *fila, TipoDado dado) {


if (fila->Tras == (Max - 1)) //fila cheia
{
printf("\n\nErro: Fila Cheia!\n");
return 0;
} else {
fila->Tras++;
fila->Dados[fila->Tras] = dado;
return 1;
}
}

Programa 5.3: Função Enfileira.

A função mostrada no Programa 5.4 é a Desenfileira. Esta


função retira um item do início da fila. As variáveis fila e dado são pas-
sadas por referência à função. Caso a fila esteja vazia, uma mensagem
de erro é exibida e a função retorna um código de falha (0). Se hou-
ver algum item a ser desenfileirado, este é salvo no parâmetro dado
para possível uso externo. Na seqüência, o vetor é compactado e a
função retorna um código de sucesso (1).

71
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 72

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

int Desenfileira(TipoFila *fila, TipoDado *dado) {


int i;

if (Fila_Vazia(*fila)) //fila vazia


{
printf("\n\nErro: Fila Vazia!\n");
return 0;
} else {
*dado = fila->Dados[fila->Frente];

/* compactacao do vetor */
for (i = 0; i < fila->Tras; i++)
fila->Dados[i] = fila->Dados[i+1];

fila->Tras--;
return 1;
}
}

Programa 5.4: Função Desenfileira.

Para consultar o elemento da frente da fila, a função


Consulta_Frente, mostrada no Programa 5.5, retorna por
parâmetro o dado armazenado na frente da Fila, retornando o valor
lógico VERDADEIRO. Se a fila estiver vazia, exibe uma mensagem de
erro e retorna FALSO.

int Consulta_Frente(TipoFila fila, TipoDado *dado) {


if (Fila_Vazia(fila)) //fila vazia
{
printf("\n\nErro: Fila Vazia!\n");
return 0;
} else {
*dado = fila.Dados[fila.Frente];
return 1;
}
}

Programa 5.5: Função Consulta_Frente.

72
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 73

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

A fim realizar uma consulta do número de elementos da fila, uma


aplicação pode utilizar a função Quantidade_Fila, mostrada no
Programa 5.6. A implementação por vetores permite uma consulta
simples, pelo retorno do índice Tras, uma vez que este indica a
última posição ocupada. Devido ao fato dos índices dos vetores na
Linguagem C iniciarem em 0, é necessário somar um ao valor do índice
Tras, para refletir a quantidade de elementos.

int Quantidade_Fila(TipoFila fila) {


return fila.Tras + 1;
}

Programa 5.6: Função Quantidade_Fila.

A função lógica Fila_Vazia, mostrada no Programa 5.7, consulta o


índice Tras, retornando VERDADEIRO (1) caso este seja igual a zero,
indicando que não existem dados na fila, ou FALSO (0) caso contrário.
A fila estará vazia se o índice Tras for igual a -1.

int Fila_Vazia(TipoFila fila) {


if (fila.Tras == -1)
return 1;
else
return 0;
}

Programa 5.7: Função Fila_Vazia.

73
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 74

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

5.3 Filas implementadas por variáveis dinâmicas

A implementação do TAD Fila usando alocação dinâmica utiliza as


definições de tipo e interfaces das operações mostradas no Programa
5.8. Trata-se do arquivo de cabeçalho do TAD.

#ifndef FILAD_H_
#define FILAD_H_

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct Celula {


TipoDado Dado;
struct Celula *Proximo;
}TipoCelula;

typedef struct {
TipoCelula *Frente, *Tras;
} TipoFila;

void Cria_Fila(TipoFila *fila);


int Fila_Vazia(TipoFila fila);
int Enfileira(TipoFila *fila, TipoDado dado);
int Desenfileira(TipoFila *fila, TipoDado *dado);
int Consulta_Frente(TipoFila fila, TipoDado *dado);
int Quantidade_Fila(TipoFila fila);

#endif /*FILAD_H_*/

Programa 5.8: Definições de tipo e interface das operações do TAD Fila.

O procedimento Cria_Fila inicializa as variáveis ponteiro


Frente e Tras com NULO. Isto indica que a fila está vazia e não
aponta para nenhuma célula (alocada na memória). Esta função é
vista no Programa 5.9.
74
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 75

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

void Cria_Fila(TipoFila *fila) {


fila->Frente = NULL;
fila->Tras = NULL;
}

Programa 5.9: Procedimento Cria Fila.

A função Enfileira é responsável pelo acréscimo de elementos ao


final da fila. No Programa 5.10. Como parâmetros, a função recebe a
variável fila, por referência e a variável dado, por valor. Este dado
será inserido na nova célula alocada no início da função. Após a alo-
cação bem-sucedida, a nova célula aponta para NULL. Se a função
estiver enfileirando a primeira célula, o ponteiro Frente é atualizado
para a nova célula, caso contrário, a última célula apontará para
novo. O ponteiro Tras é então atualizado para apontar para a nova
célula.

Sendo uma função lógica, retorna VERDADEIRO em caso de suces-


so ou FALSO em caso de falha.

75
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 76

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

int Enfileira(TipoFila *fila, TipoDado dado) {


TipoCelula *novo;

if ( (novo = (TipoCelula *) malloc(sizeof(TipoCelula))) == NULL) {


printf("\n\nErro de alocacao de memoria!");
return 0;
}
else {
novo->Dado = dado;
novo->Proximo = NULL;

if (Fila_Vazia(*fila))
fila->Frente = novo;
else
fila->Tras->Proximo = novo;

fila->Tras = novo;
return 1;
}
}

Programa 5.10: Procedimento Enfileira.

Para o processo de desenfileiramento, mostrado no Programa


5.11, o conteúdo do dado a ser removido é salvo no parâmetro
passado por referência. O ponteiro Aux guarda o endereço da célula
da frente para posterior liberação da memória. Antes, o ponteiro
Frente deve apontar para a próxima célula da fila, que será a nova
Frente. Ao se remover a última célula, o ponteiro Tras é atualizado
para NULL. Esta função também retorna 0 ou 1, indicando falha ou
sucesso na remoção de um elemento da fila, respectivamente.

76
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 77

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Enfileira(TipoFila *fila, TipoDado dado) {


TipoCelula *novo;

if ( (novo = (TipoCelula *) malloc(sizeof(TipoCelula))) == NULL) {


printf("\n\nErro de alocacao de memoria!");
return 0;
}
else {
novo->Dado = dado;
novo->Proximo = NULL;

if (Fila_Vazia(*fila))
fila->Frente = novo;
else
fila->Tras->Proximo = novo;

fila->Tras = novo;
return 1;
}
}

Programa 5.11: Função Desenfileira.

O Programa 5.12 mostra a função que poderá ser utilizada para


consultar o dado da célula da Frente. Para isto, o Dado é retornado
por referência e o código de sucesso é retornado. Caso a Fila esteja
vazia uma mensagem é exibida e um código de falha retornado.

77
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 78

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

int Consulta_Frente(TipoFila fila, TipoDado *dado)


{
if (Fila_Vazia(fila)) //fila vazia
{
printf("\n\nErro: Fila Vazia!");
return 0;
}
else
{
*dado = fila.Frente->Dado;
return 1;
}
}

Programa 5.12: Função Consulta_Frente.

A fim de consultar a quantidade de elementos na fila na imple-


mentação com variáveis dinâmicas, cada célula deve ser visitada e
contada. O Programa 5.13 mostra a função Quantidade_Fila que
realiza esta tarefa.

int Quantidade_Fila(TipoFila fila)


{
TipoCelula *aux;
int cont = 0;

aux = fila.Frente;
while(aux != NULL)
{
cont++;
aux = aux->Proximo;
}
return cont;
}

Programa 5.13: Função Quantidade_Fila.

78
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 79

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

A função Fila_Vazia, mostrada no Programa 5.14, apóia a imple-


mentação dos procedimentos de manipulação de fila. Retorna um
valor lógico correspondente ao fato da fila estar vazia ou não.

int Fila_Vazia(TipoFila fila)


{
if (fila.Frente == NULL)
return 1;
else
return 0;
}

Programa 5.14. Função Fila Vazia.

79
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 80

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

80
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 81

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

CAPÍTULO 6

Recursividade

6.1 Introdução

Este capítulo apresenta a implementação de alguns exemplos de


recursividade vistos em Estrutura de Dados I.

6.2 Revisando o conceito de recursividade

De acordo com o apresentado na disciplina de Estrutura de Dados


I, muitos problemas têm a propriedade de conter uma instância menor
do mesmo problema. Dizemos que estes problemas são recursivos. O
termo recursividade significa a chamada de um subprograma a si
próprio causando sua reativação para resolver uma nova instância do
problema.
Na linguagem C, assim como é válido uma função chamar outra
função, também é válido uma função chamar a si mesma. Trata-se por
recursiva uma função que faz uma chamada a si própria, direta ou
indiretamente.
Assim como os demais procedimentos, a função recursiva, deve
possuir pelo menos uma chamada proveniente de um local exterior a
ela, muitas vezes a função main(). Essa chamada é denominada
externa.
Vamos ver algumas implementações de algoritmos recursivos em
linguagem C. Começaremos com um programa de contagem
regressiva de um determinado número (N). O Programa 6.1 apresenta
uma forma não recursiva de mostrar esta lista de números decres-
centes. Você irá observar que foi usado o comando while para solu-
cionar o problema. No Programa 6.2 apresentamos o mesmo problema
sendo solucionado por um algoritmo recursivo, ou seja, declaramos a
função Dec(), que chama a si própria. O loop (ou laço) acontece
devido a esta chamada recursiva.
81
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 82

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

O Programa 6.1 começa com a leitura do valor que será decremen-


tado. Na linha 6 é utilizada a estrutura de repetição while que será
executada enquanto (num != 0).
O Programa 6.2 começa com a declaração de uma função recursi-
va chamada Dec(), que retorna um valor inteiro. Logo em seguida,
encontra-se a parte principal do sistema que contém uma leitura do
valor que será decrementado e então é chamada a função Dec().
Observe que não utilizamos nenhuma estrutura de repetição, o laço
acontece quando a função chama a si própria.

#include <stdio.h>

main(void)
{
int i,num;

printf (“\nDigite um numero:”);


scanf (“%d”, &num);

while (num != 0)
{
printf (“—> %d\n”, num);
--num;
}
return 0;
}

Programa 6.1: Programa não recursivo em C

82
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 83

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

#include <stdio.h>

int dec(int i)
{
printf ("--> %d\n", i);
if (i == 1)
return 1;
else
return dec(i-1);
}

main()
{
int i,num;

printf ("\nDigite um numero: ");


scanf ("%d", &num);

i = dec(num);
return 0;
}

Programa 6.2: Programa Recursivo em C.

O próximo programa (Programa 6.3) recursivo a ser implementado


em C é o fatorial. O fatorial de N é definido por:

0! = 1
N! = N x (N-1)!, para N >= 0

Pode-se observar que, dentro da própria definição, aparece o


operador que está sendo definido. Para N = 3, 3! = 6. A seqüência de
operações que produz o resultado de 3! é apresentada a seguir:

83
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 84

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

3! = 3 x (3-1)! = 3 x 2 x 1 x 1 = 6
(3-1)! = 2 x (2-1)! = 2 x 1 = 2
(2-1)! = 1 x (1-1)! = 1 x 1 = 1
(1-1)! = 0! = 1

Fonte: Arthur Vargas Lopes

int fatorial(int n)
{
if (n == 0)
return 1;
else
return n * fatorial(n-1);
}
int main(void)
{
printf(“%d”,fatorial(5));
return 0;
}

Programa 6.3: Fatorial com recursão em C.

O Programa 6.3 foi dividido em duas partes: a primeira onde é


feita a definição da função fatorial. Esta função recebe um valor
inteiro como argumento e devolve outro valor inteiro. Observe o que
acontece se chamarmos essa função da seguinte maneira:

fatorial(5)

Observe a execução do algoritmo considerando que tenha rece-


bido valor 5.
fatorial é chamada para o valor 5.

84
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 85

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

1ª CHAMADA: fatorial := 5 * fatorial(4);


Fatorial é chamada para o valor 4.

2ª CHAMADA: fatorial := 4 * fatorial(3);


Fatorial é chamada para o valor 3.

3ª CHAMADA: fatorial := 3 * fatorial(2);


Fatorial é chamada para o valor 2.

4ª CHAMADA: fatorial := 2 * fatorial(1);

Se valor for 1, retorna 1. Condição de parada verdadeira, fim da


recursão.
E então a execução do programa volta para função principal
(main()). Assim, a saída completa se parece com:

fatorial <- 2 * 1; //2


fatorial <- 3 * 2; // 6
fatorial <- 4 * 6; // 24
fatorial <- 5 * 24; // 120

A primeira chamada retorna o valor 120.

O exemplo 6.4 apresenta uma implementação para determinar o


valor de um elemento máximo de um vetor v [0 .. n-1] . O problema
só faz sentido se o vetor não é vazio, ou seja, se n 1.

85
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 86

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

#include <stdio.h>
#include <stdlib.h>

int maximo (int qtd, int vet[]) {


int x;

if (qtd == 2) {
if (vet[0] < vet[1])
return vet[1];
else
return vet[0];
}
if (qtd == 1)
return vet[0];

x = maximo(qtd-1, vet);
if (x < vet[qtd-1])
return vet[qtd-1];
else
return x;
}

int main (void) {


int *vet, num, max, i;
printf (“\nNúmero de elementos: “);
scanf (“%d”, &num);

vet = (int *) malloc(sizeof(int) * num);

printf (“Entre com %d inteiros:\n”, num);


for (i = 0; i < num; i++)
scanf (“%d”, &vet[i]);

printf (“máximo = %d\n”, maximo(num, vet));


return 0;
}

Programa 6.4: Máximo recursivo em C

86
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 87

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

A função maximo é chamada pela função main() e por si própria.


Na função main() é solicitado ao usuário que liste uma lista de
números que são adicionados a um vetor (vet[]), pré-alocado de um
tamanho escolhido pelo usuário. A função maximo recebe como
parâmetro o vetor e o número de elementos do vetor.

#include <stdio.h>
#include <stdlib.h>

int mdc(int a, int b);

int main()
{
int a,b;
char op;

printf(“Informe dois numeros inteiros: “);


scanf(“%i%i”, &a, &b);
printf(“m.d.c => %i\n”, mdc(a, b));
return 0;
}
int mdc(int a, int b)
{
if(b == 0)
return a;
else
return mdc(b, a % b);
}

Programa 6.5: MDC recursivo em C.

87
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 88

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Observe outro exemplo de recursividade direta:

#include <stdio.h>
#include <stdlib.h>

int soma (int v[], int n) {


int s;
if (n == 1)
return V [0];
else {
s = soma (v, n-2) + v[n-1];
return s;
}
}

int main (void)


{
int *vet, num, i;
printf ("\nNúmero de elementos: ");
scanf ("%d", &num);
vet = (int *) malloc(sizeof(int) * num);
printf ("Entre com %d Elementos:\n", num);

for (i = 0; i < num; i++)


scanf ("%d", &vet[i]);

printf ("soma = %d\n", soma(vet, num));


return 0;
}

Programa 6.6: Soma recursiva em C.

88
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 89

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Exercícios

1. Uma empresa contratou 15 funcionários temporários. De acor-


do com o valor das vendas mensais, os funcionários adquirem pontos
que determinarão seus salários ao final de cada mês. Sabe-se que
esses funcionários trabalharão nos meses de novembro de 2008 a
janeiro de 2009. Faça um programa em C que implemente um TAD
que:
a. Cadastre os nomes dos funcionários e suas respectivas vendas
mensais;
b. Calcule e mostre a pontuação geral de cada funcionário nos
três meses. Sabe-se que cada R$ 100,00 equivalem a 1 ponto;
c. Calcule e mostre a pontuação geral de cada mês;
d. Determine e mostre a maior pontuação atingida nos três
meses, mostrando o nome do funcionário. Desconsidere empates;
e. Determine e mostre o valor total vendido.

2. Faça um programa em C que implemente um TAD para uma


escola que leia o código, o sexo ([M] - Masculino / [F] - Feminino) e o
número de horas/aula dadas no mês dos professores de uma escola,
sabendo que um professor ganha R$ 12,50 hora/aula e que a escola
possui dez professores. Após a leitura, mostre:
a) Uma listagem contendo (código, salário bruto, o desconto e o
salário líquido) de todos os professores;
b) A média aritmética dos salários brutos do professores do sexo
masculino;
c) A média aritmética dos salários brutos do professores do sexo
feminino.

89
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 90

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

Os descontos devem ser calculados de acordo com a tabela


abaixo:

3. Implemente em C uma solução em TAD para uma companhia


aérea, com a estrutura e operações relacionadas. O programa deverá
ler:
a) Os números dos aviões;
b) A quantidade de lugares disponíveis em cada avião.

Devem ser implementadas as seguintes operações:


c) Cadastrar aviões e lugares disponíveis em cada aeronave;
d) Consultar avião por número;
e) Consultar passageiro por nome;
f) Realizar reserva de passagem.

4. Acrescentar ao Programa 2.2:


a) Leitura e escrita através dos ponteiros pr e pc;
b) Escrita dos valores dos endereços armazenados nas variáveis
tipo ponteiro.

5. Criar um registro para armazenar dados de um aluno


(matrícula, nome e curso). Aloque memória para um vetor de registros
com tamanho definido pelo usuário. Leia os dados do vetor e escreva
o total de alunos do curso de “TADS”.

90
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 91

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

6. A partir do programa apresentado no item 3.2, lista


implementada por alocação estática, implemente as seguintes
funcionalidades:
a) Criticar número de registros da lista no módulo de inserção
para avisar quando a lista estiver cheia;
b) Retirar uma informação. Para tal, deve ser solicitado ao
usuário o código do produto a ser retirado;
c) Consultar se determinado produto consta da lista. Solicitar ao
usuário o nome do produto a pesquisar, e informar se o mesmo cons-
ta, ou não, da lista;
d) Fornecer o valor total do estoque. O valor do estoque é obtido
multiplicando o preço unitário de cada produto pela respectiva quan-
tidade e somando esses produtos;
e) Atualizar as informações de um produto, dado o código;
f) Informar quantos produtos constam da lista.

7. Implementar uma lista simplesmente encadeada, a partir da


estrutura apresentada no item 3.3, implementação de lista
simplesmente encadeada, com as mesmas funcionalidades da lista do
exercício 6.

8. Implemente o procedimento Quantidade_Pilha para o TAD Pilha


implementado com ponteiros. Acrescente uma variável quantidade na
estrutura do TAD e altere as operações necessárias.

9. Implemente o procedimento Imprimir_Pilha para o TAD Pilha


implementado com ponteiros, utilizando as operações definidas no
TAD, ou seja, acessando diretamente apenas o elemento TOPO através
das operações.

10.Implemente o procedimento Quantidade_Fila para o TAD Fila


implementado com ponteiros. Acrescente uma variável quantidade na
estrutura do TAD e altere as operações necessárias.

11.Implemente o procedimento Imprimir_Fila para o TAD Fila


implementado com ponteiros, utilizando as operações definidas no
TAD, ou seja, acessando diretamente apenas os elementos FRENTE e
TRAS através das operações.

91
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:48 Page 92

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

12.Escreva em linguagem C uma função recursiva que ordene um


vetor de Pessoas e liste-os por ordem:
a) Crescente do índice do vetor;
b) Decrescente do índice do vetor.

13.Escreva em linguagem C uma função recursiva e outra não


recursiva para efetuar cada uma das seguintes alíneas:
a) Somar os elementos de um vetor de números inteiros. Altere o
programa anterior de modo a visualizar também as somas intermédias;
b) Escreva uma função recursiva e booleana para determinar se
um elemento X é elemento do vetor a[0..n-1] e escreva os elementos
percorridos por ordem inversa do processo de pesquisa;
c) Verificar se a leitura de um inteiro é a mesma da esquerda para
a direita ou da direita para a esquerda.

14.Escreva em linguagem C uma função recursiva que calcule e


retorne o comprimento de uma lista ligada.

15.Escreva em linguagem C uma função recursiva que imprima os


elementos de uma lista ligada na ordem em que aparecem na lista.

16.Escreva em linguagem C uma função recursiva que imprima os


elementos de uma lista ligada na ordem inversa em que aparecem na
lista.

17.Escreva em linguagem C uma função recursiva que retire um


elemento da lista.

18.Escreva em linguagem C uma função recursiva que inverta os


elementos de uma lista ligada.

92
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 93

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

19. Escreva em linguagem C uma função não recursiva para as


seguintes funções:
a) funcao f (i: inteiro) : inteiro
inicio
se i > 1 entao
retorne i + f(i-1)
senao
retorne 1
fimse
fimfuncao

b) funcao f ( i: inteiro) : inteiro


inicio
se i=0 entao
retorne 0
senao
se i = 1 entao
i <- 1
senao
retorne f(i-1) + f(i-2)
fimse
fimse
fimfuncao

93
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 94

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

94
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 95

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo A
Implementação do TAD Conta utilizando vetores.

conta-tad.h

#ifndef CONTATAD_H_
#define CONTATAD_H_

#define max 100

typedef struct tipo_conta {


int numero;
char nome[50];
float saldo;
} TConta;

void CadastrarConta(TConta c[]);

void VisualizarConta(TConta c[]);

void ExcluirConta(TConta c[]);

#endif /*CONTATAD_H_*/

95
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 96

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

conta-tad.c

#include <stdio.h>
#include <string.h>
#include <values.h>
#include “conta-tad.h”

void CadastrarConta(TConta c[]) {


int num_conta;

printf(“\nDigite o numero da conta: “);


scanf(“%d”, &num_conta);
if (c[num_conta].numero != 0) //conta ja existe
printf(“\nErro: Ja existe conta com este numero!”);
else {
c[num_conta - 1].numero = num_conta;
printf(“Informe nome do cliente: “);
scanf(“%s”, c[num_conta - 1].nome);
printf(“Informe saldo do cliente: “);
scanf(“%f”, &c[num_conta - 1].saldo);
printf(“\nConta cadastrada com sucesso!”);
}
}

void VisualizarConta(TConta c[]) {


int i;
char nome_cli[50];

printf(“Digite o nome do Cliente a ser Consultado: “);


scanf(“%s”, nome_cli);
for (i = 0; i < 10; i++) {
if (!strcmp(c[i].nome, nome_cli)) {
printf(“\n\nNumero da Conta: %d”, c[i].numero);
printf(“\nNome.........: %s”, c[i].nome);
printf(“\nSaldo........: R$ %.2f”, c[i].saldo);
}
}
}

96
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 97

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

void ExcluirConta(TConta c[]) {


int posicao = -1, i;
float menor_saldo = MAXFLOAT;

for (i = 0; i < 10; i++) {


if (c[i].numero != 0) { //conta ja existe
if (c[i].saldo < menor_saldo) {
menor_saldo = c[i].saldo;
posicao = i;
}
}
}
if (posicao == -1)
printf(“Nenhuma Conta foi Cadastrada”);
else {
c[posicao].numero = 0;
c[posicao].saldo = 0;
strcpy(c[posicao].nome, “ “);
printf(“Conta %d excluida com sucesso”, posicao + 1);
}
}

97
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 98

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

aplicacao-conta.c

#include <stdio.h>
#include <string.h>
#include “conta-tad.h”

int main(void) {
TConta contas[max];
int i, op = 0;

for (i = 0; i < 10; i++) {


contas[i].numero = 0;
strcpy(contas[i].nome, “ “);
contas[i].saldo = 0;
}

while (op != 4) {
printf(“\n\nMenu de Opcoes:”);
printf(“\n1 - Cadastrar Contas”);
printf(“\n2 - Visualizar Contas Cliente”);
printf(“\n3 - Excluir Conta de menor saldo”);
printf(“\n4 - Sair”);
printf(“\n\nDigite a sua Opcao:”);
scanf(“%d”, &op);

switch (op) {
case 1:
CadastrarConta(contas);
break;
case 2:
VisualizarConta(contas);
break;
case 3:
ExcluirConta(contas);
break;
default:
printf(“\nErro: Opção Inválida”);
}
}
return 0;
}

98
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 99

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo B
Implementação do TAD Lista utilizando vetores.

lista.h

#ifndef LISTA_H_
#define LISTA_H_

#define max 100 //def. da constante com o valor maximo de itens


typedef struct tipo_item { // definicao da estrutura
int cod;
char especif[30];
float preco;
int quant;
} TItem;

typedef struct tipo_lista {//definicao da estrutura do vetor


TItem item[max];
int tamanho;
} TLista;

void cria_lista_vazia(TLista *lista);


//passagem por referencia

int vazia(TLista lista); //passagem por valor

void inserir(TLista *lista);

void listar(TLista lista);

#endif /*LISTA_H_*/

99
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 100

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

lista.c

#include <stdio.h>
#include “lista.h”

void cria_lista_vazia(TLista *lista) {


lista->tamanho = 0;
}

int vazia(TLista lista) {


if (lista.tamanho == 0)
return 1;
else
return 0;
}

void inserir(TLista *l) {


printf(“\nDigite o codigo do produto: “);
scanf(“%d”, &l->item[l->tamanho].cod);
printf(“Especificacao: “);
scanf(“%s”, l->item[l->tamanho].especif);
printf(“Digite o preco: “);
scanf(“%f”, &l->item[l->tamanho].preco);
printf(“Digite a quantidade: “);
scanf(“%d”, &l->item[l->tamanho].quant);
l->tamanho ++;
}
void listar(TLista l) {
int i;

if (vazia(l))
printf(“Nao ha produto cadastrado”);
else {
printf(“\n\nProdutos cadastrados:”);
for (i = 0; i < l.tamanho; i++) {
printf(“\nCodigo: %5d”, l.item[i].cod);
printf (“ Especificacao: %s”,
l.item[i].especif);
printf(“ Preco: %6.2f “,
l.item[i].preco);
printf(“Qtd: %3i”, l.item[i].quant);
}
}
}

100
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 101

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

aplicacao-lista.c

#include <stdio.h>
#include “lista.h”

int main(void) {
char op = ‘ ‘;
TLista lista;

cria_lista_vazia(&lista);
while (op != ‘3’) {
printf(“\n\n\t\tCadastro de produtos”);
printf(“\n\n\t\t1 - Inserir dados”);
printf(“\n\t\t2 - Listar”);
printf(“\n\t\t3 - Encerrar programa”);
printf(“\n\n\t\tOpcao escolhida: “);
__fpurge(stdin);
scanf(“%c”, &op);
switch (op) {
case ‘1’:
inserir(&lista); //argumento passado por ref.
break;
case ‘2’:
listar(lista); //argumento passado por valor
break;
}
}
return 0;
}

101
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 102

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

102
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 103

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo C
Implementação do TAD Lista utilizando variáveis dinâmicas.

listad.h
#ifndef LISTAD_H_
#define LISTAD_H_

typedef int TipoChave;

typedef struct {
TipoChave cod;
char especif[30];
float preco;
int quant;
} TipoDado;

typedef struct Celula {


TipoDado Dado;
struct Celula *Proximo;
}TipoCelula;

typedef struct {
TipoCelula *Inicio;
} TipoLista;

void CriaLista(TipoLista *lista);

int ListaVazia(TipoLista lista);

int InsereOrdenadoLista(TipoLista *lista, TipoDado dado);

int RetiraLista(TipoLista *lista, TipoChave cod,


TipoDado *dado);

void ListarItens(TipoLista lista);

int ConsultaItem(TipoLista lista, TipoChave cod,


TipoDado *dado);

void ApagarLista(TipoLista *lista);

#endif /*LISTAD_H_*/

103
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 104

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

listad.c

#include <stdio.h>
#include <stdlib.h>
#include “listad.h”

void CriaLista(TipoLista *lista) {


lista->Inicio = NULL;
}

int ListaVazia(TipoLista lista) {


if (lista.Inicio == NULL)
return 1;
else
return 0;
}

104
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 105

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int InsereOrdenadoLista(TipoLista *lista, TipoDado dado)


{
TipoCelula *aux1, *aux2, *novo;

if ( (novo = (TipoCelula *)malloc(sizeof(TipoCelula)))


== NULL) {
printf(“\n\nErro de alocacao de memoria!”);
return 0;
} else {
novo->Dado = dado;
// busca do local de insercao

if (ListaVazia(*lista)) { //eh o primeiro item?


lista->Inicio = novo;
novo->Proximo = NULL;
} else {
if (lista->Inicio->Dado.cod >
novo->Dado.cod) {// no inicio
novo->Proximo = lista->Inicio;
lista->Inicio = novo;
} else { // insere no meio ou no fim
da lista
aux1 = lista->Inicio;
aux2 = lista->Inicio->Proximo;
while ( (aux2 != NULL) &&
(aux2->Dado.cod <
novo->Dado.cod)) {
aux1 = aux2;
aux2 = aux2->Proximo;
} //ao fim do while, insere
entre aux1 e aux2
aux1->Proximo = novo;
novo->Proximo = aux2;
}
}
}
return 1;
}

int RetiraLista(TipoLista *lista, TipoChave cod,


TipoDado *dado) {
TipoCelula *aux, *aux2;

if (ListaVazia(*lista)) {
printf(“Erro: Nao ha produtos
cadastrados!”);
return 0;
}

105
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 106

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

aux = lista->Inicio;
if (cod == lista->Inicio->Dado.cod) {
//retira a primeira celula
*dado = lista->Inicio->Dado;
//salva o dado no parametro
lista->Inicio = lista->Inicio->Proximo;
free(aux);
return 1;
}
while (aux->Proximo != NULL && aux->Proximo->Dado.cod != cod) {
// busca celula
aux = aux->Proximo;
}
if (aux->Proximo == NULL) {
// nao achou o dado solicitado
printf(“Erro: Este produto nao esta cadastrado!”);
return 0; // cod nao cadastrado, retorna falso
}
*dado = aux->Proximo->Dado;
//salva o dado no parametro
aux2 = aux->Proximo;
aux->Proximo = aux->Proximo->Proximo;
free(aux2);
return 1; // item retirado, retorna verdadeiro
}

106
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 107

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int ConsultaItem(TipoLista lista, TipoChave cod,


TipoDado *dado) {
TipoCelula *aux;

if (ListaVazia(lista)) {
printf(“Erro: Nao ha produtos cadastrados!”);
return 0;
}

aux = lista.Inicio;
while (aux != NULL) { // busca celula
if (cod == aux->Dado.cod) {
//retira a primeira celula
*dado = lista.Inicio->Dado;
//salva o dado no parametro
return 1;
}
aux = aux->Proximo;
}
printf(“Erro: Este produto nao esta cadastrado!”);
return 0; // cod nao cadastrado, retorna falso
}

void ApagarLista(TipoLista *lista) {


TipoCelula *noatual, *aux;

noatual = lista->Inicio;

while (noatual != NULL) {


// sao para desalocar todos os naos
aux = noatual->Proximo;
//guarda o endereco da prox celula
free(noatual); // liberando a memoria.
noatual = aux;
}
lista->Inicio = NULL;
}

107
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 108

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

void ListarItens(TipoLista lista) {


TipoCelula *noatual;

if (ListaVazia(lista))
printf(“Erro: Nao ha produtos cadastrados!”);
else {
noatual = lista.Inicio;
printf(“\n\nProdutos cadastrados:”);
do {
printf(“\nCodigo: %5d”, noatual->Dado.cod);
printf(“\nEspecificacao: %s”,
noatual->Dado.especif);
printf(“\nPreco: %6.2f“, noatual->Dado.preco);
printf(“\nQuantidade: %3i”,
noatual->Dado.quant);
noatual = noatual->Proximo;
} while (noatual != NULL);
}
}

108
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 109

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

aplicacao-listad.c

#include <stdio.h>
#include <stdlib.h>
#include “listad.h”

int main(void) {
TipoLista l;
TipoDado d;
TipoChave cod;
int opcao;

CriaLista(&l);

do {
printf(“\n Lista de Produtos”);
printf(“\n\n1 - Inserir um produto”);
printf(“\n2 - Remover um produto”);
printf(“\n3 - Listar todos os produtos”);
printf(“\n4 - Consultar um produto”);
printf(“\n5 - Apagar a lista”);
printf(“\n\n6 - Sair”);
printf(“\n\nOpcao -> “);
scanf(“%d”, &opcao);

switch (opcao) {
case 1:
printf(“\nCadastro de Produto: “);
printf(“\n\nCodigo: “);
scanf(“%d”, &d.cod);
printf(“\nEspecificacao: “);
scanf(“%s”, d.especif);
printf(“\nPreco: “);
scanf(“%f”, &d.preco);
printf(“\nQuantidade: “);
scanf(“%d”, &d.quant);
if (InsereOrdenadoLista(&l, d)) {
printf(“Produto CODIGO = %d
inserido com sucesso!\
n”, d.cod);
}
break;

109
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 110

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

case 2:
printf(“\n\nCodigo para retirada: “);
scanf(“%d”, &cod);
if (RetiraLista(&l, cod, &d)) {
printf(“Produto CODIGO = %d
removido com sucesso!\
n”, d.cod);
}
break;
case 3:
ListarItens(l);
break;
case 4:
printf(“\n\nCodigo para pesquisa: “);
scanf(“%d”, &cod);
if (ConsultaItem(l, cod, &d)) {
printf(“\nDados do Produto: “);
printf(“\n\nCodigo: %5d”,
d.cod);
printf(“\nEspecificacao: %s”,
d.especif);
printf(“\nPreco: %6.2f”,
d.preco);
printf(“\nQuantidade: %3d\n”,
d.quant);
}
break;
case 5:
ApagarLista(&l);
break;
case 6:
printf(“\n\nSaindo....\n”);
break;
default:
printf(“\n\nErro: Opcao invalida\n”);
}
} while (opcao != 6);
return 0;
}

110
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 111

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo D
Implementação do TAD Pilha utilizando vetores.

pilha.h

#ifndef PILHA_H_
#define PILHA_H_

#define Max 100

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct {
int Topo;
TipoDado Dados[Max];
} TipoPilha;

void Cria_Pilha(TipoPilha *pilha);

int Pilha_Vazia(TipoPilha pilha);

int Empilha(TipoPilha *pilha, TipoDado dado);

int Desempilha(TipoPilha *pilha, TipoDado *dado);

int Consulta_Topo(TipoPilha pilha, TipoDado *dado);

#endif /*PILHA_H_*/

111
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 112

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

pilha.c

#include <stdio.h>
#include <stdlib.h>
#include "pilha.h"

void Cria_Pilha(TipoPilha *pilha) {


pilha->Topo = -1;
}

int Pilha_Vazia(TipoPilha pilha) {


if (pilha.Topo == -1)
return 1;
else
return 0;
}

int Empilha(TipoPilha *pilha, TipoDado dado) {


if (pilha->Topo == (Max - 1)) { //pilha cheia
printf("\n\nErro: Pilha Cheia!\n");
return 0;
} else {
pilha->Topo++;
pilha->Dados[pilha->Topo] = dado;
return 1;
}
}

int Desempilha(TipoPilha *pilha, TipoDado *dado) {


if (Pilha_Vazia(*pilha)) { //pilha vazia
printf("\n\nErro: Pilha Vazia!\n");
return 0;
} else {
*dado = pilha->Dados[pilha->Topo];
pilha->Topo--;
return 1;
}
}

112
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 113

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Consulta_Topo(TipoPilha pilha, TipoDado *dado) {


if (Pilha_Vazia(pilha)) { //pilha vazia
printf("\n\nErro: Pilha Vazia!\n");
return 0;
} else {
*dado = pilha.Dados[pilha.Topo];
return 1;
}
}

aplicacao-pilha.c

#include <stdio.h>
#include <stdlib.h>
#include “pilha.h”

int main(void) {
TipoPilha p;
TipoDado d;
int opcao;

Cria_Pilha(&p);

do {
printf(“\n Operacoes sobre uma pilha”);
printf(“\n\n1 - Empilhar um dado”);
printf(“\n2 - Desempilhar um dado”);
printf(“\n3 - Consultar o dado no topo da pilha”);
printf(“\n\n4 - Sair”);
printf(“\n\nOpcao -> “);
scanf(“%d”, &opcao);

113
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 114

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

switch (opcao) {
case 1:
printf(“\nChave: “);
scanf(“%d”, &d.chave);
if (Empilha(&p, d)) {
printf(“Elemento Empilhado ->
%d\n”, d.chave);
}
break;
case 2:
if (Desempilha(&p, &d)) {
printf(“Elemento Desempilhado ->
%d\n”, d.chave);
}
break;
case 3:
if (Consulta_Topo(p, &d)) {
printf(“Topo -> %d\n”, d.chave);
}
break;
case 4:
printf(“\n\nSaindo....\n”);
break;
default:
printf(“\n\nErro: Opcao invalida\n”);
}
} while (opcao != 4);
return 0;
}

114
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 115

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo E
Implementação de pilha utilizando alocação dinâmica.

pilhad.h

#ifndef PILHAD_H_
#define PILHAD_H_

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct Celula {


TipoDado Dado;
struct Celula *Anterior;
} TipoCelula;

typedef struct {
TipoCelula *Topo;
} TipoPilha;

void Cria_Pilha(TipoPilha *pilha);

int Pilha_Vazia(TipoPilha pilha);

int Empilha(TipoPilha *pilha, TipoDado dado);

int Desempilha(TipoPilha *pilha, TipoDado *dado);

int Consulta_Topo(TipoPilha pilha, TipoDado *dado);

#endif /*PILHAD_H_*/

115
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 116

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

pilhad.c

#include <stdio.h>
#include <stdlib.h>
#include “pilhad.h”

void Cria_Pilha(TipoPilha *pilha) {


pilha->Topo = NULL;
}

int Pilha_Vazia(TipoPilha pilha) {


if (pilha.Topo == NULL)
return 1;
else
return 0;
}

int Empilha(TipoPilha *pilha, TipoDado dado) {


TipoCelula *novo;

if ( (novo = (TipoCelula *)
malloc(sizeof(TipoCelula))) == NULL){
printf(“\n\nErro de alocacao de memoria!”);
return 0;
} else {
novo->Dado = dado;
novo->Anterior = pilha->Topo;
pilha->Topo = novo;
return 1;
}
}

116
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 117

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Desempilha(TipoPilha *pilha, TipoDado *dado) {


TipoCelula *aux;

if (Pilha_Vazia(*pilha)) { //pilha vazia


printf(“\n\nErro: Pilha Vazia!”);
return 0;
} else {
*dado = pilha->Topo->Dado;
aux = pilha->Topo;
pilha->Topo = pilha->Topo->Anterior;
free(aux);
return 1;
}
}

int Consulta_Topo(TipoPilha pilha, TipoDado *dado) {


if (Pilha_Vazia(pilha)) { //pilha vazia
printf(“\n\nErro: Pilha Vazia!”);
return 0;
} else {
*dado = pilha.Topo->Dado;
return 1;
}
}

117
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 118

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

aplicacao-pilhad.c

#include <stdio.h>
#include <stdlib.h>
#include “pilhad.h”

int main(void) {
TipoPilha p;
TipoDado d;
int opcao;

Cria_Pilha(&p);

do {
printf(“\n Operacoes sobre uma pilha”);
printf(“\n\n1 - Empilhar um dado”);
printf(“\n2 - Desempilhar um dado”);
printf(“\n3 - Consultar o dado no topo da pilha”);
printf(“\n\n4 - Sair”);
printf(“\n\nOpcao -> “);
scanf(“%d”, &opcao);

switch (opcao) {
case 1:
printf(“\nChave: “);
scanf(“%d”, &d.chave);
if (Empilha(&p, d)) {
printf(“Elemento Empilhado ->
%d\n”, d.chave);
}
break;
case 2:
if (Desempilha(&p, &d)) {
printf(“Elemento Desempilhado ->
%d\n”, d.chave);
}

break;

118
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 119

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

case 3:
if (Consulta_Topo(p, &d)) {
printf(“Topo -> %d\n”, d.chave);
}
break;
case 4:
printf(“\n\nSaindo....\n”);
break;
default:
printf(“\n\nErro: Opcao invalida\n”);
}
} while (opcao != 4);
return 0;
}

119
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 120

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

120
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 121

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo F
Implementação de fila utilizando vetores.

fila.h

#ifndef FILA_H_
#define FILA_H_

#define Max 100

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct {
int Frente, Tras;
TipoDado Dados[Max];
} TipoFila;

void Cria_Fila(TipoFila *fila);

int Fila_Vazia(TipoFila fila);

int Enfileira(TipoFila *fila, TipoDado dado);

int Desenfileira(TipoFila *fila, TipoDado *dado);

int Consulta_Frente(TipoFila fila, TipoDado *dado);

#endif /*FILA_H_*/

121
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 122

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

fila.c

#include <stdio.h>
#include “fila.h”

void Cria_Fila(TipoFila *fila) {


fila->Frente = 0;
fila->Tras = -1;
}

int Fila_Vazia(TipoFila fila) {


if (fila.Tras == -1)
return 1;
else
return 0;
}

int Enfileira(TipoFila *fila, TipoDado dado) {


if (fila->Tras == (Max - 1)) { //fila cheia
printf(“\n\nErro: Fila Cheia!\n”);
return 0;
} else {
fila->Tras++;
fila->Dados[fila->Tras] = dado;
return 1;
}
}

122
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 123

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Desenfileira(TipoFila *fila, TipoDado *dado) {


int i;

if (Fila_Vazia(*fila)) { //fila vazia


printf(“\n\nErro: Fila Vazia!\n”);
return 0;
} else {
*dado = fila->Dados[fila->Frente];

/* compactacao do vetor */
for (i = 0; i < fila->Tras; i++)
fila->Dados[i] = fila->Dados[i+1];

fila->Tras--;
return 1;
}
}

int Consulta_Frente(TipoFila fila, TipoDado *dado) {


if (Fila_Vazia(fila)) { //fila vazia
printf(“\n\nErro: Fila Vazia!\n”);
return 0;
} else {
*dado = fila.Dados[fila.Frente];
return 1;
}
}

123
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 124

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

aplicacao-fila.c

#include <stdio.h>
#include “fila.h”

int main(void)
{
TipoFila f;
TipoDado d;
int opcao;

Cria_Fila(&f);

do
{
printf(“\n Operacoes sobre uma fila
(Tamanho Maximo: %d)”, Max);
printf(“\n\n1 - Enfileirar um dado”);
printf(“\n2 - Desenfileirar um dado”);
printf(“\n3 - Consultar o dado da frente da fila”);
printf(“\n\n4 - Sair”);
printf(“\nOpcao -> “);
scanf(“%d”, &opcao);

switch(opcao)
{
case 1:
printf(“\nChave: “);
scanf(“%d”, &d.chave);
if (Enfileira(&f, d))
printf(“Elemento Enfileirado -> %d\n”, d.chave);
break;

124
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 125

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

case 2:
if(Desenfileira(&f, &d))
printf(“Elemento Desenfileirado -> %d\n”, d.chave);
break;
case 3:
if(Consulta_Frente(f, &d))
printf(“Frente -> %d\n”, d.chave);
break;
case 4:
printf(“\n\nSaindo....\n”);
break;
default:
printf(“\n\nErro: Opcao invalida”);

}
}while(opcao != 4);
return 0;
}

125
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 126

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

126
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 127

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo G
Implementação de fila utilizando alocação dinâmica.

filad.h

#ifndef FILAD_
#define FILAD_

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct Celula {


TipoDado Dado;
struct Celula *Proximo;
}TipoCelula;

typedef struct {
TipoCelula *Frente, *Tras;
} TipoFila;

void Cria_Fila(TipoFila *fila);

int Fila_Vazia(TipoFila fila);

int Enfileira(TipoFila *fila, TipoDado dado);

int Desenfileira(TipoFila *fila, TipoDado *dado);

int Consulta_Frente(TipoFila fila, TipoDado *dado);

int Quantidade_Fila(TipoFila fila1);

#endif /*FILAD_*/

127
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 128

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

filad.c

#include <stdio.h>
#include <stdlib.h>
#include “filad.h”

void Cria_Fila(TipoFila *fila) {


fila->Frente = fila->Tras = NULL;
}

int Fila_Vazia(TipoFila fila) {


if (fila.Frente == NULL)
return 1;
else
return 0;
}

int Enfileira(TipoFila *fila, TipoDado dado) {


TipoCelula *novo;

if ((novo = (TipoCelula *)
malloc(sizeof(TipoCelula))) == NULL) {
printf(“\n\nErro de alocacao de memoria!”);
return 0;
} else {
novo->Dado = dado;
novo->Proximo = NULL;

if (FilaVazia(*fila))
fila->Frente = novo;
else
fila->Tras->Proximo = novo;

fila->Tras = novo;
return 1;
}
}

128
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 129

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int Desenfileira(TipoFila *fila, TipoDado *dado) {


TipoCelula *aux;

if (Fila_Vazia(*fila)) //fila vazia


{
printf(“\n\nErro: Fila Vazia!”);
return 0;
} else {
*dado = fila->Frente->Dado; /* guarda do
dado da frente */
aux = fila->Frente;
fila->Frente = fila->Frente->Proximo;
free(aux);

if (Fila_Vazia(*fila))
fila->Tras = NULL;
return 1;
}
}

int Consulta_Frente(TipoFila fila, TipoDado *dado) {


if (Fila_Vazia(fila)) //fila vazia
{
printf(“\n\nErro: Fila Vazia!”);
return 0;
} else {
*dado = fila.Frente->Dado;
return 1;
}
}

129
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 130

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

int Quantidade_Fila(TipoFila fila)


{
TipoCelula *aux;
int cont = 0;

aux = fila.Frente;
while(aux != NULL)
{
cont++;
aux = aux->Proximo;
}
return cont;
}

130
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 131

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

aplicacao-filad.c

#include <stdio.h>
#include <stdlib.h>
#include “filad.h”

int main(void) {
TipoFila f;
TipoDado d;
int opcao;

Cria_Fila(&f);

do {
printf(“\n Operacoes sobre uma Fila”);
printf(“\n\n1 - Enfileirar um dado”);
printf(“\n2 - Desenfileirar um dado”);
printf(“\n3 - Consultar o dado na frente da fila”);
printf(“\n4 - Quantidade de itens na fila”);
printf(“\n\n5 - Sair”);
printf(“\n\nOpcao -> “);
scanf(“%d”, &opcao);

switch (opcao) {
case 1:
printf(“\nChave: “);
scanf(“%d”, &d.chave);
if (Enfileira(&f, d)) {
printf(“Elemento Enfileirado -> %d”,
d.chave);
}
break;

131
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 132

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

case 2:
if (Desenfileira(&f, &d)) {
printf(“Elemento Desenfileirado -> %d”,
d.chave);
}
case 3:
if (Consulta_Frente(f, &d)) {
printf(“Frente -> %d”, d.chave);
}
break;
case 4:
printf(“\n\nTotal de itens na fila:
%d\n”, Quantidade_Fila(f));
break;
case 5:
printf(“\n\nSaindo....”);
break;
default:
printf(“\n\nErro: Opcao invalida”);

}
} while (opcao != 5);
return 0;
}

132
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 133

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

Anexo H
Implementação de fila circular.

filacircular.h
#ifndef FILACIRCULAR_H_
#define FILACIRCULAR_H_

#define Max 10

typedef int TipoChave;

typedef struct {
TipoChave chave;
/* outros campos */
} TipoDado;

typedef struct {
int Frente, Tras;
TipoDado Dados[Max];
} TipoFila;

void CriaFilaCircular(TipoFila *fila);

int FilaCircularVazia(TipoFila fila);

int EnfileiraCircular(TipoFila *fila, TipoDado dado);

int DesenfileiraCircular(TipoFila *fila, TipoDado *dado);

int ConsultaFrenteFilaCircular(TipoFila fila, TipoDado


*dado);

int QuantidadeFilaCircular(TipoFila fila);

#endif /*FILACIRCULAR_H_*/

133
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 134

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

filacircular.c

#include <stdio.h>
#include “filacircular.h”

void CriaFilaCircular(TipoFila *fila) {


fila->Frente = 0;
fila->Tras = 0; // zero e o primeiro indice
}

int FilaCircularVazia(TipoFila fila) {


if (fila.Tras == fila.Frente)
return 1;
else
return 0;
}

int EnfileiraCircular(TipoFila *fila, TipoDado dado) {


if (QuantidadeFilaCircular(*fila) + 1 == Max) {
//fila cheia
printf(“\n\nErro: Fila Cheia!\n”);
return 0;
} else {
fila->Dados[fila->Tras] = dado;

// de Max-1 incrementa p zero


fila->Tras = (fila->Tras + 1) % Max;
return 1;
}
}

134
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 135

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

int DesenfileiraCircular(TipoFila *fila, TipoDado *dado) {


if (FilaCircularVazia(*fila)) { //fila vazia
printf(“\n\nErro: Fila Vazia!\n”);
return 0;
} else {
*dado = fila->Dados[fila->Frente];
/* guarda o dado da Frente */

// de Max-1 incrementa p zero


fila->Frente = (fila->Frente + 1) % Max;
return 1;
}
}

int ConsultaFrenteFilaCircular(TipoFila fila, TipoDado *dado) {


if (FilaCircularVazia(fila)){ //fila vazia
printf(“\n\nErro: Fila Vazia!\n”);
return 0;
} else {
*dado = fila.Dados[fila.Frente];
return 1;
}
}

int QuantidadeFilaCircular(TipoFila fila) {


return (Max - fila.Frente + fila.Tras) % Max;
}

135
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 136

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

aplicacao-filacircular.c

#include <stdio.h>
#include “filacircular.h”

int main(void) {
TipoFila f;
TipoDado d;
int opcao;

CriaFilaCircular(&f);

do {
printf(“\n Operacoes sobre Fila Circular
(Tam. Maximo: %d)”, Max);
printf(“\n\n1 - Enfileirar um dado”);
printf(“\n2 - Desenfileirar um dado”);
printf(“\n3 - Consultar o dado da frente da fila”);
printf(“\n\n4 - Sair”);
__fpurge(stdin);
printf(“\nOpcao -> “);
scanf(“%d”, &opcao);

switch (opcao) {
case 1:
printf(“\nChave: “);
scanf(“%d”, &d.chave);
if (EnfileiraCircular(&f, d))
printf(“Elemento Enfileirado -> %d\n”,
d.chave);
break;
case 2:
if (DesenfileiraCircular(&f, &d))
printf(“Elemento Desenfileirado -> %d\n”,
d.chave);
break;

136
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 137

Laboratório de Tecnologia em Análise e


Estrutura de Dados I Desenvolvimento de Sistemas

case 3:
if (ConsultaFrenteFilaCircular(f, &d))
printf(“Frente -> %d\n”, d.chave);
break;
case 4:
printf(“\n\nSaindo....\n”);
break;
default:
printf(“\n\nErro: Opcao invalida”);

}
} while (opcao != 4);
return 0;
}

137
01_laboratorio_de_estrutura_de_dados_i.qxp 5/8/2008 15:49 Page 138

Tecnologia em Análise e Laboratório de


Desenvolvimento de Sistemas Estrutura de Dados I

138

Você também pode gostar