Vous êtes sur la page 1sur 195

Universidade Catlica de Pelotas Centro Politcnico Cincia da Computao

Estruturas de Dados em C
por

Prof. Dr. Paulo Roberto Gomes Luzzardi


luzzardi@atlas.ucpel.tche.br pluzzardi@gmail.com http://infovis.ucpel.tche.br/luzzardi http://graphs.ucpel.tche.br/luzzardi http://gcg.ucpel.tche.br

Verso 2.02

Referncias Bibliogrficas
CORMEN, et al. Algoritmos - Teoria e Prtica. Rio de Janeiro: Campus, 2002. VELOSO, Paulo e SANTOS, Clsio - Estruturas de Dados - Editora Campus, 4 ed., Rio de Janeiro, 1986. WIRTH, Niklaus. Algoritmos e Estruturas de Dados. Rio de Janeiro: Prentice-Hall do Brasil, 1989. PINTO, Wilson - Introduo ao Desenvolvimento de Algoritmos e Estrutura de Dados, Editora rica, 1994.

Pelotas, 25 de fevereiro de 2009

Sumrio
1. Tipos de Dados 1.1 Conceitos Bsicos 1.2 Tipos Primitivos 1.3 Construo de Tipos (Estruturados ou Complexos) 1.3.1 Strings 1.3.2 Vetor (Agregados Homogneos) 1.3.3 Struct (Estrutura) 1.3.4 Ponteiros (Apontadores) 1.4 Operadores (Aritmticos, Relacionais e Lgicos) 1.4.1 Aritmticos 1.4.2 Relacionais 1.4.3 Lgicos 2. Vetores e Matrizes 2.1 Conceitos Bsicos 3. Listas Lineares 3.1 Listas Genricas 3.2 Tipos de Representaes 3.2.1 Lista Representada por Contigidade Fsica 3.2.2 Lista Representada por Encadeamento 3.2.3 Lista Encadeada com Descritor 3.2.4 Lista Duplamente Encadeada 3.2.5 Listas com disciplinas de Acesso 3.2.5.1 Filas 3.2.5.1.1 Fila com Vetor 3.2.5.1.2 Fila Circular 3.2.5.1.3 Fila com Alocao Dinmica 3.2.5.2 Pilhas 3.2.5.2.1 Pilha com Vetor 3.2.5.2.2 Pilha com Alocao Dinmica 3.2.5.2.3 Analisador de Expresses usando Pilha 3.2.5.3 Deques 3.3 Representao por Contigidade Fsica 3.4 Representao por Encadeamento

4. Arquivos 4.1 Sistema de Arquivo Bufferizado 4.2 Argumentos argc e argv 5. Pesquisa de Dados 5.1 Pesquisa Seqencial 5.2 Pesquisa Binria 5.3 Clculo de Endereo (Hashing) 6. Classificao de Dados (Ordenao) 6.1 6.2 6.3 6.4 Classificao por Fora Bruta Vetor Indireto de Ordenao (Tabela de ndices) Classificao por Encadeamento Mtodos de Classificao Interna 6.4.1 Mtodo por Insero Direta 6.4.2 Mtodo por Troca 6.4.2.1 Mtodo da Bolha (Bubble Sort) 6.4.3 Mtodo por Seleo 6.4.3.1 Mtodo por Seleo Direta

7. rvores 7.1 Conceitos Bsicos 7.2 rvores Binrias 7.3 Representaes 7.3.1 Representao por Contigidade Fsica 7.3.2 Representao por Encadeamento 7.4 Caminhamentos em rvores 7.4.1 Caminhamento Pr-Fixado (Pr-Ordem) 7.4.2 Caminhamento In-Fixado (Central) 7.4.3 Caminhamento Ps-Fixado 7.4.4 Algoritmos recursivos para percorrer rvores Binrias 7.4.4.1 Caminhamento Pr-Fixado (Pr-Ordem) 7.4.4.2 Caminhamento In-Fixado (Central) 7.4.4.3 Caminhamento Ps-Fixado 7.5 rvore de Busca Binria 7.6 rvores AVL 7.6.1 Insero em uma rvore AVL 7.6.2 Remoo em uma rvore AVL

8. Grafos 8.1 Conceitos 8.2 Representao por Lista e Matriz de Adjacncias 8.2.1 Lista de Adjacncias 8.2.2 Matriz de Adjacncias 8.3 Percurso em Amplitude e Percurso em Profundidade 8.4 Determinao do Caminho Mnimo

1. Tipos de Dados
1.1 Conceitos Bsicos Estruturas de Dados
Estuda as principais tcnicas de representao e manipulao de dados na memria principal (Memria de Acesso Randmico, RAM Random Access Memory).

Organizao de Arquivos
Estuda as principais tcnicas de representao e manipulao de dados na memria secundria (Disco).

Conceito

Dados
So as informaes a serem representadas, armazenadas ou manipuladas.

Tipos de Dados
o conjunto de valores que uma constante, ou varivel, ou expresso pode assumir, ou ento a um conjunto de valores que possam ser gerados por uma funo. Na definio de uma varivel, constante, expresso ou funo deve-se definir o Tipo de Dado, por algumas razes: 1) Representar um tipo abstrato de dado (Realidade); 2) Delimitar a faixa de abrangncia (Limites); 3) Definir a quantidade de bytes para armazenamento;
5

4) E as operaes que podem ser efetuadas. Os tipos de dados podem ser: Primitivos ou Estruturados, sendo que os estruturados, so chamados de Complexos.

1.2 Tipos Primitivos


So os tipos de dados que, alm de depender das caractersticas do sistema, dependem do processador e do co-processador. Tipos primitivos da Linguagem de Programao C: CARACTER ( char ch; ) INTEIRO ( int i; ) REAL ( float f; ou double d;)
Tipo Bytes char 1 Int 2 float 4 double 8 void 0 Bits 8 16 32 64 0 Faixa de valores -128 127 -32768 32767 -3.4E-38 3.4E+38 -1.7E-308 1.7E+308 Sem tipo

1.3 Construo de Tipos (Estruturados ou Complexos)


Tipos obtidos atravs de tipos primitivos, podem ser: STRING (Cadeia de Caracteres) ( char *s; ou char s[11]; ) VETOR (Agregados Homogneos) ( int v[10]; ) ESTRUTURA (Agregados Heterogneos) ( struct ) PONTEIRO (Apontadores) ( int *p; )

1.3.1 String (Cadeia de Caracteres)


Tipo de dado que permite que uma varivel possua vrios caracteres. Exemplo: char nome[30]=UCPel; ou char *s=UCPel\n;

1.3.2 Vetor (Agregados Homogneos)


Tipo de dado que permite que uma varivel possua vrios elementos, todos do mesmo tipo. Exemplo: #define MAX 10 float vetor[MAX]; ............. vetor[0] at vetor[9]

1.3.3 Struct (Estrutura)


Tipo de dado que permite que uma varivel possua vrios campos. Os campos podem ser de tipos de dados distintos. Exemplos: #define MAX 50 struct ALUNO { int matricula; char nome[30]; char endereco[40]; } struct ALUNO turma[MAX]; struct DATA { int dia; int mes; int ano; } data; Acesso aos elementos: data.dia, data.mes ou data.ano struct TEMPO { int horas; int minutos; int segundos; } *tempo;

Acesso aos elementos tempo->horas, tempo->minutos ou tempo->segundos


ou

(*tempo).horas, (*tempo).minutos ou (*tempo).segundos

1.3.4 Ponteiros (Apontadores)


um tipo de dado, onde a varivel contm o endereo de outra varivel, ou um endereo de memria. Permite ainda, alocao dinmica de Memria, ou seja, alocao de memria em tempo de execuo do programa. Exemplo: int *p;

Exemplos:
#include <stdio.h> int main(void) { int *p; int n; n = 65; p = &n; printf(Contedo: %d\n,*p); getchar(); }

&n ....... Endereo da varivel n na memria principal (RAM), sendo que o endereo formado de Segmento:OffSet (segmento e deslocamento).
#include <stdio.h> #include <stdlib.h>

int main(void) { int *p; int i,n; printf("Quantos valores: "); scanf("%d",&n); p = (int *) malloc(sizeof(int)*n); if (p == NULL) printf("ERRO FATAL: Falta de Memria"); else { for (i = 0;i < n;i++) p[i] = i; for (i = 0;i < n;i++) printf("Contedo: %d\n",p[i]); free(p); } getchar(); } Exemplo: #include <stdio.h> #include <stdlib.h> int main(void) { int *p; int i,n; printf("Quantos valores: "); scanf("%d",&n); p = (int *) malloc(sizeof(int)*n); if (p == NULL) printf("ERRO FATAL: Falta de Memria"); else { for (i = 1;i <= n;i++) { *p = i; p++; } for (i = 1;i <= n;i++) { p--; printf("Contedo: %d\n",*p); } free(p); } getchar(); 9

Definies
malloc(p) ....................... Aloca dinamicamente memria para o ponteiro "p" free(p) .......................... Desaloca memria ocupada pela varivel "p" NULL ............................. Palavra reservada para ponteiro NULO p ................................... Endereo da memria RAM *p ................................. Contedo do ponteiro &p ................................. Endereo do ponteiro

1.4 Operadores (Aritmticos, Relacionais e Lgicos) 1.4.1 Aritmticos


+ * / % ++ -Adio Subtrao Multiplicao Diviso Resto Inteiro da Diviso Incremento Decremento

1.4.2 Relacionais
> < >= <= == != Maior Menor Maior ou Igual Menor ou Igual Igual Diferente

1.4.3 Lgicos
&& || ! e ou no

10

2. Vetores e Matrizes
Permitem armazenamento de vrios dados na memria RAM ao mesmo instante de tempo e com contigidade fsica, ou seja, uma varivel com possui vrios elementos, igualmente distanciados, ou seja, um ao lado do outro.

2.1 Conceitos Bsicos Vetor: ( uma matriz unidimensional)


#define MAX 7 int vetor[MAX];

Matriz: (Possui mais de uma dimenso)


#define M 3 #define N 4 float matriz[M][N]; ndice: Constante numrica inteira que referencia cada elemento Exemplos: Dada a definio acima: vetor[0]...................... primeiro elemento vetor[MAX-1].............. ltimo elemento m[0][0]...................... primeiro elemento m[M-1][N-1]............... ltimo elemento Entrada de um Vetor for (i = 0;i < MAX;i++) scanf(%d, &vetor[i]); Entrada de uma Matriz Bidimensional for (i = 0;i < M;i++) for (j = 0;j < N;j++) scanf(%f, &matriz[i][j]);

11

Exerccios: 1) Escreva um programa em C que l uma matriz A (6x6) e cria 2 vetores SL e SC de 6 elementos que contenham respectivamente a soma das linhas (SL) e a soma das colunas (SC). Imprimir os vetores SL e SC. 2) Escreva um programa em C que l uma matriz A (12x13) e divide todos os elementos de cada uma das 12 linhas de A pelo valor do maior elemento daquela linha. Imprimir a matriz A modificada. Observao: Considere que a matriz armazena apenas elementos inteiros 3) Escreva um programa em C que insere nmeros inteiros (mximo 10 elementos) em um vetor mantendo-o ordenado. Quando o usurio digitar um ZERO o programa deve imprimir na tela o vetor ordenado.

Operaes sobre os Dados


Criao dos Dados Manuteno dos Dados Insero de um Componente Remoo de um Componente Alterao de um Componente Consulta aos Dados Destruio dos Dados Pesquisa e Classificao

Alocao de Memria (RAM - Random Access Memory) Alocao Esttica de Memria


a forma mais simples de alocao, na qual cada dado tem sua rea reservada, no variando em tamanho ou localizao ao longo da execuo do programa. float f;
// a varivel f ocupa 4 bytes durante toda a execuo do programa

12

Alocao Dinmica de Memria


Nesta forma de alocao, so feitas requisies e liberaes de pores da memria ao longo da execuo do programa. Para isto, so usadas variveis do tipo Ponteiro. int *p;
// a varivel p poder ocupar n bytes a qualquer momento

Clula, Nodo ou N
Espao reservado (alocado) na memria RAM para uma varivel (tipo primitivo ou complexo), ou seja, nmero de bytes gastos para o armazenamento de um dado.

Campo
uma subdiviso de uma clula, ou seja, cada elemento de uma estrutura (struct). No exemplo abaixo, tempo uma clula e horas, minutos e segundos so os campos. struct TEMPO { int horas; int minutos; int segundos; } *tempo;

3. Listas Lineares
3.1 Listas Genricas Conceito
Conjunto de dados que mantm a relao de ordem Linear entre os componentes. composta de elementos (componentes ou ns), os quais podem conter um dado primitivo ou estruturado.

Lista Linear
uma estrutura que permite representar um conjunto de dados de forma a preservar a relao de ordem entre eles.
13

Uma lista linear X um conjunto de nodos (ns) X1, X2, ... Xn, Tais que: 1) Existem n nodos na lista (n >= 0) 2) X1 o primeiro nodo da lista 3) Xn o ltimo nodo da lista 4) Para todo i,j entre 1 e n, se i<j, ento o elemento Xi antecede o elemento Xj 5) Caso i = j-1, Xi o antecessor de Xj e Xj o sucessor de Xi

Observao: Quando n=0, diz-se que a Lista Vazia Exemplos de Listas Lista de clientes de um Banco Lista de Chamada Fichrio

Operaes sobre Listas


1) Percurso Permite utilizar cada um dos elementos de uma lista, de tal forma que: 0 primeiro nodo utilizado o primeiro da lista; Para utilizar o nodo Xj, todos os nodos de X1 at X(j-1) j foram utilizados; ltimo nodo utilizado o ltimo nodo da lista.

14

2) Busca Procura um nodo especfico da lista linear, de tal forma que: nodo identificado por sua posio na lista; nodo identificado pelo seu contedo.

3) Insero Acrescenta um nodo X a uma lista linear, de tal forma que: nodo X ter um sucessor e/ou um antecessor; Aps inserir o nodo X na posio i (i >= 1 e i <= n+1), ele passar a ser i-simo nodo da lista; nmero de elementos (n) acrescido de uma unidade.

4) Retirada (Excluso) Retira um nodo X da lista, de tal forma que: Se Xi o elemento retirado, o seu sucessor passa a ser o sucessor de seu antecessor. X(i+1) passa a ser o sucessor de X(i-1). Se Xi o primeiro nodo, o seu sucessor passa a ser o primeiro, se Xi o ltimo, o seu antecessor passa a ser o ltimo; nmero de elementos (n) decrescido de uma unidade.

Operaes Vlidas sobre Listas Acessar um elemento qualquer da lista; Inserir um novo elemento lista; Concatenar duas listas; Determinar o nmero de elementos da lista; Localizar um elemento da lista com um determinado valor; Excluir um elemento da lista; Alterar um elemento da lista; Criar uma lista;
15

Destruir a lista.

3.2 Tipos de Representaes 3.2.1 Lista Representada por Contigidade Fsica


Os nodos so armazenados em endereos contguos, ou igualmente distanciados um do outro. Os elementos so armazenados na memria um ao lado do outro, levando-se em considerao o tipo de dado, ou seja, a quantidade de bytes. Se o endereo do nodo Xi conhecido, ento o endereo do nodo X(i+1) pode ser determinado.

Os relacionamentos so representados pela disposio fsica dos componentes na memria; A posio na estrutura lgica determina a posio na estrutura fsica.

Observao: Uma lista pode ser implementada atravs de um vetor de m elementos. Ateno: Se n = m a Lista chamada Cheia Observao: Como o nmero de nodos armazenados na lista pode ser modificado durante a execuo do programa, deve-se representar como parte de um vetor de m elementos com n <= m.

16

Representao: A lista X est representada por um vetor V de m elementos.

Componentes de uma Lista


Nmero de nodos da lista (n); Vetor de nodos (v); Tamanho total da lista (m).

#define m 7 typedef float TDADOS; typedef struct { int n; TDADOS v[m]; } TLISTA; TLISTA l;

17

Observao: Considera-se que o primeiro armazenado na primeira posio do vetor. Exemplo: typedef int TDADOS;
#define SUCESSO 1 #define LISTA_CHEIA 2 // ------------------------------------ Cria_Lista void Cria_Lista(TLISTA *x) { x->n = 0; } // ------------------------------------ Inclui_Fim int Inclui_Fim(TLISTA *x, TDADOS no) { if (x->n == m) return(LISTA_CHEIA); else { x->v[x->n] = no; x->n = x->n + 1; return(SUCESSO); } } // ------------------------------------ Inclui_Inicio int Inclui_Inicio(TLISTA *x, TDADOS no) { int i; if (x->n == m) return(LISTA_CHEIA); else { for (i = x->n-1;i >= 0;i--) x->v[i+1] = x->v[i]; x->v[0] = no; x->n = x->n + 1; return(SUCESSO); } }

nodo

da

lista

ser

18

4) Incluir dados em uma lista de nmeros inteiros (mximo 10 elementos), mantendo-a ordenada. Soluo do problema proposto (4):
// Inserir Lista mantendo Ordenada #include <stdio.h> // ---------------------------------------------- Definies #define m 5 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 // ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int n; TDADOS v[m]; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *x); int Inclui_Fim(TLISTA *x, TDADOS dado); int Inclui_Inicio(TLISTA *x, TDADOS dado); int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos); int Verifica_Posicao(TLISTA *x, TDADOS dado); void Exibe_Lista(TLISTA x); void Imprime_Erro(int erro); // ------------------------------------ Programa Principal int main(void) { TLISTA l; TDADOS valor; int erro; Cria_Lista(&l); printf("Valor: "); scanf("%d", &valor); if (valor != 0) { Inclui_Fim(&l,valor); 19

do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { erro = Verifica_Posicao(&l,valor); if (erro) Imprime_Erro(erro); } } while (valor != 0 && erro != LISTA_CHEIA); } Exibe_Lista(l); getchar(); } // ------------------------------------ Cria_Lista void Cria_Lista(TLISTA *x) { x->n = 0; } // ------------------------------------ Inclui_Fim int Inclui_Fim(TLISTA *x, TDADOS dado) { if (x->n == m) return(LISTA_CHEIA); else { x->v[x->n] = dado; x->n = x->n + 1; return(SUCESSO); } } // ------------------------------------ Inclui_Inicio int Inclui_Inicio(TLISTA *x, TDADOS dado) { int i; if (x->n == m) return(LISTA_CHEIA); else { for (i = x->n-1;i >= 0;i--) x->v[i+1] = x->v[i]; x->v[0] = dado; x->n = x->n + 1; 20

return(SUCESSO); } } // ------------------------------------ Inclui_Posicao int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos) { int i; if (x->n == m) return(LISTA_CHEIA); else { for (i = x->n-1;i >= pos;i--) x->v[i+1] = x->v[i]; x->v[pos] = dado; x->n = x->n + 1; return(SUCESSO); } } // ------------------------------------ Verifica_Posicao int Verifica_Posicao(TLISTA *x, TDADOS dado) { int i=0; do { if (dado < x->v[i]) return(Inclui_Posicao(x,dado,i)); i++; } while (i < x->n); return(Inclui_Fim(x,dado)); } // ------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case LISTA_CHEIA: printf("ERRO: Lista Cheia\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } } // ------------------------------------ Exibe_Lista

21

void Exibe_Lista(TLISTA x) { int i; printf("Lista Ordenada: "); for (i = 0;i < x.n;i++) printf("%02d ",x.v[i]); }

5) Incluir dados em uma lista linear de nmeros inteiros (mximo 50) sem repetio. O programa termina quando o dado lido for zero, ento o programa deve imprimir a lista na tela sem repetio. Soluo do problema proposto (5):
// Inserir Lista sem Repeticao #include <stdio.h> // ---------------------------------------------- Definies #define m 5 #define TRUE !0 #define FALSE 0 #define #define #define #define SUCESSO 0 LISTA_CHEIA 1 LISTA_VAZIA 2 DADO_REPETIDO 3

// ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int n; TDADOS v[m]; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *x); int Inclui_Fim(TLISTA *x, TDADOS dado); int Inclui_Inicio(TLISTA *x, TDADOS dado); int Insere_Sem_Repeticao(TLISTA *x, TDADOS dado); void Imprime_Erro(int erro); void Exibe_Lista(TLISTA x); // ------------------------------------ Programa Principal 22

int main(void) { TLISTA l; TDADOS valor; int erro; Cria_Lista(&l); printf("Valor: "); scanf("%d", &valor); if (valor != 0) { Inclui_Fim(&l,valor); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { erro = Insere_Sem_Repeticao(&l,valor); if (erro) Imprime_Erro(erro); } } while (valor != 0 && erro != LISTA_CHEIA); } Exibe_Lista(l); getchar(); } // ------------------------------------ Cria_Lista void Cria_Lista(TLISTA *x) { x->n = 0; } // ------------------------------------ Inclui_Fim int Inclui_Fim(TLISTA *x, TDADOS dado) { if (x->n == m) return(LISTA_CHEIA); else { x->v[x->n] = dado; x->n = x->n + 1; return(SUCESSO); } } // ------------------------------------ Inclui_Inicio 23

int Inclui_Inicio(TLISTA *x, int dado) { int i; if (x->n == m) return(LISTA_CHEIA); else { for (i = x->n-1;i >= 0;i--) x->v[i+1] = x->v[i]; x->v[0] = dado; x->n = x->n + 1; return(SUCESSO); } } // ------------------------------------ Insere_Sem_Repeticao int Insere_Sem_Repeticao(TLISTA *x, TDADOS dado) { int i,achei = FALSE; if (x->n == m) return(LISTA_CHEIA); else { for (i = 0;i < x->n;i++) if (x->v[i] == dado) { achei = TRUE; return(DADO_REPETIDO); } if (!achei) return(Inclui_Fim(x,dado)); } return(SUCESSO); } // ------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case LISTA_CHEIA: printf("ERRO: Lista Cheia\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; case DADO_REPETIDO: printf("ERRO: Dado Repetido\n"); break; 24

} } // ------------------------------------ Exibe_Lista void Exibe_Lista(TLISTA x) { int i; printf("Lista sem Repetio: "); if (x.n != 0) for (i = 0;i < x.n;i++) printf("%02d ",x.v[i]); }

Contigidade Fsica
Uma alternativa para representao por contigidade fsica no iniciar no incio do vetor, isto facilita as inseres.

Observao: As operaes de incluso e excluso de nodos podem optar pela extremidade da lista que ir diminuir (no caso de excluso) ou aumentar (no caso de insero) de comprimento. A escolha dever considerar o caso que produz menor movimentao de elementos. typedef float TDADOS; typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; TLISTA l; Lista vazia

25

incio = -1 fim = -1 Lista cheia incio = 0 fim = m-1 6) Escreva um programa em C que permite a incluso de nmeros inteiros no incio ou no fim da lista linear (mximo 7 elementos). Soluo do problema proposto (6):
// Lista Linear #include <stdio.h> #include <string.h> #include <ctype.h> // ---------------------------------------------- Definies #define m 7 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 // ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *x); int Inclui_Inicio(TLISTA *x, TDADOS dado); int Inclui_Fim(TLISTA *x, TDADOS dado); void Exibe_Lista(TLISTA x); void Imprime_Erro(int erro); // ---------------------------------------------- Programa Principal int main(void) 26

{ TLISTA l; TDADOS valor; int erro; char ch; Cria_Lista(&l); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { printf("[I]ncio ou [F]im ?"); do { ch = toupper(getchar()); } while (!strchr("IF",ch)); switch (ch) { case 'I': erro = Inclui_Inicio(&l,valor); break; case 'F': erro = Inclui_Fim(&l,valor); break; } if (erro) Imprime_Erro(erro); } } while (valor != 0 && erro != LISTA_CHEIA); Exibe_Lista(l); getchar(); } // ---------------------------------------------- Cria_Lista void Cria_Lista(TLISTA *x) { x->inicio = -1; x->fim = -1; } // ---------------------------------------------- Inclui_Inicio int Inclui_Inicio(TLISTA *x, TDADOS dado) { if (x->inicio == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->inicio] = dado; return(SUCESSO); } 27

else if (x->inicio == 0) return(LISTA_CHEIA); else { x->inicio = x->inicio - 1; x->v[x->inicio] = dado; return(SUCESSO); } } // ---------------------------------------------- Inclui_Fim int Inclui_Fim(TLISTA *x, TDADOS dado) { if (x->fim == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->fim] = dado; return(SUCESSO); } else if (x->fim == m-1) return(LISTA_CHEIA); else { x->fim = x->fim + 1; x->v[x->fim] = dado; return(SUCESSO); } } // ---------------------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case LISTA_VAZIA: printf("\nERRO: Lista Vazia"); break; case LISTA_CHEIA: printf("\nERRO: Lista Cheia"); break; } } // ---------------------------------------------- Exibe_Lista void Exibe_Lista(TLISTA x) { int i; 28

printf("\nLista: "); if (x.inicio != -1) for (i = x.inicio;i <= x.fim;i++) printf("%02d ",x.v[i]); else printf("VAZIA"); }

7) Escreva um programa em C que permite a incluso de nmeros inteiros no incio ou no fim da lista linear (mximo 7 elementos) avisando qual lado est cheio. Observao: Note que a lista pode estar cheia num lado e no estar cheia no outro lado. A prxima soluo (7) avisa ao usurio qual lado da lista linear est cheio. Soluo do problema proposto (7):
// Lista Linear no meio do Vetor #include <stdio.h> #include <string.h> #include <ctype.h> // ---------------------------------------------- Definies #define m 7 #define SUCESSO 0 #define LISTA_CHEIA_ESQUERDA 1 #define LISTA_CHEIA_DIREITA 2 // ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *x); int Inclui_Inicio(TLISTA *x, TDADOS dado); int Inclui_Fim(TLISTA *x, TDADOS dado); void Imprime_Erro(int erro); 29

void Exibe_Lista(TLISTA x); // ---------------------------------------------- Programa Principal int main(void) { TLISTA l; TDADOS valor; int erro; char ch; Cria_Lista(&l); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { printf("[I]ncio ou [F]im ?"); do { ch = toupper(getchar()); } while (!strchr("IF",ch)); switch (ch) { case 'I': erro = Inclui_Inicio(&l,valor); break; case 'F': erro = Inclui_Fim(&l,valor); break; } if (erro) Imprime_Erro(erro); } } while (valor != 0); Exibe_Lista(l); getchar(); } // ---------------------------------------------- Cria_Lista void Cria_Lista(TLISTA *x) { x->inicio = -1; x->fim = -1; } // ---------------------------------------------- Inclui_Inicio int Inclui_Inicio(TLISTA *x, TDADOS dado) { if (x->inicio == -1) { 30

x->inicio = m / 2; x->fim = x->inicio; x->v[x->inicio] = dado; return(SUCESSO); } else if (x->inicio == 0) return(LISTA_CHEIA_ESQUERDA); else { x->inicio = x->inicio - 1; x->v[x->inicio] = dado; return(SUCESSO); } } // ---------------------------------------------- Inclui_Fim int Inclui_Fim (TLISTA *x, TDADOS dado) { if (x->fim == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->fim] = dado; return(SUCESSO); } else if (x->fim == m-1) return(LISTA_CHEIA_DIREITA); else { x->fim = x->fim + 1; x->v[x->fim] = dado; return(SUCESSO); } } // ---------------------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case LISTA_CHEIA_ESQUERDA: printf("\nERRO: Lista Cheia na ESQUERDA"); break; case LISTA_CHEIA_DIREITA: printf("\nERRO: Lista Cheia na DIREITA"); break; } }

31

// ---------------------------------------------- Exibe_Lista void Exibe_Lista(TLISTA x) { int i; printf("\nLista: "); if (x.inicio == -1) printf("VAZIA"); else for (i = x.inicio;i <= x.fim;i++) printf("%02d ",x.v[i]); }

8) Escreva um programa em C que permite a incluso de nmeros inteiros em uma lista linear no incio, fim e na posio escolhida pelo usurio Soluo do problema proposto (8):
// Lista Linear meio do vetor #include <stdio.h> #include <string.h> #include <ctype.h> // ---------------------------------------------- Definies #define m 7 #define SUCESSO 0 #define LISTA_CHEIA 1 #define LISTA_VAZIA 2 // ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int inicio; int fim; TDADOS v[m]; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *x); int Inclui_Inicio(TLISTA *x, TDADOS dado); int Inclui_Fim(TLISTA *x, TDADOS dado);

32

int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos); void Exibe_Lista(TLISTA x); void Imprime_Erro(int erro); // ------------------------------------ Programa Principal int main(void) { TLISTA l; TDADOS valor; int erro,pos,inic,fim; char ch; Cria_Lista(&l); do { Exibe_Lista(l); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { printf("[I]ncio, [P]osio ou [F]im ?"); do { ch = toupper(getchar()); } while (!strchr("IFP",ch)); switch (ch) { case 'I': erro = Inclui_Inicio(&l,valor); break; case 'F': erro = Inclui_Fim(&l,valor); break; case 'P': if (l.inicio == -1) inic = 1; else if (l.inicio == 0) inic = 1; else inic = l.inicio +1; if (l.fim == -1) fim = m; else fim = l.fim + 1; printf("\n"); do { printf("Posio [%d..%d]: ",inic,fim); scanf("%d",&pos); } while (!(pos >= inic && pos <= fim)); erro = Inclui_Posicao(&l,valor,pos-1); break; } } if (erro) 33

Imprime_Erro(erro); } while (valor != 0); Exibe_Lista(l); getchar(); } // ------------------------------------ Cria_Lista void Cria_Lista(TLISTA *x) { x->inicio = -1; x->fim = -1; } // ------------------------------------ Inclui_Inicio int Inclui_Inicio(TLISTA *x, TDADOS dado) { if (x->inicio == -1) { x->inicio = m / 2; x->fim = x->inicio; x->v[x->inicio] = dado; return(SUCESSO); } else if (x->inicio == 0) return(LISTA_CHEIA); else { x->inicio = x->inicio - 1; x->v[x->inicio] = dado; return(SUCESSO); } } // ------------------------------------ Inclui_Fim int Inclui_Fim(TLISTA *x, TDADOS dado) { if (x->fim == -1) { x->fim = m / 2; x->inicio = x->fim; x->v[x->fim] = dado; return(SUCESSO); } else if (x->fim == m-1) return(LISTA_CHEIA); else 34

{ x->fim = x->fim + 1; x->v[x->fim] = dado; return(SUCESSO); } } // ----------------------------------- Inclui_Posicao int Inclui_Posicao(TLISTA *x, TDADOS dado, int pos) { int i,erro; if (x->inicio == -1) { x->inicio = pos; x->fim = pos; x->v[x->inicio] = dado; return(SUCESSO); } else if (x->inicio == 0 && x->fim == m-1) return(LISTA_CHEIA); else if (pos == x->inicio-1) { erro = Inclui_Inicio(x,dado); return(erro); } else if (pos == x->fim+1) { erro = Inclui_Fim(x,dado); return(erro); } else { for (i = x->fim;i >= pos;i--) x->v[i+1] = x->v[i]; x->v[pos] = dado; x->fim = x->fim + 1; return(SUCESSO); } } // ----------------------------------- Exibe_Lista void Exibe_Lista(TLISTA x) { int i;

35

printf("\nLista: "); if (x.inicio == -1) printf("VAZIA"); else for (i = x.inicio;i <= x.fim;i++) printf("%02d ",x.v[i]); } // ----------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case LISTA_CHEIA: printf("ERRO: Lista Cheia\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } }

Vantagens e Desvantagens da Representao por Contigidade Fsica Vantagens

A consulta pode ser calculada (acesso randmico aos dados); Facilita a transferncia de dados (rea de memria contgua); Adequada para o armazenamento de estruturas simples.

Desvantagens

O tamanho mximo da lista precisa ser conhecido e alocado antecipadamente, pois a lista alocada estaticamente na memria; Inseres e remoes podem exigir considervel movimentao de dados; Inadequada para o armazenamento de estruturas complexas; Mantm um espao de memria ocioso (no ocupado); Como a lista limitada, devem ser testados os limites.

3.2.2 Lista representada por Encadeamento


Permite Alocao Dinmica de Memria, ou seja, a lista cresce com a execuo do programa. Operaes como insero e remoo so mais simples. Isto feito atravs de variveis do tipo ponteiro, ou seja,

36

um elemento aponta (possui o endereo, posio de memria do prximo elemento) para o prximo.

9) Escreva um programa em C que permite incluir nmeros inteiros em uma lista encadeada. Soluo do problema proposto (9):
// Lista Encadeada #include <stdio.h> #include <stdlib.h> // ------------------------------------ Definies #define SUCESSO #define FALTA_DE_MEMORIA #define LISTA_VAZIA 0 1 2

// ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct nodo { TDADOS dado; struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; } TLISTA; // ------------------------------------ Prototypes void Cria_Lista (TLISTA *l); int Inclui_Lista (TLISTA *l, TDADOS d); int Remove_Primeiro(TLISTA *l); int Conta_Elementos_Lista(TLISTA l); int Remove_Ultimo(TLISTA *l); void Imprime_Erro(int erro);

37

void destroi_Lista(TLISTA *l); // ------------------------------------ Programa Principal int main(void) { TLISTA l; TDADOS d; int n,erro; Cria_Lista(&l); do { printf("Valor: "); scanf("%d",&d); if (d != 0) { erro = Inclui_Lista(&l,d); if (erro) { Imprime_Erro(erro); break; } } } while (d != 0); n = Conta_Elementos_Lista(l); printf("Nmero de Elementos: %d\n",n); Destroi_Lista(&l); getchar(); } // ------------------------------------ Cria_Lista void Cria_Lista (TLISTA *l) { l->primeiro = NULL; } // ------------------------------------ Inclui_Lista int Inclui_Lista (TLISTA *l, TDADOS d) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { if (l->primeiro == NULL) { l->primeiro = p; 38

p->dado = d; p->elo = NULL; } else { p->dado = d; p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO); } } // ------------------------------------ Remove_Primeiro int Remove_Primeiro(TLISTA *l) { TNODO *p; if (l->primeiro == NULL) return(LISTA_VAZIA); else { p = l->primeiro; l->primeiro = p->elo; free(p); return(SUCESSO); } } // ------------------------------------ Conta_elementos int Conta_Elementos_Lista(TLISTA l) { TNODO *p; int n = 0; if (l.primeiro == NULL) return(n); else { p = l.primeiro; while (p != NULL) { n++; p = p->elo; } return(n); } }

39

// ------------------------------------ Remove_Ultimo int Remove_Ultimo(TLISTA *l) { TNODO *p,*q; if (l->primeiro == NULL) return(LISTA_VAZIA); else { q = l->primeiro; p = l->primeiro; while (p->elo != NULL) { q = p; p = p->elo; } if (l->primeiro == q) l->primeiro = NULL; else q->elo = NULL; free(p); return(SUCESSO); } } // ------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memria\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } getchar(); } // ------------------------------------------ Destroi_Lista void Destroi_Lista(TLISTA *l) { TNODO *p; if (l->primeiro != NULL) { p = l->primeiro; while (p != NULL) { 40

l->primeiro = p->elo; free(p); p = l->primeiro; } } }

10) Escrever um programa em C que insere dados em uma lista encadeada, permitindo obter o contedo do ltimo elemento, imprimindo tambm, toda a lista. Soluo do problema proposto (10):
// Lista Encadeada #include <stdio.h> #include <stdlib.h> // ------------------------------------ Definies #define SUCESSO #define FALTA_DE_MEMORIA #define LISTA_VAZIA 0 1 2

// ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct nodo { TDADOS dado; struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; } TLISTA; // ------------------------------------ Prototypes void Cria_Lista (TLISTA *l); int Inclui_Lista (TLISTA *l, TDADOS dado); int Consulta_Ultimo(TLISTA l,TDADOS *dado); int Imprime_Lista(TLISTA l); void Imprime_Erro(int erro); // ------------------------------------ Programa Principal int main(void) {

41

TLISTA l; TDADOS valor; int erro; Cria_Lista(&l); do { printf("Valor: "); scanf("%d",&valor); if (valor != 0) { erro = Inclui_Lista(&l,valor); if (erro) { Imprime_Erro(erro); break; } } } while (valor != 0); erro = Consulta_Ultimo(l,&valor); if (erro == SUCESSO) { printf("ltimo Elemento: %d\n",valor); Imprime_Lista(l); } else Imprime_Erro(erro); getchar(); } // ------------------------------------ Cria_Lista void Cria_Lista (TLISTA *l) { l->primeiro = NULL; } // ------------------------------------ Inclui_Lista int Inclui_Lista (TLISTA *l, TDADOS d) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { if (l->primeiro == NULL) { l->primeiro = p; p->dado = d; 42

p->elo = NULL; } else { p->dado = d; p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO); } } // ------------------------------------ Consulta_Ultimo int Consulta_Ultimo(TLISTA l,TDADOS *dado) { TNODO *p; if (l.primeiro == NULL) return(LISTA_VAZIA); else { p = l.ultimo; *dado = p->dado; return(SUCESSO); } } // ------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memria\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } } // ------------------------------------ Imprime_Lista int Imprime_Lista(TLISTA l) { TNODO *p; if (l.primeiro == NULL) return(LISTA_VAZIA); else { 43

printf("Lista Encadeada: "); p = l.primeiro; while (p != NULL) { printf("%02d ",p->dado); p = p->elo; } return(SUCESSO); } }

11) Escrever um programa em C que permite incluir, excluir e consultar (no incio ou fim) dados inteiros em uma lista encadeada. Em cada operao imprimir a lista. Soluo do problema proposto (11):
// Lista Encadeada #include #include #include #include <stdio.h> <string.h> <ctype.h> <stdlib.h>

// ---------------------------------------------- Definies #define SUCESSO 0 #define FALTA_DE_MEMORIA 1 #define LISTA_VAZIA 2 // ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct nodo { TDADOS dado; struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *l); int Inclui_Lista(TLISTA *l, TDADOS valor); int Exclui_Lista(TLISTA *l); int Consulta_Lista(TLISTA l, TDADOS *valor);

44

void void void void

Imprime_Erro(int erro); Destroi_Lista(TLISTA *l); Exibe_Primeiro(TLISTA l); Exibe_Lista(TLISTA l);

// ------------------------------- Programa Principal int main(void) { TLISTA l; TDADOS valor; int erro; char tecla; Cria_Lista(&l); do { Exibe_Primeiro(l); Exibe_Lista(l); printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]inalizar: "); do { tecla = toupper(getchar()); } while (!strchr("IECF",tecla)); switch (tecla) { case 'I': printf("Valor: "); scanf("%d",&valor); erro = Inclui_Lista(&l,valor); break; case 'E': erro = Exclui_Lista(&l); if (!erro) { printf("Ok, Elemento Excludo"); printf(", tecle <enter> para continuar"); } break; case 'C': erro = Consulta_Lista(l,&valor); if (!erro) printf("Valor Consultado: %d",valor);  break; } if (erro && tecla != 'F') Imprime_Erro(erro); } while (tecla != 'F'); Destroi_Lista(&l); } // ------------------------------- Cria_Lista void Cria_Lista(TLISTA *l) { l->primeiro = NULL; 45

} // ------------------------------- Inclui_Lista int Inclui_Lista(TLISTA *l, TDADOS dado) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; if (l->primeiro == NULL) { l->primeiro = p; p->elo = NULL; } else { p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO); } } // ------------------------------- Exclui_Lista int Exclui_Lista(TLISTA *l) { TNODO *p; if (l->primeiro == NULL) return(LISTA_VAZIA); else { p = l->primeiro; l->primeiro = p->elo; free(p); return(SUCESSO); } } // ------------------------------- Consulta_Lista int Consulta_Lista(TLISTA l, TDADOS *dado) { TNODO *p;

46

if (l.primeiro == NULL) return(LISTA_VAZIA); else { p = l.primeiro; *dado = p->dado; return(SUCESSO); } } // ------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: FALTA DE MEMRIA"); break; case LISTA_VAZIA: printf("ERRO: LISTA VAZIA"); break; } printf(", tecle <enter> para continuar"); } // ----------------------------------------- Destroi_Lista void Destroi_Lista(TLISTA *l) { TNODO *p,*q; if (l->primeiro != NULL) { p = l->primeiro; while (p != NULL) { q = p->elo; free(p); p = q; } } Cria_Lista(l); } // ----------------------------------------- Exibe_Primeiro void Exibe_Primeiro(TLISTA l) { if (l.primeiro != NULL) printf("Primeiro: | %p |",l.primeiro); else printf("Primeiro: | NULL |"); 47

} // ----------------------------------------- Exibe_Lista void Exibe_Lista(TLISTA l) { TNODO *p; printf("Lista Encadeada: "); if (l.primeiro == NULL) printf("LISTA VAZIA"); else { p = l.primeiro; while (p != NULL) { printf("| %02d ",p->dado); p = p->elo; } } }

Vantagens das Listas representadas por Encadeamento Lista cresce indeterminadamente, enquanto houver memria livre (Alocao Dinmica de Memria); As operaes de inserso e remoo de elementos no exige a movimentao dos demais elementos.

Desvantagens das Listas representadas por Encadeamento Determinar o nmero de elementos da lista, pois para tanto, deve-se percorrer toda a lista; Acessar diretamente um determinado elemento pela sua posio, pois s conhecido o primeiro elemento da lista; Acessar o ltimo elemento da lista, pois para acess-lo, deve-se visitar todos os intermedirios.

3.2.3 Lista Encadeada com Descritor


Como foi visto anteriormente, as dificuldades da lista encadeada, descobrir o nmero de elementos e ainda, acessar o ltimo elemento. Estas dificuldades podem ser resolvidas utilizando-se um descritor, da seguinte forma:

48

12) Escrever o mesmo programa em C que insere dados em uma lista encadeada com descritor, permitindo obter o contedo do ltimo elemento diretamente, imprimindo tambm, toda a lista. Soluo do problema proposto (12):
// Lista Encadeada com Descritor #include <stdio.h> #include <stdlib.h> // ------------------------------------ Definies #define SUCESSO #define FALTA_DE_MEMORIA #define LISTA_VAZIA 0 1 2

// ------------------------------------ Tipos de Dados typedef int TDADOS; typedef struct nodo { TDADOS dado; struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; int n; TNODO *ultimo; } TDESCRITOR;

49

// ------------------------------------ Prototypes void Cria_Lista (TDESCRITOR *d); int Inclui_Esquerda (TDESCRITOR *d, TDADOS dado); int Inclui_Direita (TDESCRITOR *d, TDADOS dado); int Consulta_Ultimo(TDESCRITOR d,TDADOS *dado); void Imprime_Lista(TDESCRITOR d); void Imprime_Erro(int erro); // ------------------------------------ Programa Principal int main(void) { TDESCRITOR d; TDADOS dado; char tecla; int erro; Cria_Lista(&d); do { Imprime_Lista(d); printf("\nValor: "); scanf("%d",&dado); if (dado != 0) { printf("[E]squerda ou [D]ireita: "); do { tecla = toupper(getchar()); } while (!strchr("ED",tecla)); switch (tecla) { case 'E': erro = Inclui_Esquerda(&d,dado); break; case 'D': erro = Inclui_Direita(&d,dado); break; } if (erro) { Imprime_Erro(erro); break; } } } while (dado != 0); erro = Consulta_Ultimo(d,&dado); if (erro == SUCESSO) printf("ltimo Elemento: %d\n",dado); else Imprime_Erro(erro); getchar(); }

50

// ------------------------------------ Cria_Lista void Cria_Lista (TDESCRITOR *l) { l->primeiro = NULL; l->n = 0; l->ultimo = NULL; } // ------------------------------------ Inclui_Esquerda int Inclui_Esquerda (TDESCRITOR *d, TDADOS dado) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; p->elo = d->primeiro; d->primeiro = p; if (d->n == 0) d->ultimo = p; (d->n)++; return(SUCESSO); } } // ------------------------------------ Inclui_Direita int Inclui_Direita (TDESCRITOR *d, TDADOS dado) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; p->elo = NULL; if (d->n == 0) d->primeiro = p; else d->ultimo->elo = p; d->ultimo = p; (d->n)++; return(SUCESSO); } 51

} // ------------------------------------ Consulta_Ultimo int Consulta_Ultimo(TDESCRITOR d,TDADOS *dado) { TNODO *p; if (d.primeiro == NULL) return(LISTA_VAZIA); else { p = d.primeiro; while (p->elo != NULL) p = p->elo; *dado = p->dado; return(SUCESSO); } } // ------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memria\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; } } // ------------------------------------ Imprime_Lista void Imprime_Lista(TDESCRITOR l) { TNODO *p; printf("\nLista Encadeada: "); if (l.primeiro == NULL) printf("VAZIA"); else { p = l.primeiro; while (p != NULL) { printf("%02d ",p->dado); p = p->elo; } } 52

13) Escrever um programa em C que permite incluir, excluir e consultar (no incio ou fim) dados inteiros em uma lista encadeada. Em cada operao imprimir a lista. Soluo do problema proposto (13):
// Lista Encadeada com Descritor #include #include #include #include <stdio.h> <string.h> <ctype.h> <stdlib.h>

// ----------------------------------------- Definies #define SUCESSO 0 #define FALTA_DE_MEMORIA 1 #define LISTA_VAZIA 2 // ----------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct nodo { TDADOS dado; struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; int n; TNODO *ultimo; } TLISTA; // ---------------------------------------------- Prototypes void Cria_Lista(TLISTA *l); int Inclui_Inicio(TLISTA *l, TDADOS valor); int Inclui_Fim(TLISTA *l, TDADOS valor); int Exclui_Inicio(TLISTA *l); int Exclui_Fim(TLISTA *l); int Consulta_Inicio(TLISTA l, TDADOS *valor); int Consulta_Fim(TLISTA l, TDADOS *valor); void Imprime_Erro(int erro); void Destroi_Lista(TLISTA *l); void Exibe_Descritor(TLISTA l); void Exibe_Lista(TLISTA l);

53

// ------------------------------- Programa Principal int main(void) { TLISTA l; TDADOS valor; int erro; char tecla1,tecla2; Cria_Lista(&l); do { Exibe_Descritor(l); Exibe_Lista(l); printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]inalizar: "); do { tecla1 = toupper(getchar()); } while (!strchr("IECF",tecla1)); if (tecla1 != 'F') { printf("[I]nicio ou [F]im: "); do { tecla2 = toupper(getchar()); } while (!strchr("IF",tecla2)); switch (tecla1) { case 'I': printf("Valor: "); scanf("%d",&valor); if (tecla2 == 'I') erro = Inclui_Inicio(&l,valor); else erro = Inclui_Fim(&l,valor); break; case 'E': if (tecla2 == 'I') erro = Exclui_Inicio(&l); else erro = Exclui_Fim(&l); if (!erro) printf("Ok, Elemento Excludo"); break; case 'C': if (tecla2 == 'I') erro = Consulta_Inicio(l,&valor); else erro = Consulta_Fim(l,&valor); if (!erro) printf("Valor Consultado: %d",valor); break; } if (erro) Imprime_Erro(erro); } 54

} while (tecla1 != 'F'); Destroi_Lista(&l); } // ------------------------------- Cria_Lista void Cria_Lista(TLISTA *l) { l->primeiro = NULL; l->n = 0; l->ultimo = NULL; } // ------------------------------- Inclui_Inicio int Inclui_Inicio(TLISTA *l, TDADOS dado) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; if (l->n == 0) { l->primeiro = p; l->n = 1; l->ultimo = p; p->elo = NULL; } else { p->elo = l->primeiro; l->primeiro = p; l->n = l->n + 1; } return(SUCESSO); } } // ------------------------------- Inclui_Fim int Inclui_Fim (TLISTA *l, TDADOS dado) { TNODO *p,*q; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); 55

else { p->dado = dado; p->elo = NULL; if (l->n == 0) { l->primeiro = p; l->n = 1; l->ultimo = p; } else { q = l->ultimo; l->ultimo = p; q->elo = p; (l->n)++; } return(SUCESSO); } } // ------------------------------- Exclui_Inicio int Exclui_Inicio(TLISTA *l) { TNODO *p; if (l->n == 0) return(LISTA_VAZIA); else { p = l->primeiro; l->primeiro = p->elo; l->n = l->n - 1; if (l->n == 0) { l->primeiro = NULL; l->ultimo = NULL; } free(p); return(SUCESSO); } } // ------------------------------- Exclui_Fim int Exclui_Fim(TLISTA *l) { TNODO *p,*q;

56

if (l->n == 0) return(LISTA_VAZIA); else { p = l->primeiro; while (p->elo != NULL) { q = p; p = p->elo; } l->ultimo = q; q->elo = NULL; l->n = l->n - 1; if (l->n == 0) { l->primeiro = NULL; l->ultimo = NULL; } free(p); return(SUCESSO); } } // ------------------------------- Consulta_Inicio int Consulta_Inicio(TLISTA l, TDADOS *dado) { TNODO *p; if (l.n == 0) return(LISTA_VAZIA); else { p = l.primeiro; *dado = p->dado; return(SUCESSO); } } // ------------------------------- Consulta_Fim int Consulta_Fim(TLISTA l, TDADOS *dado) { TNODO *p; if (l.n == 0) return(LISTA_VAZIA); else { p = l.ultimo; *dado = p->dado; 57

return(SUCESSO); } } // ------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: FALTA DE MEMRIA"); break; case LISTA_VAZIA: printf("ERRO: LISTA VAZIA"); break; } } // ----------------------------------------- Destroi_Lista void Destroi_Lista(TLISTA *l) { TNODO *p,*q; if (l->n > 0) { p = l->primeiro; while (p != NULL) { q = p->elo; free(p); p = q; } } Cria_Lista(l); } // ----------------------------------------- Exibe_Descritor void Exibe_Descritor(TLISTA l) { if (l.primeiro != NULL && l.ultimo != NULL) printf("Descritor: | %p | %d | %p |",l.primeiro,l.n,l.ultimo); else printf("Descritor: | NULL | 0 | NULL |"); } // ----------------------------------------- Exibe_Lista void Exibe_Lista(TLISTA l) { TNODO *p; 58

printf("Lista Encadeada: "); if (l.n == 0) printf("LISTA VAZIA"); else { p = l.primeiro; while (p != NULL) { printf("| %02d ",p->dado); p = p->elo; } } }

3.2.4 Lista Duplamente Encadeada


Na lista duplamente encadeada, cada elemento possui um elo para o anterior e o posterior, sendo que a lista pode ter ou no descritor. 14) Escrever um programa em C que insere dados em uma lista duplamente encadeada com descritor. Soluo do problema proposto (14):
// Lista Duplamente Encadeada com Descritor #include #include #include #include <stdio.h> <string.h> <ctype.h> <stdlib.h>

// --------------------------------------- Definies #define #define #define #define SUCESSO FALTA_DE_MEMORIA LISTA_VAZIA POSICAO_INVALIDA 0 1 2 3

// --------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct nodo { struct nodo *anterior; TDADOS dado; struct nodo *posterior; } TNODO;

59

typedef struct { TNODO *primeiro; int n; TNODO *ultimo; } TDESCRITOR; // --------------------------------------------- Prototypes void Inicializa_Descritor(TDESCRITOR *d); int Insere_Direita(TDESCRITOR *d, TDADOS dado); int Insere_Esquerda(TDESCRITOR *d, TDADOS dado); void Imprime_Lista_Esquerda(TDESCRITOR d); void Imprime_Lista_Direita(TDESCRITOR d); void Imprime_Erro(int erro); void Exibe_Descritor(TDESCRITOR d); int Insere_Posicao(TDESCRITOR *d, int pos, TDADOS dado); // ------------------------------- Programa Principal int main(void) { TDESCRITOR d; TDADOS valor; int erro,pos; char tecla; Inicializa_Descritor(&d); do { Exibe_Descritor(d); Imprime_Lista_Esquerda(d); Imprime_Lista_Direita(d); printf("\nValor: "); scanf("%d",&valor); if (valor != 0) { printf("Inserir na [E]squerda, [D]ireita ou [P]osio: "); do { tecla = toupper(getchar()); } while (!strchr("EDP",tecla)); switch (tecla) { case 'E': erro = Insere_Esquerda(&d,valor); break; case 'D': erro = Insere_Direita(&d,valor); break; case 'P': printf("\nPosio: "); scanf("%d",&pos); erro = Insere_Posicao(&d,pos,valor); break; } 60

if (erro) Imprime_Erro(erro); } } while (valor != 0); } // ------------------------------- Inicializa_Descritor void Inicializa_Descritor(TDESCRITOR *d) { d->primeiro = NULL; d->n = 0; d->ultimo = NULL; } // ------------------------------- Insere_Direita int Insere_Direita (TDESCRITOR *d, TDADOS dado) { TNODO *p,*q; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; p->posterior = NULL; if (d->n == 0) { d->primeiro = p; d->n = 1; d->ultimo = p; p->anterior = NULL; } else { q = d->ultimo; d->ultimo = p; q->posterior = p; p->anterior = q; (d->n)++; } return(SUCESSO); } } // ------------------------------- Insere_Esquerda int Insere_Esquerda(TDESCRITOR *d, TDADOS dado) { 61

TNODO *p,*q; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->dado = dado; p->anterior = NULL; if (d->n == 0) { d->primeiro = p; d->n = 1; d->ultimo = p; p->posterior = NULL; } else { q = d->primeiro; d->primeiro = p; q->anterior = p; p->posterior = q; (d->n)++; } return(SUCESSO); } } // ------------------------------- Imprime_Lista_Direita void Imprime_Lista_Direita(TDESCRITOR d) { TNODO *p; printf("\nLista pela Direita: "); p = d.ultimo; while (p != NULL) { printf("%02d ",p->dado); p = p->anterior; } } // ------------------------------- Imprime_Lista_Esquerda void Imprime_Lista_Esquerda(TDESCRITOR d) { TNODO *p; printf("\nLista pela Esquerda: "); 62

p = d.primeiro; while (p != NULL) { printf("%02d ",p->dado); p = p->posterior; } } // ------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memria\n"); break; case LISTA_VAZIA: printf("ERRO: Lista Vazia\n"); break; case POSICAO_INVALIDA: printf("ERRO: Posio Invlida\n"); break; } } // ------------------------------- Exibe_Descritor void Exibe_Descritor(TDESCRITOR d) { printf("\nDescritor: %p | %d | %p |",d.primeiro,d.n,d.ultimo); } // ------------------------------- Insere_Posicao int Insere_Posicao(TDESCRITOR *d, int pos, TDADOS dado) { TNODO *p,*q; int i; if (pos < 1 || pos > d->n+1) return(POSICAO_INVALIDA); else if (pos == 1) return(Insere_Esquerda(d,dado)); else if (pos == d->n+1) return(Insere_Direita(d,dado)); else { p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else 63

{ p->dado = dado; q = d->primeiro; i = 1; while (i < pos-1) { q = q->posterior; i++; } p->anterior = q; p->posterior = q->posterior; q->posterior = p; p->posterior->anterior = p; (d->n)++; return(SUCESSO); } } }

64

a) Preencha os campos de elo com os valores adequados para que seja representada a seqncia (A, B, C, D): (sem descritor)

Preencha os campos de elo com os valores adequados para que seja representada a seqncia (A, B, C, D, E, F): (com descritor)

65

66

Vantagens e Desvantagens das Listas Duplamente Encadeadas Vantagens Insero e remoo de componentes sem movimentar os demais; Pode-se ter qualquer quantidade de elementos, limitado pela memria livre, pois cada elemento alocado dinamicamente.

Desvantagens Gerncia de memria mais onerosa, alocao / desalocao para cada elemento; Procedimentos mais complexos; Processamento serial (Acesso Seqencial).

3.2.5 Listas Lineares com Disciplina de Acesso


So tipos especiais de Listas Lineares, onde insero, consulta e excluso so feitas somente nos extremos. Estas listas lineares com disciplina de acesso so: Filas, Pilhas e Deques.

3.2.5.1 Filas
uma Lista Linear na qual as inseres so feitas no fim e as excluses e consultas no incio da fila.

Critrio de Utilizao FIFO - "First In First Out" (primeiro a entrar o primeiro a sair)

Operaes sobre Filas


Cria_Fila(f); Destroi_Fila(f); erro = Insere_ Fila(f, i); erro = Exclui_ Fila (f); erro = Consulta_ Fila (f, j); Cria FILA Vazia Desfaz a FILA Insere o dado "i" no fim da FILA Retira da FILA o primeiro elemento Copia em "j" o primeiro elemento da FILA

67

Erros nas operaes sobre Filas: FILA CHEIA ou FILA VAZIA

15) Escrever um programa em C que insere, exclui e consulta dados (nmeros inteiros) em uma fila. Soluo do problema proposto (15):

3.2.5.1.1 Fila com Vetor


// Fila em Vetor #include <stdio.h> #include <string.h> #include <ctype.h> // -------------------------------- Definies #define m 9 #define SUCESSO 0 #define FILA_CHEIA 1 #define FILA_VAZIA 2 // -------------------------------- Tipos de Dados

68

typedef int TDADOS; typedef struct { int primeiro; int ultimo; TDADOS elem[m]; } FILA; // -------------------------------- Prototypes void Cria_Fila(FILA *f); int Insere_Fila(FILA *f, TDADOS dado); int Exclui_Fila(FILA *f); int Consulta_Fila(FILA f, TDADOS *dado); void Imprime_Erro(int erro); // ----------------------------------- Programa Principal int main(void) { FILA f; TDADOS valor; int erro; char ch; Cria_Fila(&f); do { printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]im?"); do { ch = toupper(getchar()); } while (!strchr("IECF",ch)); switch (ch) { case 'I': printf("\nValor: "); scanf("%d",&valor); erro = Insere_Fila(&f,valor); break; case 'E': erro = Exclui_Fila(&f); break; case 'C': erro = Consulta_Fila(f,&valor); if (erro == SUCESSO) printf("\nPrimeiro da Fila: %d\n",valor); break; } if (erro && ch != 'F') Imprime_Erro(erro); } while (ch != 'F'); } // ------------------------------------ Cria_Fila

69

void Cria_Fila(FILA *f) { f->primeiro = 0; f->ultimo = -1; } // ------------------------------------ Insere_Fila int Insere_Fila(FILA *f, TDADOS dado) { if (f->ultimo == m-1) return(FILA_CHEIA); else { (f->ultimo)++; f->elem[f->ultimo] = dado; return(SUCESSO); } } // -------------------------------- Exclui_Fila int Exclui_Fila(FILA *f) { if (f->ultimo == -1) return(FILA_VAZIA); else { printf("\nExcluido\n"); (f->primeiro)++; if (f->primeiro > f->ultimo) { f->primeiro = 0; f->ultimo = -1; } return(SUCESSO); } } // ------------------------------- Consulta_Fila int Consulta_Fila(FILA f, TDADOS *dado) { if (f.ultimo == -1) return(FILA_VAZIA); else { *dado = f.elem[f.primeiro]; return(SUCESSO); } } 70

// ------------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FILA_CHEIA: printf("\nERRO: Lista Cheia\n"); break; case FILA_VAZIA: printf("\nERRO: Lista Vazia\n"); break; } }

Exemplo: FILA VAZIA

Incluso de: 3, 5, 4, 7, 8 e 6

Excluso dos trs primeiros elementos: 3, 5 e 4

Problema com as Filas A reutilizao da fila depois que alguns elementos foram extrados.

Soluo deste Problema


71

Para reutilizar as vagas dos elementos j extrados, deve-se usar uma Fila Circular.

3.2.5.1.2 Fila Circular

16) Escrever um programa em C que insere, exclui e consulta dados (nmeros inteiros) em uma fila circular. Soluo do problema proposto (16):
// Fila Circular #include <stdio.h> #include <string.h> #include <ctype.h> // -------------------------------- Definies #define m 9 #define SUCESSO 0 #define FILA_CHEIA 1 #define FILA_VAZIA 2 // -------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int primeiro; int ultimo; int tamanho; TDADOS elem[m]; } FILA; // -------------------------------- Prototypes 72

void Cria_Fila_Circular(FILA *f); int Insere_Fila_Circular(FILA *f, TDADOS dado); int Exclui_Fila_Circular(FILA *f); int Consulta_Fila_Circular(FILA f, TDADOS *dado); void Imprime_Erro(int erro); // ----------------------------------- Programa Principal int main(void) { FILA f; TDADOS valor; int erro; char ch; Cria_Fila_Circular(&f); do { printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]im?"); do { ch = toupper(getchar()); } while (!strchr("IECF",ch)); switch (ch) { case 'I': printf("\nValor: "); scanf("%d",&valor); erro = Insere_Fila_Circular(&f,valor); break; case 'E': erro = Exclui_Fila_Circular(&f); break; case 'C': erro = Consulta_Fila_Circular(f,&valor); if (erro == SUCESSO) printf("\nPrimeiro da Fila: %d\n",valor); break; } if (erro && ch != 'F') Imprime_Erro(erro); } while (ch != 'F'); } // ------------------------------------ Cria_Fila_Circular void Cria_Fila_Circular(FILA *f) { f->primeiro = 0; f->ultimo = -1; f->tamanho = 0; } // ------------------------------------ Insere_Fila_Circular

73

int Insere_Fila_Circular(FILA *f, TDADOS dado) { if (f->tamanho == m) return(FILA_CHEIA); else { (f->tamanho)++; f->ultimo = (f->ultimo + 1) % m; f->elem[f->ultimo] = dado; return(SUCESSO); } } // -------------------------------- Exclui_Fila_Circular int Exclui_Fila_Circular(FILA *f) { if (f->tamanho == 0) return(FILA_VAZIA); else { printf("\nExcluido\n"); (f->tamanho)--; f->primeiro = (f->primeiro + 1) % m; return(SUCESSO); } } // ------------------------------- Consulta_Fila_Circular int Consulta_Fila_Circular(FILA f, TDADOS *dado) { if (f.tamanho == 0) return(FILA_VAZIA); else { *dado = f.elem[f.primeiro]; return(SUCESSO); } } // ------------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FILA_CHEIA: printf("\nERRO: Lista Cheia\n"); break; case FILA_VAZIA: printf("\nERRO: Lista Vazia\n"); break; 74

} }

Como calcular a nova posio:

3.2.5.1.3 Fila com Alocao Dinmica


17) Escrever um programa em C que insere, exclui e consulta dados (nmeros inteiros) em uma fila alocada dinamicamente. Soluo do problema proposto (17):
// Fila Dinamica #include #include #include #include <stdio.h> <string.h> <ctype.h> <stdlib.h>

// -------------------------------- Definies #define SUCESSO 0 #define FILA_VAZIA 1 #define FALTA_DE_MEMORIA 2 // -------------------------------- Tipos de Dados

75

typedef int TDADOS; typedef struct nodo { TDADOS info; struct nodo *seg; } TNODO; typedef struct { TNODO *primeiro; int tamanho; TNODO *ultimo; } TFILA; // ------------------------------------ Prototypes void Cria_Fila(TFILA *f); int Inserir_Fila(TFILA *f, TDADOS dado); int Excluir_Fila (TFILA *f); int Consultar_Fila (TFILA f, TDADOS *dado); void Destroi_Fila(TFILA *f); void Imprime_Erro(int erro); // ------------------------------------ Programa Principal int main(void) { TFILA f; TDADOS valor; int erro; char tecla; Cria_Fila(&f); do { printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]im?"); do { tecla = toupper(getchar()); } while (!strchr("IECF",tecla)); switch (tecla) { case 'I': printf("\nValor: "); scanf("%d",&valor); erro = Inserir_Fila(&f,valor); break; case 'E': erro = Excluir_Fila(&f); if (erro) Imprime_Erro(erro); else printf("\nElemento Excluido\n"); break; case 'C': erro = Consultar_Fila(f,&valor); if (erro) 76

Imprime_Erro(erro); else printf("\nValor: %d\n",valor); break; } } while (tecla != 'F'); Destroi_Fila(&f); } // ---------------------------------------------- Cria_Fila void Cria_Fila(TFILA *f) { f->primeiro = NULL; f->tamanho = 0; f->ultimo = NULL; } // ---------------------------------------------- Inserir_Fila int Inserir_Fila(TFILA *f, TDADOS dado) { TNODO *t; t = (TNODO *) malloc(sizeof(TNODO)); if (t == NULL) return(FALTA_DE_MEMORIA); else { t->info = dado; t->seg = NULL; f->tamanho = f->tamanho + 1; if (f->ultimo != NULL) f->ultimo->seg = t; f->ultimo = t; if (f->primeiro == NULL) f->primeiro = t; return(SUCESSO); } } // ---------------------------------------------- Excluir_Fila int Excluir_Fila(TFILA *f) { TNODO *t; if (f->primeiro == NULL) return(FILA_VAZIA); else { 77

t = f->primeiro; f->tamanho = f->tamanho - 1; f->primeiro = t->seg; free(t); if (f->primeiro == NULL) { f->ultimo = NULL; return(FILA_VAZIA); } } return(SUCESSO); } // ---------------------------------------------- Consultar_Fila int Consultar_Fila (TFILA f, TDADOS *dado) { if (f.primeiro == NULL) return(FILA_VAZIA); else *dado = f.primeiro->info; return(SUCESSO); } // ---------------------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FILA_VAZIA: printf("\nERRO: Fila Vazia\n"); break; case FALTA_DE_MEMORIA: printf("\nERRO: Falta de Memria\n"); break; } } // ---------------------------------------------- Destroi_Fila void Destroi_Fila(TFILA *f) { while (f->tamanho != 0) Excluir_Fila(f); }

78

3.2.5.2 Pilhas
uma Lista Linear na qual as inseres, excluses e consultas so feitas em um mesmo extremo (TOPO).

Critrio de Utilizao
LIFO - "Last In First Out" (ltimo a entrar o primeiro a sair)

Operaes sobre Pilhas


Cria_Pilha(p); Destroi_Pilha(p); erro = Push(p, i); erro = Pop(p, i); erro = Consulta_Pilha(p,j); Cria pilha Vazia Desfaz a pilha Empilha o dado "i" no fim da PILHA Desempilha o primeiro elemento Copia em "j" o primeiro elemento

Identificadores da Pilha
B(p) T(p) L(p) Base da PILHA Topo da PILHA Limite da PILHA

3.2.5.2.1 Pilha com Vetor

18) Escreva um programa em C que insere (Push), exclui (Pop) e consulta dados (nmeros inteiros) em uma Pilha alocada estaticamente.

79

Soluo do problema proposto (18):


// Pilha com Vetor #include <stdio.h> #include <string.h> #include <ctype.h> // -------------------------------- Definies #define m 7 #define SUCESSO 0 #define PILHA_CHEIA 1 #define PILHA_VAZIA 2 // -------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int topo; TDADOS elem[m]; } TPILHA; // -------------------------------- Prototypes void Cria_Pilha(TPILHA *p); int Push(TPILHA *p, TDADOS dado); int Pop(TPILHA *p, TDADOS *dado); int Consulta_Pilha(TPILHA p, TDADOS *dado); void Imprime_Erro(int erro); // -------------------------------- Programa Principal int main(void) { TPILHA p; char tecla; TDADOS valor; int erro; Cria_Pilha(&p); do { printf("[P]ush, p[O]p, [C]onsultar ou [F]im? "); do { tecla = toupper(getchar()); } while (!strchr("POCF",tecla)); switch (tecla) { case 'P': printf("\nValor: ");

80

scanf("%d",&valor); erro = Push(&p,valor); if (erro) Imprime_Erro(erro); break; case 'O': erro = Pop(&p,&valor); if (erro) Imprime_Erro(erro); else printf("\nValor: %d\n",valor); break; case 'C': erro = Consulta_Pilha(p,&valor); if (erro) Imprime_Erro(erro); else printf("\nValor: %d\n",valor); break; } } while (tecla != 'F'); } // ---------------------------------------------- Cria_Pilha void Cria_Pilha(TPILHA *p) { p->topo = -1; } // ---------------------------------------------- Push int Push(TPILHA *p, TDADOS dado) { if (p->topo == m-1) return(PILHA_CHEIA); else { p->topo = p->topo + 1; p->elem[p->topo] = dado; return(SUCESSO); } } // ---------------------------------------------- Pop int Pop(TPILHA *p, TDADOS *dado) { if (p->topo == -1) return(PILHA_VAZIA); else { *dado = p->elem[p->topo]; 81

p->topo = p->topo - 1; return(SUCESSO); } } // ---------------------------------------------- Consulta_Pilha int Consulta_Pilha(TPILHA p, TDADOS *dado) { if (p.topo == -1) return(PILHA_VAZIA); else { *dado = p.elem[p.topo]; return(SUCESSO); } } // ---------------------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case PILHA_CHEIA: printf("\nERRO: Pilha Cheia\n"); break; case PILHA_VAZIA: printf("\nERRO: Pilha Vazia\n"); break; } }

19) Escreva um programa em C que simula uma Torre de Hanoi. Soluo do problema proposto (19):
// Torre de Hanoi #include #include #include #include <stdio.h> <conio.h> // Turbo C++ 1.01 ou Turbo C 2.01 <string.h> <ctype.h>

// ---------------------------------------------- Definies #define m 3 #define #define #define #define SUCESSO 0 PILHA_CHEIA 1 PILHA_VAZIA 2 MOVIMENTO_INVALIDO 3 82

// ---------------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int topo; TDADOS elem[m]; } TPILHA; // ---------------------------------------------- Prototypes void Cria_Pilha(TPILHA *p); int Push(TPILHA *p, TDADOS dado); int Pop(TPILHA *p, TDADOS *dado); int Consulta_Pilha(TPILHA p, TDADOS *dado); void Lista_Pilhas(TPILHA p1, TPILHA p2, TPILHA p3); void Lista_Pilha(TPILHA p1, int col); void Imprime_Erro(int erro); // ---------------------------------------------- Programa Principal int main(void) { TPILHA p1,p2,p3; TDADOS valor,v2; int erro,pilha; char tecla1,tecla2; clrscr(); Cria_Pilha(&p1); Cria_Pilha(&p2); Cria_Pilha(&p3); Push(&p1,30); Push(&p1,20); Push(&p1,10); Lista_Pilhas(p1,p2,p3); do { gotoxy(1,6); printf("\n De: p[1], p[2], p[3] ou [F]im? "); do { tecla1 = toupper(getchar()); } while (!strchr("123F",tecla1)); if (tecla1 != 'F') { gotoxy(1,7); printf("\nPara: p[1], p[2], p[3] ou [F]im? "); do { tecla2 = toupper(getchar()); } while (!strchr("123F",tecla2)); switch (tecla1) 83

{ case '1': erro = Pop(&p1,&valor); pilha=1; break; case '2': erro = Pop(&p2,&valor); pilha=2; break; case '3': erro = Pop(&p3,&valor); pilha=3; break; } switch (tecla2) { case '1': if (!erro) { erro = Consulta_Pilha(p1,&v2); if (!erro && valor > v2) Imprime_Erro(MOVIMENTO_INVALIDO); if (erro || valor < v2) Push(&p1,valor); else switch (pilha) { case 1: Push(&p1,valor); break; case 2: Push(&p2,valor); break; case 3: Push(&p3,valor); break; } } break; case '2': if (!erro) { erro = Consulta_Pilha(p2,&v2); if (!erro && valor > v2) Imprime_Erro(MOVIMENTO_INVALIDO); if (erro || valor < v2) Push(&p2,valor); else switch (pilha) { case 1: Push(&p1,valor); break; case 2: Push(&p2,valor); break; case 3: Push(&p3,valor); break; } } break; 84

case '3': if (!erro) { erro = Consulta_Pilha(p3,&v2); if (!erro && valor > v2) Imprime_Erro(MOVIMENTO_INVALIDO); if (erro || valor < v2) Push(&p3,valor); else switch (pilha) { case 1: Push(&p1,valor); break; case 2: Push(&p2,valor); break; case 3: Push(&p3,valor); break; } } break; } Lista_Pilhas(p1,p2,p3); if (p2.topo == 2 || p3.topo == 2) { gotoxy(1,10); textcolor(LIGHTRED); printf("Game Over, Congratulations ..."); getchar(); break; } } } while (tecla1 != 'F' && tecla2 != 'F'); } // ---------------------------------------------- Cria_Pilha void Cria_Pilha(TPILHA *p) { p->topo = -1; } // ---------------------------------------------- Push int Push(TPILHA *p, TDADOS dado) { if (p->topo == m-1) return(PILHA_CHEIA); else { p->topo = p->topo + 1; p->elem[p->topo] = dado; return(SUCESSO); 85

} } // ---------------------------------------------- Pop int Pop(TPILHA *p, TDADOS *dado) { if (p->topo == -1) return(PILHA_VAZIA); else { *dado = p->elem[p->topo]; p->topo = p->topo - 1; return(SUCESSO); } } // ---------------------------------------------- Consulta_Pilha int Consulta_Pilha(TPILHA p, TDADOS *dado) { if (p.topo == -1) return(PILHA_VAZIA); else { *dado = p.elem[p.topo]; return(SUCESSO); } } // --------------------------------- Lista_Pilhas void Lista_Pilhas(TPILHA p1, TPILHA p2, TPILHA p3) { gotoxy(1,1); printf(" -- -- --"); gotoxy(1,2); printf(" -- -- --"); gotoxy(1,3); printf(" -- -- --"); gotoxy(1,4); printf("-------------"); gotoxy(1,5); printf(" p1 p2 p3"); Lista_Pilha(p1,2); Lista_Pilha(p2,6); Lista_Pilha(p3,10); } // --------------------------------- Lista_Pilha

86

void Lista_Pilha(TPILHA p, int col) { int i,l=3; if (p.topo != -1) for (i = 0;i <= p.topo;i++) { gotoxy(col,l); printf("%02d",p.elem[i]); l--; } } // --------------------------------- Imprime_Erro void Imprime_Erro(int erro) { gotoxy(1,10); switch (erro) { case PILHA_CHEIA: printf("Erro: PILHA CHEIA"); break; case PILHA_VAZIA: printf("Erro: PILHA VAZIA"); break; case MOVIMENTO_INVALIDO: printf("Erro: MOVIMENTO INVLIDO"); break; } getchar(); gotoxy(1,10); delline(); }

3.2.5.2.2 Pilha com Alocao Dinmica

20) Escreva um programa em C que inclui, exclui e consulta dados em uma Pilha Encadeada.

87

Soluo do problema proposto (20):


// --------------------------------------- Pilha Encadeada #include #include #include #include <stdio.h> <string.h> <ctype.h> <stdlib.h>

// ------------------------------------- Definies #define SUCESSO 0 #define FALTA_DE_MEMORIA #define PILHA_VAZIA 2 1

// -------------------------------------- Tipos de Dados typedef int TDADOS; typedef struct nodo { TDADOS info; struct nodo *seg; } TNODO; typedef struct { TNODO *topo; } TPILHA; // -------------------------------------------- Prototypes void Cria_Pilha(TPILHA *p); int Push(TPILHA *p, TDADOS dado); int Pop(TPILHA *p, TDADOS *dado); int Consulta_Pilha(TPILHA p, TDADOS *dado); void Imprime_Erro(int erro); void Exibe_Pilha(TPILHA p); // -------------------------------------------- Programa Principal int main(void) { TPILHA p; TDADOS valor; char tecla; int erro; Cria_Pilha(&p); do { Exibe_Pilha(p);

88

printf("[P]ush, p[O]p, [C]onsultar ou [F]im?"); do { tecla = toupper(getchar()); } while (!strchr("POCF",tecla)); switch (tecla) { case 'P': printf("Valor a ser Empilhado: "); scanf("%d",&valor); erro = Push(&p,valor); if (erro) Imprime_Erro(erro); break; case 'O': erro = Pop(&p,&valor); if (erro) Imprime_Erro(erro); else printf("Valor Desempilhado: %d, tecle algo",valor); break; case 'C': erro = Consulta_Pilha(p,&valor); if (erro) Imprime_Erro(erro); else printf("Topo: %d, tecle algo",valor); break; } } while (tecla != 'F'); } // ---------------------------------------------- Cria_Pilha void Cria_Pilha(TPILHA *p) { p->topo = NULL; } // ---------------------------------------------- Push int Push(TPILHA *p, TDADOS dado) { TNODO *t; t = (TNODO *) malloc(sizeof(TNODO)); if (t == NULL) return(FALTA_DE_MEMORIA); else { t->info = dado; t->seg = p->topo; p->topo = t; return(SUCESSO); } 89

} // ---------------------------------------------- Pop int Pop(TPILHA *p, TDADOS *dado) { TNODO *t; if (p->topo == NULL) return(PILHA_VAZIA); else { t = p->topo; *dado = t->info; p->topo = t->seg; free(t); return(SUCESSO); } } // ---------------------------------------------- Consulta_Pilha int Consulta_Pilha(TPILHA p, TDADOS *dado) { TNODO *t; if (p.topo == NULL) return(PILHA_VAZIA); else { t = p.topo; *dado = t->info; return(SUCESSO); } } // ---------------------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case FALTA_DE_MEMORIA: printf("ERRO: Falta de Memria"); break; case PILHA_VAZIA: printf("ERRO: Pilha Vazia"); break; } } // ------------------------------------------------- Exibe_Pilha

90

void Exibe_Pilha(TPILHA p) { TNODO *t; printf("Pilha: "); if (p.topo == NULL) printf("VAZIA"); else { t = p.topo; while (t != NULL) { printf("%02d ",t->info); t = t->seg; } } }

3.2.5.2.2 Analisador de Expresses usando Pilhas


21) Criar um Analisador de Expresses utilizando Pilhas. Exemplo: (3 * (4 + 5))

Dicas: 1. 2. 3. 4. 5. 6. Crie duas PILHAS (nmeros e operandos) "(" no faa nada Nmero (Push pilha 2) empilhe na pilha de nmeros Operando (Push pilha 1) empilhe na pilha de operandos ")" (Pop pilha 2, Pop pilha 2 e Pop pilha 1) execute a operao At que i = e[0]

Valores Vlidos: Nmeros: 0 1 2 3 4 5 6 7 8 9 (Nmeros Inteiros Positivos) Operandos: + - * /

91

Soluo do Trabalho Proposto (21):


// -------------------------------- Analisador de Expresses #include <stdio.h> #include <string.h> #include <ctype.h> // -------------------------------- Definies #define m 50 #define SUCESSO 0 #define PILHA_CHEIA 1 #define PILHA_VAZIA 2 #define TRUE !0 #define FALSE 0 // -------------------------------- Tipos de Dados typedef int TDADOS; typedef struct { int topo; TDADOS elem[m]; } TPILHA; // -------------------------------- Prototypes

92

void Cria_Pilha(TPILHA *p); int Push(TPILHA *p, TDADOS dado); int Pop(TPILHA *p, TDADOS *dado); int Consulta_Pilha(TPILHA p, TDADOS *dado); void Imprime_Erro(int erro); int Codifica(char ch, TDADOS *valor,TDADOS *op); int Testa_Expressao(char *s); int Calcula(int v1, int v2, char op); // -------------------------------- Programa Principal int main(void) { TPILHA p1,p2; char s[256]; int n,i,tipo,erro; TDADOS valor,v1,v2,operador,resposta; printf("Analisador de Expresses\n"); printf("Expresso: "); gets(s); n = strlen(s); if (n > m) printf("ERRO: Expresso muito Longa"); else if (Testa_Expressao(s)) { Cria_Pilha(&p1); Cria_Pilha(&p2); for (i = 0;i < n;i++) { tipo = Codifica(s[i],&valor,&operador); switch (tipo) { case 1: erro = Push(&p1,valor); break; case 2: erro = Push(&p2,operador); break; case 3: erro = Pop(&p1,&v2); erro = Pop(&p1,&v1); erro = Pop(&p2,&operador); resposta = Calcula(v1,v2,operador); erro = Push(&p1,resposta); break; } } erro = Pop(&p1,&resposta); if (erro) Imprime_Erro(erro); else printf("Resposta: %d",resposta); 93

} else { printf("Erro: Expresso Invlida"); } getchar(); } // ---------------------------------------------- Codifica int Codifica(char ch, TDADOS *valor, TDADOS *op) { int codifica = 4; if (ch >= '0' && ch <= '9') { codifica = 1; *valor = ch - 48; } if (strchr("+- ",ch)) { codifica = 2; *op = ch; } if (ch == ')') codifica = 3; return(codifica); } // -------------------------------------------- Testa_Expressao int Testa_Expressao(char *s) { int i,n,abre=0,fecha=0; n = strlen(s); for (i = 0;i < n;i++) if (s[i] == '(') abre++; else if (s[i] == ')') fecha++; if (abre == fecha) return(TRUE); else return(FALSE); } // ------------------------------------------ Calcula int Calcula(int v1, int v2, char op) 94

{ switch (op) { case '+': return(v1 + v2); case '-': return(v1 - v2); case '*': return(v1 * v2); case '/': return(v1 / v2); } return(0); } // ---------------------------------------------- Cria_Pilha void Cria_Pilha(TPILHA *p) { p->topo = -1; } // ---------------------------------------------- Push int Push(TPILHA *p, TDADOS dado) { if (p->topo == m-1) return(PILHA_CHEIA); else { p->topo = p->topo + 1; p->elem[p->topo] = dado; return(SUCESSO); } } // ---------------------------------------------- Pop int Pop(TPILHA *p, TDADOS *dado) { if (p->topo == -1) return(PILHA_VAZIA); else { *dado = p->elem[p->topo]; p->topo = p->topo - 1; return(SUCESSO); } } // ---------------------------------------------- Consulta_Pilha int Consulta_Pilha(TPILHA p, TDADOS *dado) { if (p.topo == -1) 95

return(PILHA_VAZIA); else { *dado = p.elem[p.topo]; return(SUCESSO); } } // ---------------------------------------------- Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case PILHA_CHEIA: printf("\nERRO: Pilha Cheia\n"); break; case PILHA_VAZIA: printf("\nERRO: Pilha Vazia\n"); break; } }

3.2.5.3 Deque (Double-Ended QUEue)


uma fila de duas extremidades. As inseres, consultas e retiradas so permitidas nas duas extremidades.

Deque de Entrada Restrita


A insero s pode ser efetuada ou no incio ou no final da lista.

Deque de Sada Restrita


A retirada s pode ser efetuada ou no incio ou no final da lista. Condio Inicial: Esquerda (Esq) e Direita (Dir) no meio do vetor Esq = (m DIV 2 + 1 Dir = (m DIV 2) + 1

96

Deque Vazio Esq = -1 Dir = -1 Deque Cheio Esq = 0 Dir = m-1 Clculo do Nmero de Elementos do Deque nmero_de_elementos = Dir - Esq + 1; 22) Escreva um programa em C que inclui, exclui e consulta dados em um Deque. Soluo do problema proposto (22):
// -------------------------------------------------- Deque #include <stdio.h> #include <string.h> #include <ctype.h> // -------------------------------------------------- Definies #define m 9 #define #define #define #define SUCESSO 0 DEQUE_ESQUERDO_CHEIO 1 DEQUE_DIREITO_CHEIO 2 DEQUE_VAZIO 3

// ------------------------------------------------- Tipos de Dados

97

typedef int TDADOS; typedef struct { int esq; int dir; TDADOS v[m]; } TDEQUE; // ------------------------------------ Prototypes void Cria_Deque(TDEQUE *d); int Inclui_Esquerda(TDEQUE *d, TDADOS dado); int Inclui_Direita(TDEQUE *d, TDADOS dado); int Exclui_Esquerda(TDEQUE *d, TDADOS *dado); int Exclui_Direita(TDEQUE *d, TDADOS *dado); void Exibe_Deque(TDEQUE d); void Imprime_Erro(int erro); // ------------------------------------ Programa Principal int main(void) { TDEQUE d; TDADOS valor; char ch,op; int erro; Cria_Deque(&d); do { Exibe_Deque(d); printf("[I]nclui, [E]xclui, [C]onsulta ou [F]im: "); do { op = toupper(getchar()); } while (!strchr("IECF",op)); if (strchr("'IEC",op)) { printf("[E]squerda ou [D]ireita: "); do { ch = toupper(getchar()); } while (!strchr("ED",ch)); switch (op) { case 'I': printf("Valor: "); scanf("%d",&valor); if (valor != 0) switch (ch) { case 'E': erro = Inclui_Esquerda(&d,valor); break; case 'D': erro = Inclui_Direita(&d,valor); break; 98

} break; case 'E': switch (ch) { case 'E': erro = Exclui_Esquerda(&d,&valor); break; case 'D': erro = Exclui_Direita(&d,&valor); break; } if (!erro) printf("Valor Excludo: %d",valor); break; case 'C': switch (ch) { case 'E': erro = Consulta_Esquerda(d,&valor); break; case 'D': erro = Consulta_Direita(d,&valor); break; } if (!erro) { printf("Valor Consultado: %d",valor); printf(", tecle <ENTER> para continuar"); getchar(); } break; } if (erro) Imprime_Erro(erro); } } while (op != 'F'); } // ------------------------------------ Cria_Deque void Cria_Deque(TDEQUE *d) { d->esq = -1; d->dir = -1; } // ------------------------------------ Inclui_Esquerda int Inclui_Esquerda(TDEQUE *d, TDADOS dado) { if (d->esq == 0) return(DEQUE_ESQUERDO_CHEIO); else { if (d->esq == -1) { 99

d->esq = m / 2; d->dir = d->esq; } else d->esq = d->esq - 1; d->v[d->esq] = dado; return(SUCESSO); } } // ------------------------------------ Inclui_Direita int Inclui_Direita(TDEQUE *d, TDADOS dado) { if (d->dir == m-1) return(DEQUE_DIREITO_CHEIO); else { if (d->dir == -1) { d->dir = m / 2; d->esq = d->dir; } else d->dir = d->dir + 1; d->v[d->dir] = dado; return(SUCESSO); } } // ------------------------------------ Exclui_Esquerda int Exclui_Esquerda(TDEQUE *d, TDADOS *dado) { if (d->esq == -1) return(DEQUE_VAZIO); else { *dado = d->v[d->esq]; d->esq = d->esq + 1; if (d->esq > d->dir) Cria_Deque(d); return(SUCESSO); } } // ------------------------------------ Exclui_Direita int Exclui_Direita(TDEQUE *d, TDADOS *dado) { if (d->dir == -1) 100

return(DEQUE_VAZIO); else { *dado = d->v[d->dir]; d->dir = d->dir - 1; if (d->dir < d->esq) Cria_Deque(d); return(SUCESSO); } } // ------------------------------------ Consulta_Esquerda int Consulta_Esquerda(TDEQUE d, TDADOS *dado) { if (d.esq == -1) return(DEQUE_VAZIO); else { *dado = d.v[d.esq]; return(SUCESSO); } } // ------------------------------------ Consulta_Direita int Consulta_Direita(TDEQUE d, TDADOS *dado) { if (d.dir == -1) return(DEQUE_VAZIO); else { *dado = d.v[d.dir]; return(SUCESSO); } } // ------------------------------------ Exibe_Deque void Exibe_Deque(TDEQUE d) { int i; printf("Deque: "); if (d.esq == -1) printf("VAZIO"); else for (i = d.esq;i <= d.dir;i++) printf("%02d ",d.v[i]); }

101

// ------------------------------------ Imprime_Erro void Imprime_Erro(int erro) { switch (erro) { case DEQUE_ESQUERDO_CHEIO: printf("ERRO: Deque Cheio Esquerda"); break; case DEQUE_DIREITO_CHEIO: printf("ERRO: Deque Cheio Direita"); break; case DEQUE_VAZIO: printf("ERRO: Deque Vazio"); break; } printf(", tecle <ENTER> para continuar"); getchar(); }

102

4. Arquivos
Os arquivos permitem armazenar dados em disco, ou seja, na memria secundria, permitindo desta forma, que as informaes no sejam perdidas quando o computador desligado. Os arquivos so formados por registros. Cada registro possui uma chave de acesso, ou seja, um ndice que diferencia um registro do outro e que permite localiz-lo. Os registros so compostos de campos. Os campos podem ser de qualquer tipo, permitindo que dados e estruturas de dados sejam armazenados. Tais dados podem ser: inteiros, reais, caracteres, strings, estruturas, etc. Os arquivos podem ser de dois tipos bsicos: texto ou binrio. Os arquivos tipo texto so formados por linhas de caracteres finalizados pelo caracter \n. Os arquivos binrios permitem armazenamento de qualquer tipo de dado. Em C, existe um tipo de dado pr-definido chamado FILE (definido em stdio.h) que permite definir um ponteiro que aponta para um arquivo, ou seja, aponta para uma fila de bytes.

Exemplo: #include <stdio.h> FILE *fp; // onde fp significa File Pointer

Observao: Note que o nome do ponteiro do arquivo pode ter qualquer nome (identificador) vlido em C, normalmente ele chamado fp (File Pointer).

103

Em C existem dois tipos de sistemas de arquivos: bufferizado e no-bufferizado.

4.1 Sistema de Arquivo Bufferizado


A ligao existente entre o sistema de entrada e sada bufferizado e um arquivo em C um ponteiro que aponta para o arquivo. O ponteiro do arquivo identifica um determinado arquivo em disco e utilizado pela fila associada a ele para direcionar cada uma das funes de entrada e sada bufferizada para o lugar em que elas operam. Um ponteiro de arquivo uma varivel ponteiro do tipo FILE *. O tipo de dado FILE pr-definido em stdio.h. Exemplo: #include <stdio.h> int main(void) { FILE *fp; Funo: fopen A funo fopen (file open) permite abrir (criar ou anexar) um arquivo ligando-o a uma fila de bytes. Sintaxe: FILE *fopen (char *nome_arquivo, char *modo); Prototype: stdio.h nome_arquivo: Deve ser uma string que contenha: "drive:\path\nome_do_arquivo" modo: uma string que contm as caractersticas desejadas (veja tabela abaixo). Observao: t (arquivo texto) e b (arquivo binrio) Modo de abertura de arquivos
Modo r w a rb wb Significado Abre um arquivo-texto para leitura Cria um arquivo-texto para gravao Anexa a um arquivo-texto Abre um arquivo binrio para leitura Cria um arquivo binrio para gravao

104

ab r+ w+ a+ r+b Modo w+b a+b rt wt at r+t w+t a+t

Anexa a um arquivo binrio Abre um arquivo-texto para leitura/gravao Cria um arquivo-texto para leitura/gravao Abre ou cria um arquivo-texto para leitura/gravao Abre um arquivo binrio para leitura/gravao Significado Cria um arquivo binrio para leitura/gravao Abre um arquivo binrio para leitura/gravao Abre um arquivo texto para leitura Cria um arquivo texto para gravao Anexa a um arquivo texto Abre um arquivo-texto para leitura/gravao Cria um arquivo-texto para leitura/gravao Abre ou cria um arquivo-texto para leitura/gravao

Observao: Se ocorrer erro na abertura de um arquivo, fopen devolver um ponteiro nulo, ou seja, se (fp == NULL) erro. Exemplos: #include <stdio.h> int main (void) { FILE *fp; if ((fp = fopen("teste.dat","r")) == NULL) printf("Erro Fatal: Impossvel Abrir o Arquivo\n"); else { printf("Ok, arquivo aberto\n"); ... ou #include <stdio.h> int main (void) { FILE *fp; fp = fopen("a:\fontes\teste.dat","w"); if (fp == NULL) printf("Erro Fatal: Impossvel Criar o Arquivo\n); else
105

{ printf("Ok, arquivo criado com sucesso\n"); ... Funo: putc A funo putc utilizada para gravar (write) caracteres em um arquivo. Sintaxe: int putc (int ch, FILE *fp); Prototype: stdio.h ch o caracter a ser gravado fp o ponteiro do arquivo aberto pela funo fopen() Observao: Se uma gravao for bem sucedida putc() devolver o caracter gravado, caso contrrio devolver um EOF. EOF - End of File (Fim de Arquivo) Funo: getc A funo getc utilizada para ler (read) caracteres de um arquivo. Sintaxe: int getc (FILE *fp); Prototype: stdio.h fp o ponteiro do arquivo aberto pela funo fopen() Funo: feof A funo feof (file end of file) determina se o fim de arquivo foi encontrado. Devolve 0 se no chegou ao fim do arquivo. Sintaxe: int feof (FILE *fp); Prototype: stdio.h Funo: fclose

106

A funo fclose (file close) utilizada para fechar um arquivo aberto. Antes de fechar o arquivo os dados (que ainda estavam no buffer) so gravados. Sintaxe: int fclose (FILE *fp); Prototype: stdio.h Observao: Retorna 0 se a operao foi bem sucedida.

4.2 Argumentos argc e argv


Quando o programador que implementar um programa que recebe parmetros pela linha de comandos necessrio definir dois argumentos (parmetros) na funo main. argc - Identifica o nmero de parmetros presente na linha de comandos. argv - um vetor de strings que possui todos os parmetros da linha de comandos. Como definir os argumentos: int main(int argc, char *argv[]) Exemplo: (execuo do programa lista.exe pela linha de comandos) C:\>lista lista.c <enter>
0 1 0 C l 1 : i 2 \ s 3 l t 4 i a 5 s . 6 t c 7 a
NULL

8 .

9 e

10 x

11 e

12
NULL

argv[0] c:\lista.exe argv[1] lista.c 23) Escrever um programa em C que lista na tela um arquivo texto. Soluo do problema proposto (23): Observao: Este programa deve ser compilado e ento executado por linha de comando da seguinte forma:

107

C:\>lista lista.c <enter>


// lista.c #include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; char ch; if (argc != 2) printf("Sintaxe: LISTA <Nome_Arquivo_Texto>\n"); else { fp = fopen(argv[1],"rt"); if (fp == NULL) printf("ERRO FATAL: Arquivo [%s] Inexistente\n",argv[1]); else { ch = getc(fp); while (!feof(fp)) { printf("%c",ch); ch = getc(fp); } fclose(fp); } } }

24) Escrever um programa em C que lista na tela um arquivo texto, imprimindo ainda o nmero de caracteres e o nmero de linhas. Soluo do problema proposto (24):
// bytes.c #include <stdio.h> int main(int argc, char *argv[]) { FILE *fp; char ch; long unsigned int n = 0; unsigned int l = 1; if (argc != 2) printf("Sintaxe: LISTA <Nome_Arquivo_Texto>\n"); else 108

{ fp = fopen(argv[1],"rt"); if (fp == NULL) printf("ERRO FATAL: Arquivo [%s] Inexistente\n",argv[1]); else { ch = getc(fp); while (!feof(fp)) { if (ch == '\n') l++; n++; printf("%c",ch); ch = getc(fp); } fclose(fp); printf("\nNmero de Caracteres: %d",n); printf("\nNmero de Linhas: %d",l); } } }

25) Escreva um programa em C que l strings via teclado e grava-as (caracter por caracter) em um arquivo texto. Soluo do problema proposto (25):
// grava.c #include <stdio.h> #include <string.h> int main(void) { FILE *fp; char nome[256],linha[256]; char ch; int i,n; printf("Nome do Arquivo Texto: "); scanf("%s",nome); fp = fopen(nome,"rt"); if (fp != NULL) printf("ERRO FATAL: Arquivo [%s] Existe\n",nome); else { fp = fopen(nome,"wt"); if (fp == NULL) printf("ERRO FATAL: Problema na Criao do Arquivo [%s]\n",nome); else 109

{ do { gets(linha); if (strcmp(linha,"") != 0) { n = strlen(linha); for (i = 0;i < n;i++) putc(linha[i],fp); putc('\n',fp); } } while (strcmp(linha,"") != 0); putc(EOF,fp); fclose(fp); } } }

Escrever um programa em C que l strings via teclado e grava-as (toda de uma vez) em um arquivo texto.
26)

Soluo do problema proposto (26):


// grava.c #include <stdio.h> #include <string.h> int main(void) { FILE *fp; char nome[256],linha[256]; char ch; printf("Nome do Arquivo Texto: "); scanf("%s",nome); fp = fopen(nome,"rt"); if (fp != NULL) printf("ERRO FATAL: Arquivo [%s] Existe\n",nome); else { fp = fopen(nome,"wt"); if (fp == NULL) printf("ERRO FATAL: Problema na Criao do Arquivo [%s]\n",nome); else { do { gets(linha); if (strcmp(linha,"") != 0) { fprintf(fp,"%s",linha); 110

putc('\n',fp); } } while (strcmp(linha,"") != 0); putc(EOF,fp); fclose(fp); } } }

Funo: rewind A funo rewind estabelece o localizador de posio do arquivo para o incio do arquivo especificado, ou seja, faz com que o ponteiro do arquivo (fp) aponte para o byte zero. Sintaxe: void rewind (FILE *fp); Prototype: stdio.h Funes: getw e putw As funes getw e putw so utilizadas para ler e gravar, respectivamente, inteiros em um arquivo. Funo: Leitura de inteiros (getw) Sintaxe: int getw (FILE *fp); Prototype: stdio.h Funo: Gravao de inteiros (putw) Sintaxe: int putw (int x, FILE *fp); Prototype: stdio.h Funes: fgets e fputs As funes fgets e fputs so utilizadas para ler e gravar strings. Funo: Leitura de strings (fgets) Sintaxe: char *fgets (char *str, int comprimento, FILE *fp); Prototype: stdio.h Funo: Gravao de strings (fputs) Sintaxe: char *fputs (char *str, FILE *fp); Prototype: stdio.h

111

Observao: A funo fgets l uma string do arquivo especificado at que leia ou um '\n' ou (comprimento - 1) caracteres. Funes: fread e fwrite As funes fread e fwrite so utilizadas para ler e gravar blocos de dados, normalmente uma struct. Funo: Leitura de blocos (fread) Sintaxe: int fread (void *buffer, int num_bytes, int cont, FILE *fp); Prototype: stdio.h Funo: Gravao de blocos (fwrite) Sintaxe: int fwrite (void *buffer, int num_bytes, int cont, FILE *fp); Prototype: stdio.h buffer: um ponteiro para a regio da memria ou o endereo de uma varivel que receber os dados lidos do arquivo pela funo fread ou que ser gravada no arquivo pela funo fwrite. num_bytes: Especifica a quantidade de bytes a serem lidos ou gravados. cont: Determina quantos blocos (cada um com comprimento de num_bytes) sero lidos ou gravados. fp: o ponteiro para o arquivo. Funo: fseek A funo fseek utilizada para ajustar o localizador de posio do arquivo, ou seja, permite selecionar a posio para efetuar operaes de leitura e gravao aleatrias. Sintaxe: int fseek (FILE *fp, long int num_bytes, int origem); Prototype: stdio.h num_bytes: o nmero de bytes desde origem at chegar a posio desejada. Origem em arquivos Origem Incio do arquivo Posio corrente
112

Identificador SEEK_SET SEEK_CUR

Fim do arquivo Funes: fprintf e fscanf

SEEK_END

As funes fprintf e fscanf se comportam exatamente como printf e scanf, exceto pelo fato de que elas operam com arquivos em disco. Funo: Gravao de dados formatados (fprintf) Sintaxe: int fprintf (FILE *fp, char *formato, lista argumentos); Prototype: stdio.h Funo: Leitura de dados formatados (fscanf) Sintaxe: int fscanf (FILE *fp, char *formato, lista argumentos); Prototype: stdio.h Funo: remove A funo remove apaga do disco o arquivo especificado. Sintaxe: int remove (char *nome_arquivo); Prototype: stdio.h Exemplos: Abaixo, so listados trs programas: cria.c, lista.c, consulta.c, os quais possuem como registro, uma string com no mximo 80 caracteres. Escreva um programa em C que l nomes via teclado (mximo 80 caracteres) e grava-os em um arquivo binrio qualquer (o nome deve ser informado pelo usurio). O programa termina quando o usurio digitar apenas um enter.
27)

Soluo do problema proposto (27):


// write.c #include <stdio.h> #include <string.h> int main(void) { FILE *fp; 113

char nome[80],arquivo[256]; int n = 0; printf("Nome do Arquivo: "); scanf("%s",arquivo); fp = fopen(arquivo,"rb"); if (fp != NULL) printf("ERRO FATAL: Arquivo [%s] Existe\n",arquivo); else { fp = fopen(arquivo,"wb"); if (fp == NULL) printf("ERRO FATAL: Problema na Criao do Arquivo [%s]\n",arquivo); else { do { printf("Nome: "); gets(nome); if (strcmp(nome,"") != 0) { fwrite(nome,sizeof(nome),1,fp); n++; } } while (strcmp(nome,"") != 0); printf("%d Nomes Gravados\n",n); fclose(fp); } } }

Escreva um programa em C que permite listar (na tela) os nomes contidos em um arquivo binrio qualquer (criado no programa acima).
28)

Soluo do problema proposto (28):


// read.c #include <stdio.h> #include <string.h> int main(void) { FILE *fp; char nome[80],arquivo[256]; int n = 0; printf("Nome do Arquivo: "); scanf("%s",arquivo); fp = fopen(arquivo,"rb"); if (fp == NULL) 114

printf("ERRO FATAL: Arquivo [%s] Inexistente\n",arquivo); else { fread(nome,sizeof(nome),1,fp); while (!feof(fp)) { printf("Nome: %s\n",nome); fread(nome,sizeof(nome),1,fp); n++; } printf("%d Nomes Lidos\n",n); fclose(fp); getchar(); } }

Escreva um programa em C que permite consultar o arquivo de nomes. Para tanto solicitado, ao usurio, o nmero do registro para ser calculado a posio deste registro no arquivo. Logo aps o registro exibido na tela.
29)

Soluo do problema proposto (29):


// consulta.c #include <stdio.h> #include <string.h> int main (void) { FILE *fp; char nome[80]; char arquivo[256]; unsigned int n, ok; long int posicao; char ch; printf("Nome do Arquivo: "); scanf(%s, arquivo); if ((fp = fopen(arquivo,"rb")) == NULL) { printf("ERRO: Arquivo no EXISTE\n"); getchar(); } else { do { printf("Nmero do Registro: "); scanf("%d", &n);

115

posicao = n * sizeof(nome); fseek(fp, posicao, SEEK_SET); ok = fread(nome, sizeof(nome), 1, fp); if (ok) printf("%d: Nome: %s\n", n, nome); else printf("ERRO: Registro NO existe\n"); printf("Continua [S/N] ? "); do { ch = getchar(); } while (!strchr("SsNn",ch)); } while (strchr("Ss",ch)); fclose(fp); } }

Escreva um programa em C que permite ordenar o arquivo de nomes gerado pelo programa write.c. Para tanto deve ser criada uma Lista Encadeada. Utilizar um mtodo de classificao qualquer. Aps a classificao os nomes devem ser gravados no arquivo original de nomes.
30)

Soluo do problema proposto (30):


// sort.c #include <stdio.h> #include <stdlib.h> // ------------------------------------ Definies #define SUCESSO 0 #define FALTA_DE_MEMORIA #define LISTA_VAZIA #define TRUE !0 #define FALSE 0 typedef char TDADOS; typedef struct nodo { TDADOS dado[80]; struct nodo *elo; } TNODO; typedef struct { TNODO *primeiro; } TLISTA; 1 2

116

// ------------------------------------ Prototypes void Cria_Lista (TLISTA *l); int Inclui_Lista (TLISTA *l, TDADOS *d); int Exclui_Lista(TLISTA *l, TDADOS *nome); void Destroi_Lista(TLISTA *l); void Exibe_Lista(TLISTA l); void Ordena_Lista(TLISTA *l); // ------------------------------------ Programa Principal int main(void) { FILE *fp; char arquivo[256]; TDADOS nome[80]; TLISTA l; int erro; Cria_Lista(&l); printf("Nome do Arquivo: "); scanf("%s",arquivo); fp = fopen(arquivo,"r+b"); if (fp == NULL) printf("ERRO FATAL: Arquivo [%s] Inexistente\n",arquivo); else { fread(nome,sizeof(nome),1,fp); while (!feof(fp)) { erro = Inclui_Lista(&l,nome); if (erro) { printf("ERRO FATAL: Falta de Memria\n"); getchar(); exit(1); } fread(nome,sizeof(nome),1,fp); } printf("Lista de Entrada"); Exibe_Lista(l); Ordena_Lista(&l); printf("\nLista Ordenada"); Exibe_Lista(l); rewind(fp); erro = Exclui_Lista(&l,nome); while (!erro) { fwrite(nome,sizeof(nome),1,fp); erro = Exclui_Lista(&l,nome); } 117

fclose(fp); } Destroi_Lista(&l); getchar(); } // ------------------------------------ Cria_Lista void Cria_Lista (TLISTA *l) { l->primeiro = NULL; } // ------------------------------------ Inclui_Lista int Inclui_Lista (TLISTA *l, TDADOS *d) { TNODO *p; p = (TNODO *) malloc(sizeof(TNODO)); if (p == NULL) return(FALTA_DE_MEMORIA); else { if (l->primeiro == NULL) { l->primeiro = p; strcpy(p->dado,d); p->elo = NULL; } else { strcpy(p->dado,d); p->elo = l->primeiro; l->primeiro = p; } return(SUCESSO); } } // ------------------------------- Exclui_Lista int Exclui_Lista(TLISTA *l, TDADOS *nome) { TNODO *p; if (l->primeiro == NULL) return(LISTA_VAZIA); else { p = l->primeiro; 118

strcpy(nome,p->dado); l->primeiro = p->elo; free(p); return(SUCESSO); } } // ----------------------------------------- Destroi_Lista void Destroi_Lista(TLISTA *l) { TNODO *p,*q; if (l->primeiro != NULL) { p = l->primeiro; while (p != NULL) { q = p->elo; free(p); p = q; } } Cria_Lista(l); } // ------------------------------------------ Exibe_Lista void Exibe_Lista(TLISTA l) { TNODO *p; if (l.primeiro == NULL) printf("\nVAZIA"); else { p = l.primeiro; while (p != NULL) { printf("\n%s",p->dado); p = p->elo; } } } // ------------------------------------ Ordena_Lista void Ordena_Lista(TLISTA *l) { TNODO *p,*q; TDADOS temp[80]; 119

int trocou; if (l->primeiro != NULL) do { trocou = FALSE; p = l->primeiro; q = p->elo; while (q != NULL) { if (strcmp(p->dado,q->dado) > 0) { strcpy(temp,p->dado); strcpy(p->dado,q->dado); strcpy(q->dado,temp); trocou = TRUE; } p = q; q = p->elo; } } while (trocou); }

120

5. Pesquisa de Dados
Uma operao complexa e trabalhosa a consulta em tabelas. Normalmente uma aplicao envolve grande quantidade de dados que so armazenadas em Tabelas. As tabelas so compostas de registros (normalmente possui uma chave), e os registros de campos.

5.1 Pesquisa Seqencial


Mtodo mais simples de pesquisa em tabela, consiste em uma varredura seqencial, sendo que cada campo comparado com o valor que est sendo procurado. Esta pesquisa termina quando for achado o valor desejado ou quando chegar o final da tabela.

23) Escreva um programa em C que faz uma Busca Seqencial em uma estrutura que possui os campos: chave, nome, altura e peso.

121

Soluo do problema proposto (23):


// ---------------------------------------------- Pesquisa Sequencial #include <stdio.h> #include <string.h> #include <ctype.h> // ---------------------------------------------- Definies #define MAX 10 typedef struct { int chave; char nome[21]; float peso; float altura; } TABELA; // ---------------------------------------------- Prototypes int Pesquisa_Sequencial(TABELA t[], int valor,int n); // ---------------------------------------------- Programa Principal int main(void) { TABELA t[MAX]; int n = 0; int ch,chave; char tecla; do { printf("Chave: "); scanf("%d",&t[n].chave); printf("Nome: "); gets(t[n].nome); printf("Peso: "); scanf("%f",&t[n].peso); printf("Altura: "); scanf("%f",&t[n].altura); printf("Continua [S/N] ?"); do { tecla = tolower(getchar()); } while (!strchr("sn",tecla)); n++; } while (tecla == 's' && n < MAX); do { printf("Chave para consulta [0 - Sair]: "); scanf("%d",&ch);

122

chave = Pesquisa_Sequencial(t,ch,n); if (chave != -1) { printf("Chave: %d\n",t[chave].chave); printf("Nome: %s\n",t[chave].nome); printf("Peso: %.1f\n",t[chave].peso); printf("Altura: %.1f\n",t[chave].altura); } else printf("Erro: Chave Inexistente\n"); } while (ch != 0); } // ---------------------------------------------- Pesquisa_Sequencial int Pesquisa_Sequencial(TABELA t[], int ch,int n) { int i,chave = -1; for (i = 0;i < n;i++) if (t[i].chave == ch) { chave = i; break; } return(chave); }

Observao: A Pesquisa Sequencial apresenta desempenho melhor se a tabela estiver ordenada pela chave de acesso: 24) Escreva um programa em C que faz uma Busca Seqencial, em uma estrutura ordenada por chave, que possui os campos: chave, nome, altura e peso. Soluo do problema proposto (24):
// ---------------------------------------------- Pesquisa Ordenada #include <stdio.h> #include <string.h> #include <ctype.h> // ---------------------------------------------- Definies #define MAX 10 typedef struct { int chave; 123

char nome[21]; float peso; float altura; } TABELA; // ---------------------------------------------- Prototypes int Pesquisa_Ordenada(TABELA t[], int ch, int n); void Ordena_Tabela(TABELA t[], int n); // ---------------------------------------------- Programa Principal int main(void) { TABELA t[MAX]; int n = 0; int ch,chave; char tecla; do { printf("Chave: "); scanf("%d",&t[n].chave); printf("Nome: "); gets(t[n].nome); printf("Peso: "); scanf("%f",&t[n].peso); printf("Altura: "); scanf("%f",&t[n].altura); printf("Continua [S/N] ?"); do { tecla = tolower(getchar()); } while (!strchr("sn",tecla)); n++; } while (tecla == 's' && n < MAX); Ordena_Tabela(t,n); do { printf("Chave para consulta [0 - Sair]: "); scanf("%d",&ch); chave = Pesquisa_Ordenada(t,ch,n); if (chave != -1) { printf("Chave: %d\n",t[chave].chave); printf("Nome: %s\n",t[chave].nome); printf("Peso: %.1f\n",t[chave].peso); printf("Altura: %.1f\n",t[chave].altura); } else printf("Erro: Chave Inexistente\n"); } while (ch != 0); }

124

// ---------------------------------------------- Ordena_Tabela void Ordena_Tabela(TABELA t[], int n) { int i,j; TABELA temp; for (i = 0;i < n-1;i++) for (j = i+1;j < n;j++) if (t[i].chave > t[j].chave) { temp = t[i]; t[i] = t[j]; t[j] = temp; } } // ---------------------------------------------- Pesquisa_Ordenada int Pesquisa_Ordenada(TABELA t[], int ch, int n) { int i,chave = -1; for (i = 0; i < n;i++) if (t[i].chave >= ch) if (t[i].chave == ch) { chave = i; break; } return(chave); }

5.2 Pesquisa Binria


Mtodo de Pesquisa que s pode ser aplicada em tabelas ordenadas.

125

O mtodo consiste na comparao do "valor" com a chave localizada na metade da tabela, pode ocorrer: valor = chave............chave localizada valor < chave............chave est na primeira metade (esquerda) valor > chave............chave est na segunda metade (direita)

A cada comparao, a rea de pesquisa reduzida a metade do nmero de elementos. O nmero mximo de comparaes ser:

25) Escreva um programa em C que faz uma Pesquisa Binria em uma tabela de nmeros inteiros. Soluo do problema proposto (25):
// --------------------------------------- Pesquisa Binria #include <stdio.h> #define MAX 10 // --------------------------------------- Prototypes void Ordena_Tabela(int t[], int n); int Pesquisa_Binaria(int t[], int n, int valor); void Exibe_Tabela(int t[], int n); // --------------------------------------- Programa Principal int main(void) { int t[MAX]; int indice,n = -1; int valor; do { n++; 126

printf("Nmero: "); scanf("%d",&t[n]); } while (t[n] != 0 && n < MAX); Exibe_Tabela(t,n); Ordena_Tabela(t,n); Exibe_Tabela(t,n); do { printf("Valor: "); scanf("%d",&valor); if (valor != 0) { indice = Pesquisa_Binaria(t,n,valor); if (indice == -1) printf("ERRO: Valor no est na tabela\n"); else printf("Indice: %d\n",indice); } } while (valor != 0); } // ---------------------------------------------- Ordena_Tabela void Ordena_Tabela(int t[], int n) { int i,j,temp; for (i = 0;i < n-1;i++) for (j = i+1;j < n;j++) if (t[i] > t[j]) { temp = t[i]; t[i] = t[j]; t[j] = temp; } } // ---------------------------------------------- Pesquisa_Binaria int Pesquisa_Binaria(int t[], int n, int valor) { int i,j,indice; int inic,fim,metade; inic = 0; fim = n-1; metade = n / 2; indice = -1; do { if (valor == t[metade]) { indice = metade; 127

break; } else if (valor < t[metade]) { fim = metade - 1; metade = (fim + inic) / 2; } else { inic = metade + 1; metade = (fim + inic) / 2; } } while (indice == -1 && inic <= fim); return(indice); } // ------------------------------------------------- Exibe_Tabela void Exibe_Tabela(int t[], int n) { int i; printf("Tabela: "); for (i = 0;i < n;i++) printf("%02d ",t[i]); printf("\n"); }

5.3 Clculo de Endereo (Hashing)


Alm de um mtodo de pesquisa, este mtodo tambm um mtodo de organizao fsica de tabelas (Classificao). Onde cada dado de entrada armazenado em um endereo previamente calculado (atravs de uma funo), desta forma, o processo de busca igual ao processo de entrada, ou seja, eficiente. Um dos problemas definir bem o tipo de funo a ser usada, pois normalmente as funes geram endereos repetidos. A eficincia deste mtodo depende do tipo de funo. Numa tabela com n elementos com valores na faixa de [0..MAX] pode ser utilizada a seguinte a funo:

Onde: n o nmero de elementos.


128

Exemplo: n = 53 entrada: [0..1000]

Note que no clculo dos endereos houve repeties, tais como: 2, 33, 23, 10 e 50, por causa disto, necessrio verificar se o endereo est ocupado ou no. Finalmente os endereos calculados so:

26) Escreva um programa em C que faz um Clculo de Endereo (Hashing) em uma tabela de nmeros inteiros. Soluo do problema proposto (26):
// --------------------- Hashing.c #include <stdio.h> #include <string.h> #define k 19 #define TRUE !0 #define FALSE 0 typedef struct { int situacao; int valor; } TABELA; // ---------------------------------------------- Inicializa_Tabela void Inicializa_Tabela(TABELA t[]) { int i; 129

for (i = 0;i < k;i++) { t[i].situacao = FALSE; t[i].valor = 0; } } // ---------------------------------------------- Insere_Tabela void Insere_Tabela(TABELA t[], int entrada) { int endereco; endereco = entrada % k; while (t[endereco].situacao) endereco++; t[endereco].valor = entrada; t[endereco].situacao = TRUE; } // ---------------------------------------------- Hashing int Hashing(TABELA t[], int entrada) { int i, endereco; endereco = entrada % k; while (t[endereco].valor != entrada && endereco != k) endereco++; if (endereco != k) return(endereco); else return(0); } // ---------------------------------------------- Exibe_Tabela void Exibe_Tabela(TABELA t[]) { int i; for (i = 0;i < k;i++) printf("%3d ",i); for (i = 0;i < k;i++) printf("%03d ",t[i].valor); } // ---------------------------------------------- PROGRAMA PRINCIPAL

130

int main(void) { TABELA t[k]; int n = 0, entrada, endereco; char tecla; Inicializa_Tabela(t); do { Exibe_Tabela(t); n++; printf("Nmero: "); scanf("%d",&entrada); Insere_Tabela(t,entrada); printf("Continua [S/N]? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && n <= k); do { printf("\nValor a ser CONSULTADO: "); scanf("%d",&entrada); endereco = Hashing(t,entrada); if (endereco == 0) printf("ERRO: Valor Invlido\n"); else printf("Endereco: %d\n",endereco); printf("Continua [S/N]? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla)); }

6. Classificao de Dados (Ordenao)


o processo pelo qual determinada a ordem em que devem ser apresentados os elementos de uma tabela de modo a obedecer seqncia de um ou mais campos (chaves de classificao). Classificao Interna...................... Memria Principal Classificao Externa...................... Memria Secundria

6.1 Classificao por Fora Bruta

131

Logo, os elementos so fisicamente reorganizados. 27) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros. Soluo do problema proposto (27):
// Sort.c #include <stdio.h> #include <string.h> #define QUANT 10 void Sort(int v[], int n) { int i,j,temp; for (i = 0;i < n-1;i++) for (j = i+1;j < n;j++) if (v[i] > v[j]) { temp = v[i]; v[i] = v[j]; v[j] = temp; } } void Exibe(int v[], int n) { int i; printf("\nLista: "); for (i = 0;i <= n;i++) printf("%2d ",v[i]); 132

} int main(void) { int v[QUANT]; int n = -1; char tecla; do { n++; printf("\nValor: "); scanf("%d",&v[n]); printf("Continua [S/N] ?"); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); Exibe(v,n); } while (strchr("Ss",tecla) && n < QUANT); Sort(v,n); Exibe(v,n); printf("\nTecle qualquer tecla ..."); getchar(); }

6.2 Vetor Indireto de Ordenao (Tabela de ndices)


Os elementos no so reorganizados fisicamente, apenas criado um outro vetor (tabela de ndices) que controla a ordem do primeiro. Exemplo:

28) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros utilizando um Vetor Indireto de Ordenao (VIO). Soluo do problema proposto (28):
133

// Vio_1.c (Vetor Indireto de Ordenao) #include <stdio.h> #include <string.h> #define TRUE !0 #define FALSE 0 #define QUANT 10 // ---------------------------------------------- Verifica int Verifica(int vio[], int i, int k) { int j, ok = TRUE; for (j = 0;j <= k;j++) if (vio[j] == i) ok = FALSE; return(ok); } // ---------------------------------------------- PROGRAMA PRINCIPAL int main(void) { char v[QUANT][20]; int vio[QUANT]; int i,j,k,l,u = -1; char tecla; int troca,ok; do { u++; printf("\nNome: "); gets(v[u]); printf("Continua [S/N] ?"); vio[u] = FALSE; do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && u <= QUANT); k = 0; j = 1; do { troca = TRUE; for (i = 0;i <= u;i++) { ok = Verifica(vio,i,k); if (ok) 134

if (strcmp(v[i],v[j]) > 0) { j = i; troca = FALSE; } } if (!troca) { vio[k] = j; k++; j = 1; } if (troca) { ok = Verifica(vio,j,k); if (ok) { k++; vio[k] = j; } if (j < u) j++; else j--; } } while (k != u); printf("\nLista de Nomes Ordenados\n"); for (i = 0;i <= u;i++) printf("Nome: %s\n",v[vio[i]]); getchar(); }

29) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros utilizando um Vetor Indireto de Ordenao (VIO). Soluo do problema proposto (29):
// Vio.c (Vetor Indireto de Ordenao) #include <stdio.h> #include <string.h> #define QUANT 10 int main(void) { char v[QUANT][30]; int vio[QUANT];

135

int i, j, u = -1, temp; char tecla; do { u++; printf("\nNome: "); gets(v[u]); printf("Continua [S/N] ?"); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && u < QUANT); for (i = 0;i <= u;i++) vio[i] = i; for (i = 0;i < u;i++) for (j = i+1;j <= u;j++) if (strcmp(v[vio[i]],v[vio[j]]) > 0) { temp = vio[i]; vio[i] = vio[j]; vio[j] = temp; } printf("\nLista de Nomes Ordenados\n"); for (i = 0; i <= u;i++) printf("Nome: %s\n",v[vio[i]]); getchar(); }

6.3 Classificao por Encadeamento


Os elementos permanecem em seus lugares. criado ento uma lista encadeada ordenada. Esta lista possui um Header (Cabea) o qual indica o primeiro elemento da lista. Exemplo:

136

30) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros utilizando encadeamento. Soluo do problema proposto (30):
// Encadea.c (Ordenao por Encadeamento) #include <stdio.h> #include <string.h> #define TRUE !0 #define FALSE 0 #define QUANT 10 typedef struct { char nome[20]; int prox; } TABELA; // ---------------------------------------------- Verifica void Verifica (TABELA t[], TABELA ta[], int *j) { int i = 0,sai; do { sai = FALSE; if (strcmp(t[i].nome,ta[*j].nome) == 0) { *j = i; sai = TRUE; } i++; } while (!sai); } // ---------------------------------------------- Copia void Copia (TABELA t[], TABELA ta[], int *m, int n) { int i; *m = -1; for (i = 0;i <= n;i++) if (t[i].prox == -1) { (*m)++; strcpy(ta[*m].nome,t[i].nome); 137

ta[*m].prox = -1; } } // ---------------------------------------------- PROGRAMA PRINCIPAL int main(void) { TABELA t[QUANT],ta[QUANT]; int i,j,k,m,u = -1; int anterior,primeiro,sai; char tecla; do { u++; printf("\nNome: "); gets(t[u].nome); t[u].prox = -1; printf("Continua [S/N]? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && u < QUANT); primeiro = 0; for (i = 1;i <= u;i++) if (strcmp(t[i].nome,t[primeiro].nome) < 0) primeiro = i; t[primeiro].prox = 0; anterior = primeiro; do { Copia(t,ta,&m,u); if (m != 0) { if (m >= 1) { i = 1; j = 0; do { if (strcmp(ta[i].nome,ta[j].nome) < 0) j = i; i++; } while (i <= m); } } else j = 0; Verifica(t,ta,&j); t[anterior].prox = j; t[j].prox = 0; anterior = j; } while (m != 0); 138

j = primeiro; printf("\nLista de Nomes Ordenados por Encadeamento\n"); for (i = 0;i <= u;i++) { printf("%s\n",t[j].nome); j = t[j].prox; } getchar(); }

6.4 Mtodos de Classificao Interna


Os mtodos de Classificao Interna podem ser: Por Insero Por Troca Por Seleo

Observao: Para os seguintes mtodos considere que as entradas so feitas no vetor v, logo aps criado o vetor c (chaves) e o vetor e (endereos). A ordenao feita no vetor c e o vetor e o vetor indireto de ordenao, ou seja, ser mantido o vetor de entrada intacto.

6.4.1 Mtodo por Insero Direta


Neste mtodo ocorre a insero de cada elemento em outro vetor ordenado.

139

Utilizao: Pequena quantidade de dados, pois pouco eficiente. O vetor dividido em dois segmentos. Inicialmente: c[0] e c[1], c[2], ... c[n]

A classificao acontece por meio de interaes, cada elemento do segundo segmento inserido ordenadamente no primeiro at que o segundo segmento acabe. Por exemplo:

31) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros utilizando Mtodo por Insero Direta. Soluo do problema proposto (31):
140

// MID.c (Mtodo de Insero Direta) #include <stdio.h> #define QUANT 10 int main(void) { int v[QUANT],c[QUANT],e[QUANT]; int i,j,k,u = -1; int chave,endereco; char tecla; do { u++; printf("\nNmero: "); scanf("%d",&v[u]); printf("Continua [S/N] ? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && u < QUANT); for (i = 0;i <= u;i++) { c[i] = v[i]; e[i] = i; } for (i = 1;i <= u;i++) { k = 0; j = i - 1; chave = c[i]; endereco = e[i]; while (j >= 0 && k == 0) if (chave < c[j]) { c[j+1] = c[j]; e[j+1] = e[j]; j--; } else k = j + 1; c[k] = chave; e[k] = endereco; } printf("\n Valores: "); for (i = 0;i <= u;i++) printf("%2d ",c[i]); printf("\nEndereos: "); for (i = 0;i <= u;i++) 141

printf("%2d ",e[i]); getchar(); }

6.4.2 Mtodo por Troca


Neste mtodo, compara-se pares de elementos, trocando-os de posio caso estejam desordenados.

6.4.2.1 Mtodo da Bolha (Bubble Sort)


Cada elemento do vetor testado com o seguinte, se estiverem fora de ordem ocorre a troca, isto repetido at no ocorrer mais trocas. Por exemplo:

Observao: Na primeira passagem completa o ltimo elemento esta ordenado, logo na segunda passagem no necessrio ir at o fim. 32) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros utilizando o Mtodo da Bolha. Soluo do problema proposto (32):
// Bolha.c #include <stdio.h> #include <string.h>

142

#define QUANT 10 #define TRUE !0 #define FALSE 0 int main(void) { int v[QUANT], c[QUANT], e[QUANT]; int i, j, n = -1, m; int chave, endereco, troca; char tecla; do { n++; printf("\nNmero: "); scanf("%d",&v[n]); printf("Continua [S/N] ? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && n < QUANT); for (i = 0;i <= n;i++) { c[i] = v[i]; e[i] = i; } m = n - 1; do { troca = TRUE; for (i = 0;i <= m;i++) if (c[i] > c[i+1]) { chave = c[i]; c[i] = c[i+1]; c[i+1] = chave; endereco = e[i]; e[i] = e[i+1]; e[i+1] = endereco; j = i; troca = FALSE; } m = j; } while (!troca); printf("\nLista Ordenada\n"); for (i = 0;i <= n;i++) printf("%d\n",c[i]); getchar(); }

6.4.3 Mtodo por Seleo


143

Seleo sucessiva do menor valor da tabela. A cada passo o menor elemento colocado em sua posio definitiva.

6.4.3.1 Mtodo por Seleo Direta


A cada passo do mtodo feita uma varredura do segmento que corresponde os elementos, ainda no selecionados, e determinado o menor elemento o qual colocado na primeira posio do elemento por troca. Por exemplo:

33) Escreva um programa em C que ordena (classifica em ordem crescente) um vetor de nmeros inteiros utilizando o Mtodo por Seleo Direta. Soluo do problema proposto (33):
// Direta.c #include <stdio.h> #include <string.h> #define QUANT 10 #define TRUE !0 #define FALSE 0 int main(void) { int v[QUANT], c[QUANT], e[QUANT]; int i, j, n = -1, min;

144

int chave, endereco, troca; char tecla; do { n++; printf("\nNmero: "); scanf("%d",&v[n]); printf("Continua [S/N] ? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla) && n < QUANT); for (i = 0;i <= n;i++) { c[i] = v[i]; e[i] = i; } for (i = 0;i <= n-1;i++) { min = i; for (j = i+1;j <= n;j++) if (c[j] < c[min]) min = j; chave = c[i]; c[i] = c[min]; c[min] = chave; endereco = e[i]; e[i] = e[min]; e[min] = endereco; } printf("\nLista Ordenada\n"); for (i = 0;i <= n;i++) printf("%d\n",c[i]); getchar(); }

145

7. rvores
So estruturas de dados (no-lineares) que caracterizam uma relao entre os dados, relao existente entre os dados uma relao de hierarquia ou de composio (um conjunto subordinado a outro).

7.1 Conceitos Bsicos Definio


um conjunto finito T de um ou mais ns, tais que: a) Existe um n principal chamado raiz (root); b) Os demais ns formam n >= 0 conjuntos disjuntos T1, T2, ... Tn, onde cada um destes subconjuntos uma rvore. As rvores Ti (i >= 1 e i <= n) recebem a denominao de sub-rvores.

Terminologia Grau
Indica o nmero de sub-rvores de um n.

146

Observao: Se um nodo no possuir nenhuma sub-rvore chamado de n terminal ou folha.

147

Nvel
o comprimento, ou seja, o nmero de linhas do caminho da raiz at o n.

Observao: Raiz nvel zero (0)


Exemplo:

Altura
o nvel mais alto da rvore. Na rvore acima, a altura igual a 2.

Floresta
um conjunto de zero ou mais rvores disjuntas, ou seja, se for eliminado o n raiz da rvore, as sub-rvores que restarem chamam-se de florestas.

148

Formas de Representao de rvores


) Representao Hierrquica

) Representao por Conjunto (Diagrama de Incluso ou Composio)

) Representao por Expresso Parentetizada (Parnteses Aninhados)

(A(B()C(D(G()H())E()F(I()))))
) Representao por Expresso no Parentetizada

AA 2 B 0 C 3 D 2 G 0 H 0 E 0 F 1 I 0
)

Representao por Endentao (Digrama de Barras)

149

150

7.2 rvores Binrias


Uma rvore binria (T) um conjunto finito de ns que pode ser vazio ou pode ser dividida em trs sub-conjuntos disjuntos: raiz, subrvore esquerda (Te) e sub-rvore direita (Td). So estruturas onde o grau de cada n menor ou igual a dois, ou seja, no mximo grau 2. O nmero mximo de ns no nvel i 2i. So rvores onde cada n tem no mximo dois filhos (grau mximo 2), desta forma, obtm-se uma estrutura apropriada para busca binria, pois sabe-se que existe, para cada nodo, duas subrvores (Te e Td). Para cada n da rvore associa-se uma chave (dado, valor ou informao) que permite a realizao de uma classificao. A Construo da rvore deve ser de forma que na sub-rvore esquerda (Te) da raiz s existam ns com chaves menores que a chave da raiz. E a sub-rvore direita (Td) s pode conter ns com valores maiores que a raiz. Com esta reestruturao da rvore, a busca de um determinado n torna-se trivial. O acesso aos dados pode ser feito ento atravs de funes recursivas.

Propriedades
1) O nmero mximo de nodos no k-simo nvel de uma rvore binria 2k; 2) O nmero mximo de nodos em uma rvore binria com altura k 2k+1-1, para k >= 0; 3) rvore completa: rvore de altura k com 2k+1-1 nodos.

151

Exemplo de uma aplicao de rvore Binria (Analisador de Expresso):

Expresso: (3 + 6) * (4 1) + 5

Converso de rvore Genrica em rvore Binria Ligar os ns irmos; Remover a ligao entre o n pai e seus filhos, exceto as do primeiro filho.

152

Nota: O n da sub-rvore esquerda filho e o n da sub-rvore direita irmo

153

7.3 Representaes
7.3.1 Representao por Contigidade Fsica (Adjacncia) Os nodos so representados seqencialmente na memria. Devem ser tomados os seguintes cuidados:
Ser alocado espao suficiente para armazenar a estrutura completa; Os nodos devem ser armazenados em uma lista, onde cada nodo i da rvore ocupa o i-simo nodo da lista.

Exemplo:

Sendo i a posio de um nodo e n o nmero mximo de nodos da rvore. Observaes:


1) O pai de i est em i / 2 sendo i <= n. Se i = 1, i a raiz e no possui pai. 2) O filho esquerda de i est em 2i se 2i <= n. Se 2i > n, ento tem filho esquerda. 3) O filho direita de i est em 2i+1. Se 2i+1 <= n. Se 2i+1 > n, ento tem filho direita.

Observao: Representao por Contigidade Fsica no um modo conveniente para representar rvores, na maioria dos casos. Vantagens Adequado para rvores binrias completas. til para o armazenamento em disco ou fita (seqencial).

154

Desvantagem A estrutura pode ter muitos espaos sem uso. Estrutura possui limite finito no nmero de nodos.

7.3.2 Representao por Encadeamento

esq: endereo do nodo filho esquerda info: contm a informao do nodo dir: endereo do nodo filho direita

typedef char TDados; typedef struct TNodo { struct TNodo *esq; TDados info; struct TNodo *dir; }; typedef struct { TNodo *raiz; } TArvore; TArvore *a;

155

7.4 Caminhamento em rvores


Consiste em processar de forma sistemtica e ordenada cada n da rvore apenas uma vez, obtendo assim uma seqncia linear de ns. Abaixo so mostrados os trs tipos de caminhamentos: 7.4.1 Caminhamento Pr-Fixado (Pr-Ordem) 1) Visitar a raiz; 2) Caminhar na sub-rvore da esquerda; 3) Caminhar na sub-rvore a direita.
Observao: Visitar significa qualquer operao em relao informao (info) do nodo.

Exemplo:

Caminhamento: ABDECFG 7.4.2 Caminhamento In-Fixado (Central) 1) Caminhar na sub-rvore da esquerda; 2) Visitar a raiz; 3) Caminhar na sub-rvore da direita. Exemplo: Conforme exemplo acima, o caminhamento In-Fixado :

Caminhamento: DBEACGF
156

7.4.3 Caminhamento Ps-Fixado 1) Caminhar na subrvore da esquerda; 2) Caminhar na subrvore da direita; 3) Visitar a raiz. Exemplo: Conforme exemplo acima, o caminhamento Ps-Fixado :

Caminhamento: DEBGFCA 7.4.4 Algoritmos recursivos para percorrer rvores Binrias Algoritmos de busca de dados em estruturas hierrquicas, caminhamentos em rvores, por exemplo, utilizam, normalmente, recursividade. Recursividade uma tcnica utilizada em programao quando se deseja que uma funo faa uma chamada a si prpria. Este mecanismo utiliza uma estrutura de pilha para fazer o controle do retorno de todas as chamadas realizadas. Como vantagens das funes recursivas tem-se: a) clareza na interpretao do cdigo (funes pequenas); b) simplicidade e elegncia na implementao. Como desvantagens tem-se: a) dificuldade para encontrar erros (debug); b) dificuldade de encontrar o critrio de parada da funo; c) em alguns casos podem ser ineficientes devido a quantidade de chamadas recursivas.

157

A chamada de uma funo recursiva requer espao para os parmetros, variveis locais e endereo de retorno. Todas estas informaes so armazenadas em uma pilha e depois desalocadas, ou seja, a quantidade de informaes proporcional ao nmero de chamadas. Todas as operaes envolvidas na recursividade contribuem para um gasto maior de tempo, pois a alocao e liberao de memria consomem tempo. 7.4.4.1 Caminhamento Pr-Fixado (Pr-Ordem)
void Caminhamento_Pre_Ordem(TArvore *a) { if (!Vazia(a)) { printf("%c ", a->info); // mostra raiz Caminhamento_Pre_Ordem(a->esq); // mostra sub_esq Caminhamento_Pre_Ordem(a->dir); // mostra sub_dir } }

7.4.4.2 Caminhamento In-Fixado (Central)


void Caminhamento_In_Fixado(TArvore *a) { if (!Vazia(a)) { Caminhamento_In_Fixado(a->esq); // mostra sub_esq printf("%c ", a->info); // mostra raiz Caminhamento_In_Fixado(a->dir); // mostra sub_dir } }

7.4.4.3 Caminhamento Ps-Fixado


void Caminhamento_Pos_Fixado(TArvore *a) { if (!Vazia(a)) { Caminhamento_Pos_Fixado(a->esq); // mostra sub_esq Caminhamento_Pos_Fixado(a->dir); // mostra sub_dir printf("%c ", a->info); // mostra raiz } }

34) Escreva um programa em C que cria a rvore da pgina 137. O programa deve exibir na tela os trs tipos de caminhamentos. Soluo do problema proposto (34):
158

// tree.c // Compilador: Dev-C++ 4.9.9.2 #include <stdio.h> typedef char TDados; typedef struct Nodo { struct Nodo *esq; TDados info; struct Nodo *dir; } TNodo; typedef TNodo TArvore; // --------------------------------------------- Cria TArvore *Cria(TArvore *esq, TDados info, TArvore* dir) { TArvore *p; p = (TArvore*) malloc(sizeof(TArvore)); if (p == NULL) { printf("ERRO FATAL: Falta de Memria\n"); getchar(); exit(0); } else { p->info = info; p->esq = esq; p->dir = dir; } return p; } // --------------------------------------------- Vazia int Vazia(TArvore *a) { if (a == NULL) return(1); else return(0); } // --------------------------------------------- Caminhamento_Pre_Ordem

159

void Caminhamento_Pre_Ordem(TArvore *a) { if (!Vazia(a)) { printf("%c ", a->info); // mostra raiz Caminhamento_Pre_Ordem(a->esq); // mostra sub_esq Caminhamento_Pre_Ordem(a->dir); // mostra sub_dir } } // --------------------------------------------- Caminhamento_In_Fixado void Caminhamento_In_Fixado(TArvore *a) { if (!Vazia(a)) { Caminhamento_In_Fixado(a->esq); // mostra sub_esq printf("%c ", a->info); // mostra raiz Caminhamento_In_Fixado(a->dir); // mostra sub_dir } } // --------------------------------------------- Caminhamento_Pos_Fixado void Caminhamento_Pos_Fixado(TArvore *a) { if (!Vazia(a)) { Caminhamento_Pos_Fixado(a->esq); // mostra sub_esq Caminhamento_Pos_Fixado(a->dir); // mostra sub_dir printf("%c ", a->info); // mostra raiz } } // --------------------------------------------- Destroi TArvore *Destroi(TArvore *a) { if (!Vazia(a)) { Destroi(a->esq); // libera sub_esq Destroi(a->dir); // libera sub_dir free(a); // libera raiz } return(NULL); } // --------------------------------------------- Programa Principal int main(void) { 160

TArvore *a,*a1,*a2,*a3,*a4,*a5,*a6; system(cls); a1 = Cria(NULL,'d',NULL); a2 = Cria(NULL,'e',NULL); a3 = Cria(a1,'b',a2); a4 = Cria(NULL,'g',NULL); a5 = Cria(a4,'f',NULL); a6 = Cria(NULL,'c',a5); a = Cria(a3,'a',a6); printf("Caminhamentos na rvore\n\n Pr-Ordem: "); Caminhamento_Pre_Ordem(a); printf("\n In-Fixado: "); Caminhamento_In_Fixado(a); printf("\nPs-Fixado: "); Caminhamento_Pos_Fixado(a); system(pause); return(0); }

Resultado do Programa: Caminhamentos na rvore Pr-Ordem: a b d e c f g In-Fixado: d b e a c g f Ps-Fixado: d e b g f c a

35) Escreva um programa em C que Insere (ordenado), Exclui e exibe na tela os trs tipos de caminhamentos na rvore criada. Soluo do problema proposto (35):
// // // // // arvore.c Autor: Ricardo Andrade Cava Adaptao: Paulo Roberto Gomes Luzzardi Data: 16/09/2005 Compilador: Dev-C++ 4.9.9.2

#include <stdio.h>

161

#include <string.h> #include <stdlib.h> // ------------------------------------ defines #define SUCESSO #define FALTA_DE_MEMORIA #define INFO_NAO_EXISTE 0 1 2

// ------------------------------------ Definio de Tipos typedef int TDados; typedef struct Nodo { struct Nodo *ptesq; TDados info; struct Nodo *ptdir; } TNodo; typedef struct { TNodo *raiz; } TArvore; // ------------------------------------ Prototypes int Inclui(TArvore *a,TDados info); int Inclui_Recursivo(TNodo **ptnodo,TDados info); int Exclui(TArvore *a,int info); int Exclui_Recursivo(TNodo **ptnodo,int info); TNodo **Procura_Maior(TNodo **ptnodo); void Cria_Arvore(TArvore *a); void Pre_Ordem(TArvore a); void Pre_Ordem_Recursivo (TNodo *ptnodo); void Em_Ordem(TArvore a); void Em_Ordem_Recursivo (TNodo *ptnodo); void Pos_Ordem(TArvore a); void Pos_Ordem_Recursivo (TNodo *ptnodo); // ------------------------------------ Programa Principal int main(void) { TArvore a; TDados info; char tecla,op; system(cls); Cria_Arvore(&a); do { printf("[I]ncluir\n"); printf("[E]xcluir\n"); 162

printf("[C]aminha\n"); printf("[F]im\n"); printf("\nQual a sua Opo? "); do { tecla = getchar(); } while (!strchr("IiEeCcFf",tecla)); printf("%c\n",tecla); switch (tecla) { case 'I': case 'i': printf("\nInformao: "); scanf("%d",&info); Inclui (&a,info); break; case 'E': case 'e': printf("\nInformao: "); scanf("%d",&info); if (Exclui (&a,info)== INFO_NAO_EXISTE) printf("ERRO: Informao Inexistente\n"); break; case 'C': case 'c': printf("[1] Pr-fixado\n"); printf("[2] In-fixado\n"); printf("[3] Ps-fixado\n"); printf("\nQual o Caminhamento? "); do { op = getchar(); } while (!strchr("123",op)); printf("%c\n",tecla); switch (op) { case '1': printf("\nCaminhamento Pr-Ordem: "); Pre_Ordem(a); printf("\n\n"); break; case '2': printf("\nCaminhamento Em-Ordem: "); Em_Ordem(a); printf("\n\n"); break; case '3': printf("\nCaminhamento Ps-Ordem: "); Pos_Ordem(a); printf("\n\n"); break; } break; } } while (!strchr("Ff",tecla)); } // ------------------------------------ Cria_Arvore

163

void Cria_Arvore (TArvore *a) { a->raiz = NULL; } // ------------------------------------ Inclui int Inclui(TArvore *a, TDados info) { return(Inclui_Recursivo(&(a->raiz),info)); } // ------------------------------------ Inclui_Recursivo int Inclui_Recursivo (TNodo **ptnodo, TDados info) { TNodo *p; if (*ptnodo == NULL) { p = (TNodo *) malloc (sizeof(TNodo)); if (p == NULL) return(FALTA_DE_MEMORIA); else { p->ptesq = NULL; p->ptdir = NULL; p->info = info; *ptnodo = p; return SUCESSO; } } else if (info < (*ptnodo)->info) return(Inclui_Recursivo(&((*ptnodo)->ptesq),info)); else return(Inclui_Recursivo(&((*ptnodo)->ptdir),info)); } // ------------------------------------ Exclui int Exclui(TArvore *a, int info) { return(Exclui_Recursivo( &(a->raiz),info)); } // ------------------------------------ Exclui_Recursivo int Exclui_Recursivo (TNodo **ptnodo, TDados info) { TNodo *p,**aux; 164

if (*ptnodo == NULL) return(INFO_NAO_EXISTE); else if ( info < (*ptnodo)->info) return(Exclui_Recursivo (&((*ptnodo)->ptesq),info)); else if (info > (*ptnodo)->info) return(Exclui_Recursivo (&((*ptnodo)->ptdir),info)); else { if ((*ptnodo)->ptesq == NULL) if ((*ptnodo)->ptdir == NULL) { free ( *ptnodo); *ptnodo = NULL; } else { p = *ptnodo; *ptnodo = (*ptnodo)->ptdir; free(p); } else if ((*ptnodo)->ptdir == NULL) { p = *ptnodo; *ptnodo = (*ptnodo)->ptesq; free(p); } else { aux = Procura_Maior( &(*ptnodo)->ptesq); (*ptnodo)->info = (*aux)->info; return(Exclui_Recursivo(aux,(*aux)->info)); } return SUCESSO; } } // ------------------------------------ Procura_Maior TNodo **Procura_Maior(TNodo **ptnodo) { if ((*ptnodo)->ptdir == NULL) return(ptnodo); else return(Procura_Maior(&(*ptnodo)->ptdir)); } // ------------------------------------ Pre_Ordem 165

void Pre_Ordem(TArvore a) { Pre_Ordem_Recursivo(a.raiz); } // ------------------------------------ Pre_Ordem_Recursivo void Pre_Ordem_Recursivo (TNodo *ptnodo) { if (ptnodo != NULL) { printf("%d ",ptnodo->info); Pre_Ordem_Recursivo(ptnodo->ptesq); Pre_Ordem_Recursivo(ptnodo->ptdir); } } // ------------------------------------ Em_Ordem void Em_Ordem(TArvore a) { Em_Ordem_Recursivo(a.raiz); } // ------------------------------------ Em_Ordem_Recursivo void Em_Ordem_Recursivo(TNodo *ptnodo) { if (ptnodo != NULL) { Em_Ordem_Recursivo(ptnodo->ptesq); printf("%d ",ptnodo->info); Em_Ordem_Recursivo(ptnodo->ptdir); } } // ------------------------------------ Pos_Ordem void Pos_Ordem(TArvore a) { Pos_Ordem_Recursivo(a.raiz); } // ------------------------------------ Pos_Ordem_Recursivo void Pos_Ordem_Recursivo (TNodo *ptnodo) { if (ptnodo != NULL) { Pos_Ordem_Recursivo(ptnodo->ptesq); 166

Pos_Ordem_Recursivo(ptnodo->ptdir); printf("%d ",ptnodo->info); } }

7.5 rvore de Busca Binria


Uma rvore de busca binria (BST - Binary Search Tree) uma rvore binria cujas chaves (informaes ou dados) aparecem em ordem crescente quando a rvore percorrida em ordem in-Fixado (esquerda -> raiz -> direita, ou seja, caminhamento ERD). Onde a chave de cada n da rvore deve ser: maior ou igual que qualquer chave na sua sub-rvore esquerda; menor ou igual que qualquer chave na sua sub-rvore direita.

Em outras palavras, a ordem esquerda-raiz-direita das chaves deve ser crescente. 36) Escreva um programa em C que cria a rvore binria ordenada (a, b, c, d, e, f, g). O programa deve permitir ao usurio buscar o endereo de uma determinada informao, ou seja, uma letra de a at z. Soluo do problema proposto (36):
// busca.c // Compilador: Dev-C++ 4.9.9.2 #include <stdio.h> #define ESC 27 typedef char TDados; typedef struct Nodo { struct Nodo *esq; TDados info; struct Nodo *dir; } TNodo; typedef TNodo TArvore; // --------------------------------------------- Cria

167

TArvore *Cria(TArvore *esq, TDados info, TArvore* dir) { TArvore *p; p = (TArvore*) malloc(sizeof(TArvore)); if (p == NULL) { printf("ERRO FATAL: Falta de Memria\n"); getchar(); exit(0); } else { p->info = info; p->esq = esq; p->dir = dir; } return p; } // --------------------------------------------- Vazia int Vazia(TArvore *a) { if (a == NULL) return(1); else return(0); } // --------------------------------------------- Caminhamento_In_Fixado void Caminhamento_In_Fixado(TArvore *a) { if (!Vazia(a)) { Caminhamento_In_Fixado(a->esq); printf("\nEndereo: %p - Info: %c", a, a->info); Caminhamento_In_Fixado(a->dir); } } // --------------------------------------------- Destroi TArvore *Destroi(TArvore *a) { if (!Vazia(a)) { Destroi(a->esq); Destroi(a->dir); 168

free(a); } return(NULL); } // --------------------------------------------- Busca TArvore *Busca(TArvore *raiz, TDados chave) { TArvore *a1; if (raiz == NULL) return(NULL); else if (raiz->info == chave) // busca na raiz return(raiz); else { a1 = Busca(raiz->esq,chave); // busca na sub-rvore esquerda if (a1 == NULL) a1 = Busca(raiz->dir,chave); // busca na sub-rvore direita return(a1); } } // --------------------------------------------- Programa Principal int main(void) { TArvore *a,*a1,*a2,*a3,*a4,*a5,*a6,*arv; TDados info; system(cls); a1 = Cria(NULL,'a',NULL); a2 = Cria(NULL,'c',NULL); a3 = Cria(a1,'b',a2); a4 = Cria(NULL,'e',NULL); a5 = Cria(NULL,'g',NULL); a6 = Cria(a4,'f',a5); a = Cria(a3,'d',a6); printf("\nCaminhamento In-Fixado: "); Caminhamento_In_Fixado(a); printf("\nESC - Abandona"); do { printf("\nInfo: "); do { info = getchar(); } while (!(info >= 'a' && info <= 'z') && info != ESC); if (info != ESC) { arv = Busca(a,info); 169

printf("\nEndereo do Nodo [%c]: %p", info, arv); } } while (info != ESC); return(0); }

7.6 rvore AVL


O objetivo principal na utilizao de rvores AVL diminuir o custo de acesso as informaes desejadas, ou seja, organizar a rvore de forma a otimizar a busca em uma rvore binria. Os algoritmos de rvore AVL so muito parecidos com os algoritmos de uma rvore binria, a diferena est no esforo necessrio para se manter uma rvore AVL balanceada. Para manter uma rvore balanceada, precisa-se constantemente refazer a estrutura da rvore nas operaes de insero ou excluso de elementos. rvores AVL, B e B++ so rvores balanceadas. Balanceamento em rvores Diz-se que uma rvore est balanceada (equilibrada), se todos os ns folhas esto mesma distncia da raiz, ou seja, uma rvore dita balanceada quando as suas sub-rvores esquerda e direita possuem a mesma altura. Quando uma rvore no est balanceada, chama-se degenerada.

O balanceamento de uma rvore binria pode ser: esttico ou dinnico (AVL). O balanceamento esttico de uma rvore binria consiste em construir uma nova verso da rvore, reorganizando-a, enquanto que no balanceamento dinmico (AVL) a cada nova operao realizada na rvore binria, ela sobre rotaes deixando-a balanceada. O termo AVL foi colocado em homenagem aos matemticos russos Adelson-Velskii e Landis.

170

Adelson-Velskii e Landis em 1962 apresentaram uma rvore de busca binria que balanceada levando-se em considerao a altura das suas sub-rvores, ou seja, uma rvore AVL uma rvore binria de pesquisa onde a diferena em altura entre as sub-rvores esquerda e direita no mximo 1 (positivo ou negativo). Est diferena chamado de fator de balanceamento (fb). Este fator deve ser calculado para todos os ns da rvore binria. O fator de balanceamento de um n folha sempre zero, ou seja, fb = 0. O fator de balanceamento (fb) um nmero inteiro igual a: fb (nodo) = altura (subrvore direita) altura (subrvore esquerda); Definio: Uma rvore binria vazia sempre balanceada por altura. Se T no vazia e Te e Td so sub-rvores da esquerda e direita, respectivamente, ento T balanceada por altura se: a) Te e Td so balanceadas por altura; b) altura Te altura Td for igual a 0, 1 ou -1. 7.6.1 Insero em uma rvore AVL Quando um novo elemento inserido em uma rvore binria, necessrio verificar se esta insero quebrou a propriedade de balanceamento da rvore, ou seja, necessrio calcular o fator de balanceamento dos nodos da rvore. Se o Fb de algum nodo for diferente de 0, 1 ou -1, necessrio reestruturar a rvore para que volte a ser balanceada. Na insero de um nodo em uma rvore AVL, pode-se ter quatro situaes distintas, cuja a forma de tratamento diferente: a) Insero dos ns: 10, 20 e 30

b) Insero dos ns: 30, 20 e 10

171

c) Insero dos ns: 10, 30 e 20

d) Insero dos ns: 30, 10 e 20

Note que nas quatro situaes acima (a, b, c e d), o fator de balanceamento de algum nodo ficou fora da faixa [-1..1], ou seja, algum nodo teve o Fator de Balanceamento (Fb) 2 ou -2. Para cada caso acima, aplica-se um tipo de rotao a rvore: a) Rotao simples esquerda

172

b) Rotao simples direita

c) Rotao dupla esquerda

(rotao simples direita + rotao simples esquerda)

d) Rotao dupla direita

(rotao simples esquerda + rotao simples direita)

Dicas: a) Para identificar quando uma rotao simples ou dupla deve-se observar os sinais do Fb:
173

Sinal for igual, a rotao simples Sinal for diferente a rotao dupla b) Se Fb for positivo (+) a rotao para esquerda c) Se Fb for negativa (-) a rotao para direita 37) Escreva um programa em C que cria uma rvore binria balanceada utilizando as caractersticas de uma rvore AVL (10, 20, 30, 40, ...). O programa deve permitir a entrada de nmeros inteiros at que o usurio digite zero (0). Ao final a rvore exibida. Soluo do problema proposto (37):
// avl.c #include <stdio.h> #include <stdlib.h> #define TRUE !0 #define FALSE 0 typedef int TDados; typedef struct nodo { TDados chave; struct nodo *esq,*dir; int bal; }*TNodo; // ------------------------------------ Procura_AVL int Procura_AVL(int x, TNodo *p) { TNodo pDeTNodo; pDeTNodo = (*p); if (!pDeTNodo) return(FALSE); else if (x<pDeTNodo->chave) return(Procura_AVL(x, &pDeTNodo->esq)); else if (x>pDeTNodo->chave) return(Procura_AVL(x, &pDeTNodo->dir)); else return(TRUE); } // ------------------------------------ Insere_AVL

174

int Insere_AVL(int x, TNodo *t, int *h) { TNodo p, q, pDeTNodo; pDeTNodo = (*t); if (!pDeTNodo) { pDeTNodo = (TNodo) malloc(sizeof (struct nodo)); if (pDeTNodo == NULL) abort(); *t = pDeTNodo; *h = TRUE; pDeTNodo->chave = x; pDeTNodo->esq = NULL; pDeTNodo->dir = NULL; pDeTNodo->bal = 0; return(TRUE); } else if (x<pDeTNodo->chave) { if (!Insere_AVL(x, &pDeTNodo->esq, h)) return(FALSE); if (*h) switch(pDeTNodo->bal) { case 1: pDeTNodo->bal = 0; *h = FALSE; break; case 0: pDeTNodo->bal = (-1); break; case -1: p = pDeTNodo->esq; if (p->bal == (-1)) { // Rotao Simples pDeTNodo->esq = p->dir; p->dir = pDeTNodo; pDeTNodo->bal = 0; pDeTNodo = p; *t = pDeTNodo; } else { // Rotao Dupla q = p->dir; p->dir = q->esq; q->esq = p; pDeTNodo->esq = q->dir; q->dir = pDeTNodo; pDeTNodo->bal = (q->bal == (-1)) ? 1 : 0; p->bal = (q->bal == 1) ? (-1) : 0; pDeTNodo = q; 175

*t = pDeTNodo; } pDeTNodo->bal = 0; *h = FALSE; break; } return(TRUE); } else if (x>pDeTNodo->chave) { if (!Insere_AVL(x, &pDeTNodo->dir, h)) return(FALSE); if (*h) switch(pDeTNodo->bal) { case -1: pDeTNodo->bal = 0; *h = FALSE; break; case 0: pDeTNodo->bal = 1; break; case 1: p=pDeTNodo->dir; if (p->bal == 1) { // Rotao Simples pDeTNodo->dir = p->esq; p->esq = pDeTNodo; pDeTNodo->bal = 0; pDeTNodo = p; *t = pDeTNodo; } else { // Rotao Dupla q = p->esq; p->esq = q->dir; q->dir = p; pDeTNodo->dir = q->esq; q->esq = pDeTNodo; pDeTNodo->bal = (q->bal == 1) ? (-1) : 0; p->bal = (q->bal == (-1)) ? 1 : 0; pDeTNodo = q; *t = pDeTNodo; } pDeTNodo->bal = 0; *h = FALSE; break; } return(TRUE); } else { *h = FALSE; 176

return(FALSE); } } // ------------------------------------ Exibe_AVL void Exibe_AVL(TNodo pt,int indent) { int i; if (pt) { Exibe_AVL(pt->dir, indent+1); for (i = 0;i < indent;i++) printf(" "); printf("%d (%d)\n",pt->chave, pt->bal); Exibe_AVL(pt->esq, indent+1); } } // ------------------------------------ main int main(void) { TNodo raiz; int chave, dh; system("cls"); printf("rvore AVL (0 - Sair)\n\n"); raiz = NULL; do { printf("Chave: "); scanf("%d", &chave); if (chave != 0) { if (!Insere_AVL(chave, &raiz, &dh)) printf("ERRO: Chave Repetida\n"); if (!Procura_AVL(chave, &raiz)) printf("ERRO: Chave Perdida\n"); } } while (chave != 0); printf("\nRVORE AVL\n\n"); Exibe_AVL(raiz,0); printf("\n"); system("pause"); } Programa online que demonstra inseres e remoes em uma rvore AVL: http://www.site.uottawa.ca/~stan/csi2514/applets/avl/BT.html

177

7.6.2 Remoo em uma rvore AVL Quando um elemento removido de uma rvore balanceada AVL, necessrio verificar se esta operao quebrou a propriedade de balanceamento da rvore, ou seja, necessrio calcular o Fator de Balanceamento dos nodos da rvore. Se o Fb de algum nodo for diferente de 0, 1 ou -1, necessrio reestruturar a rvore para que volte a ser balanceada. Na remoo de um nodo em uma rvore AVL, pode-se ter quatro situaes distintas, cuja a forma de tratamento diferente: a) Remoo do n: 10

Resultado: Com a remoo do nodo 10 a rvore ficar desbalanceada, pois o nodo raiz ficar com Fb = 2. A soluo ser fazer uma rotao simples esquerda. b) Remoo do n: 40

Resultado: Com a remoo do nodo 40 a rvore ficar desbalanceada, pois o nodo raiz ficar com Fb = -2. A soluo ser fazer uma rotao simples direita.

178

c) Remoo do n: 10

Resultado: Com a remoo do nodo 10 a rvore ficar desbalanceada, pois o nodo raiz ficar com Fb = 2. A soluo ser fazer uma rotao dupla esquerda (rotao simples direita + rotao simples esquerda). d) Remoo do n: 40

Resultado: Com a remoo do nodo 40 a rvore ficar desbalanceada, pois o nodo raiz ficar com Fb = 2. A soluo ser fazer uma rotao dupla direita (rotao simples esquerda + rotao simples direita).

179

8. Grafos
8.1 Conceitos Um grafo G definido como G (V, A) onde V um conjunto finito e no vazio de vrtices e A um conjunto finito de arestas, ou seja, linhas, curvas ou setas que interligam dois vrtices. Grafo um par ordenado de conjuntos disjuntos (V, A), onde V um conjunto arbitrrio que se designa por conjunto dos vrtices e A um subconjunto de pares no ordenados de elementos (distintos) de V que se designa por conjunto das arestas. Um vrtice representado por um ponto ou crculo representando um n, nodo ou informao. Uma aresta pode ser uma reta, seta ou arco representando uma relao entre dois nodos.

Quando uma aresta possui indicao de sentido (uma seta), ela chamada de arco, caso contrrio chamada de linha (veja grafo acima). Orientao a direo para a qual uma seta aponta, um grafo deste tipo chamado grafo dirigido ou orientado.

180

G(4,7) 4 vrtices e 7 arestas

Cardinalidade (ordem) de um conjunto de vrtices igual a quantidade de seus elementos. Grafo denso possui alta cardinalidade de vrtices, enquanto que grafo pouco povoado possui baixa cardinalidade. A ordem (V) de um grafo G o nmero de vrtices do grafo enquanto que a dimenso (A) o nmero de arestas do grafo. No exemplo acima, a ordem do grafo 4 enquanto que a dimenso 7.

O conjunto de arcos do grafo acima :


{<A,A>, <A,B>, <A,C>, <A,D>, <C,D>, <F,C>, <F,G>, <D,F>}
1 2 3 4 5 6 7 8

Um vrtice que no possui nenhuma aresta incidente chamado de isolado (figura abaixo). Um grafo com nenhum vrtice chamado de vazio.

181

Passeio uma seqncia de vrtices e arestas onde o caminho um passeio sem vrtices repetidos (seqncia de vrtices em que cada dois vrtices consecutivos so ligados por um arco). Trajeto um passeio sem arestas repetidas. Passeio uma seqncia <v0, a1, v1, a2, ..., vk-1, ak, vk> onde v0, v1,....,vk so vrtices, a1, a2,...., ak so arcos e, para cada (i, ai) um arco de vi-1 a vi. O vrtice v0 o incio do passeio e o vrtice vk o seu trmino. Um caminho um passeio sem vrtices repetidos. A dimenso de um caminho ou trajeto chamado de comprimento. Ciclo um caminho de comprimento no nulo fechado, ou seja, tem os vrtices extremos iguais ( um passeio onde v0 = vk.). Circuito um trajeto de comprimento no nulo fechado ( um ciclo sem vrtices, com exceo feita a v0 e vk). Lao uma aresta que retorna ao mesmo vrtice. Se a aresta no tiver seta ela dita sem orientao. Diz-se que uma aresta incidente com os vrtices que ela liga, no importando a orientao. Dois vrtices so adjacentes se esto ligados por uma aresta. Um vrtice dito isolado se no existe aresta incidente sobre ele. Duas arestas incidentes nos mesmos vrtices, no importando a orientao, a1 = (v,w) e a2 = (v,w), ento as arestas so paralelas.

182

Diz-se que o grafo conexo se para cada par de vrtices existe pelo menos um passeio que os une. Chama-se grafo no-orientado ou no-dirigido se as arestas representam relacionamento nas duas direes, ou seja, as arestas no possuem uma seta indicando sentido.

Grafo no-orientado ou no-dirigido

V = { Paulo, Adriane, Paola, Roberta } A = { (Paulo, Adriane) , (Paulo, Paola) , (Adriane, Paola) , (Adriane, Roberta) }

Explicao do grafo acima: O exemplo representa uma relao de amizade, ou seja, se Paulo amigo de Adriane o inverso verdade, isto se chama: relao simtrica. Quando um grafo possui arcos (seta indicando uma direo) ele denominado grafo dirigido ou dgrafo (veja prxima figura).

Grafo dirigido ou dgrafo

183

Explicao do grafo acima: O exemplo representa uma relao de subordinao, ou seja, se Paulo chefe de Adriane o inverso no verdade, isto se chama: relao no-simtrica. Grau de um vrtice, em um grafo no-dirigido, o nmero de arestas incidentes ao vrtice. Em um grafo dirigido, pode-se dividir o grau em dois: grau de emisso (nmero de arestas que saem do vrtice) e grau de recepo (nmero de arestas que chegam no vrtice). Toda rvore um grafo, mas nem todo grafo uma rvore. Um grafo onde existe um nmero associado a cada arco (peso) chamado de rede ou grafo ponderado. Um exemplo deste tipo um grafo representando cidades e distncias entre as cidades (veja figura abaixo).

Grau de um Vrtice: igual ao nmero de arestas que so incidentes ao vrtice. Um lao contado duas vezes.

No exemplo acima, o vrtice A tem grau 3 enquanto que o vrtice B tem grau 1. Em um grafo dirigido o grau de um vrtice a soma do nmero de arestas que saem e chegam no vrtice.

Tipos de Grafos
a) Simples: um grafo que no possui laos nem arestas paralelas.
184

b) Dirigido (dgrafo ou direcionado): Consiste de dois conjuntos finitos: a) vrtices e b) arestas dirigidas, onde cada aresta associada a um par ordenado de vrtices chamados de ns terminais.

c) Completo: Um grafo completo de n vrtices, denominado Kn, um grafo simples com n vrtices v1, v2, . . . , vn, cujo conjunto de arestas contm exatamente uma aresta para cada par de vrtices distintos.

d) Ciclo: Um grafo ciclo de n vrtices, denominado Cn, onde n maior ou igual a 3, um grafo simples com n vrtices v1, v2, . . . , vn, e arestas v1v2, v2v3, . . ., vn1vn, vnv1.

185

e) Multigrafo: um grafo que no possui laos, mas pode ter arestas paralelas.

f) Valorado: um grafo em que cada aresta tem um valor associado (peso), ou seja, possui um conjunto de valores (pesos) associados a cada aresta.

g) Planar: um grafo onde no h cruzamento de arestas.

h) Imersvel: Um grafo imersvel em uma superfcie S se puder ser representado geograficamente em S de tal forma que arestas se cruzem nas extremidades (vrtices). Um grafo planar um grafo que imersvel no plano. Um exemplo de grafo imersvel a representao das conexes de uma placa de circuito impresso, onde as arestas no
186

podem se cruzar, ou seja, os cruzamentos so permitidos apenas nas extremidades. i) Regular: Um grafo regular quando todos os seus vrtices tm o mesmo grau. Grafos completos com 2, 3, 4, e 5 vrtices so grafos regulares.

Grafos podem ser representados de duas formas: Matriz de Adjacncias (forma apropriada para representar grafos densos) ou Lista de Adjacncias (forma apropriada para representar grafos esparsos). 8.2 Representao por Lista e Matriz de Adjacncias 8.2.1 Lista de Adjacncias Um grafo pode ser representado por uma lista Adjacente[vi] = [va, vb] onde va, vb, ... representam os vrtices que se relacionam com o vrtice vi. Lista de Adjacncias para um grafo dirigido:

Lista de Adjacncias para um grafo no-dirigido:

187

8.2.2 Matriz de Adjacncias Um grafo pode ser representado por uma matriz A = (aij), onde aij representa o nmero de arestas de vi para vj. Matriz de Adjacncias para um grafo dirigido:

Matriz de Adjacncias para um grafo no-dirigido:

188

8.3 Percurso em Amplitude e Percurso em Profundidade Existem dois critrios para percorrer grafos: Percurso em Amplitude e Percurso em Profundidade. Em ambos os percursos parte-se de um nodo qualquer escolhido arbitrariamente e visita-se este nodo. A seguir, considera-se cada um dos nodos adjacentes ao nodo escolhido. Percurso em amplitude ou caminhamento em amplitude: a) Seleciona-se um vrtice para iniciar o caminhamento. b) Visitam-se os vrtices adjacentes, marcando-os como visitados. c) Coloca-se cada vrtice adjacente numa fila. d) Aps visitar os vrtices adjacentes, o primeiro da fila torna-se o novo vrtice inicial. Reinicia-se o processo. e) O caminhamento termina quanto todos os vrtices tiverem sido visitados ou o vrtice procurado for encontrado. Percurso em profundidade ou caminhamento em profundidade: a) Seleciona-se um vrtice para iniciar o caminhamento. b) Visita-se um primeiro vrtice adjacente, marcando-o como visitado. c) Coloca-se o vrtice adjacente visitado numa pilha. d) O vrtice visitado torna-se o novo vrtice inicial. e) Repete-se o processo at que o vrtice procurado seja encontrado ou no haja mais vrtices adjacentes. Se verdadeiro, desempilha-se o topo e procura-se o prximo adjacente, repetindo o algoritmo. f) O processo termina quando o vrtice procurado for encontrado ou quando a pilha estiver vazia e todos os vrtices tiverem sido visitados. 8.4 Determinao do Caminho Mnimo O caminho de um vrtice a outro vrtice mnimo se no existe outro caminho entre eles que tenha menos arcos. O problema de encontrar o caminho mais curto entre dois ns de um grafo ou uma rede um dos problemas clssicos da Cincia da Computao. Este problema consiste, genericamente, em encontrar o caminho de menor custo entre dois ns da rede, considerando a soma dos custos associados aos arcos percorridos.

189

O mais famoso algoritmo para resolver o problema de caminho mnimo em grafos o algoritmo de Dijkstra (1959). Este algoritmo apenas funciona se os custos associados aos arcos no forem negativos, mas isso no muito importante na maioria dos problemas prticos pois, em geral, os custos associados aos arcos so em geral grandezas fisicamente mensurveis. Algoritmo de Dijkstra Dado um grafo, G=(V,E) , dirigido ou no, com valores no negativos em cada arco ou ramo, utiliza-se o algoritmo de Dijkstra para encontrar a distncia mnima entre um vrtice inicial (s) e um vrtice final (v). Ele determina a distncia mnima entre s e os outros vrtices na ordem dessas distncias mnimas, ou seja, os vrtices que se encontram mais prximos de s em primeiro lugar. O algoritmo vai usar dist(v), uma estrutura que armazena e referencia a distncia de s ao n v. De incio, dist(s)=0 , pois a menor distncia de s a si mesmo ser sempre zero. O smbolo LIMITE representa um valor maior que o comprimento de qualquer caminho sem ciclos em G. Por outro lado, se dist(v) = LIMITE, indica que ainda no foi encontrado nenhum caminho com distncia mnima entre s e v. De incio, dist(v) = LIMITE. Ser utilizado um conjunto S que contm os vrtices cuja distncia a s mnima e conhecida naquele momento da execuo do algoritmo. Esta distncia ser definitiva para cada um deles. Este conjunto ser de incio constitudo somente pelo n s, com dist(s) = 0. Descrio do Algoritmo Comea-se considerando a distncia ao prprio s como zero. Faze-se ento dist(s)= 0. Para todos os outros vrtices, considera-se a sua distncia a s como valendo LIMITE. Fazer ento dist(v) = LIMITE. O processo de introduo de um n Vn no pertencente a S, assumindo portanto que V(S) diferente do conjunto vazio, consiste no seguinte: 1. Qualquer um que seja Vm no pertencente a S tal que v foi o ltimo n a 'entrar' em S e (V, Vm) pertencente ao conjunto V, se dist(Vm) >
190

dist(V) + distncia associada a (V,Vm) ento dist(Vm) = dist(V) + distncia associada a (V, Vm); 2. Determinar qualquer que seja Vm no pertencente a S o menor de entre os valores de dist(vm). Seja dist(vj) esse valor; 3. Fazer Vn = Vj , dist(Vn) = dist(Vj) e Vn passa a ser o novo elemento de S; Se o vrtice vn coincidir com o vrtice final ento dist(Vn) a menor distncia entre s e Vn , e parar a execuo. Se no coincidir, voltam-se a repetir os passos 1 , 2 e 3. Se no for possvel aplicar aqueles passos, ou porque V(S) igual ao conjunto vazio ou qualquer que seja Vm no pertencente a S ento (V, Vm) no pertence ao conjunto V, ento no possvel determinar a distncia mnima de s ao vrtice final. 38) Escreva um programa em C que cria um grafo representando a ligao entre seis cidades com suas respectivas distncias (So Paulo, Rio de Janeiro, Vitria, Recife, Salvador e Natal). O programa deve permitir a entrada da cidade origem (0..5) e da cidade destino (0..5) e exibir o caminho mnimo entre estas duas cidades atravs da utilizao do algoritmo de Dijkstra.

Soluo do problema proposto (38):


// Dijkstra.c

191

#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_VERTICES 6 #define LIMITE 32767 #define TRUE !0 #define FALSE 0 typedef struct { char adj; int valor; } Tinfo; // ------------------------------------ newline void newline(void) { printf("\n"); } // ------------------------------------ Inicializa_Grafo void Inicializa_Grafo(Tinfo grafo[][MAX_VERTICES]) { int l, c; for (l = 0; l < MAX_VERTICES; l++) for (c = 0; c < MAX_VERTICES; c++) { grafo[l][c].valor = LIMITE; grafo[l][c].adj = 'N'; } } // ------------------------------------ Cria_Aresta void Cria_Aresta(Tinfo grafo[][MAX_VERTICES], int origem, int destino, int info) { grafo[origem][destino].adj = 'S'; grafo[origem][destino].valor = info; grafo[destino][origem].adj = 'S'; grafo[destino][origem].valor = info; } // ------------------------------------ Imprime_Grafo void Imprime_Grafo (Tinfo grafo[][MAX_VERTICES], char Rot[][5]) { int l, c; for (l = 0; l < MAX_VERTICES; l++) printf(" %d", l); newline(); for (l = 0; l < MAX_VERTICES; l++) printf(" %s", Rot[l]); newline(); } // ------------------------------------ Imprime_Matriz void Imprime_Matriz(Tinfo grafo[][MAX_VERTICES])

192

{ int l, c; printf("Matriz de Adjacencias\n"); for (l = 0; l < MAX_VERTICES; l++) { for (c = 0; c < MAX_VERTICES; c++) printf("%5d ",grafo[l][c].valor); newline(); } newline(); } // ------------------------------------ Entrada_Origem_Destino void Entrada_Origem_Destino(int tam, int *origem, int *destino) { printf("\n Origem [0..%d]: ", tam); do { scanf("%d",origem); } while (*origem < 0 || *origem > tam); printf("Destino [0..%d]: ", tam); do { scanf("%d",destino); } while (*destino < 0 || *destino > tam); } // ---------------------------------------------- Dijkstra long int Dijkstra(Tinfo grafo[][MAX_VERTICES], int origem, int destino, int precede[]) { int i, k; int distancia[MAX_VERTICES]; int menor_cam [MAX_VERTICES]; int atual, dc, menordist, novadist; char parar = 'N'; for (i = 0; i < MAX_VERTICES; i++) { distancia[i] = LIMITE; menor_cam [i] = FALSE; precede[i] = -1; } menor_cam [origem] = TRUE; distancia[origem] = 0; atual = origem; k = atual; while (atual != destino && parar == 'N') { menordist = LIMITE; dc = distancia[atual]; for (i = 0; i < MAX_VERTICES; i++) { if (menor_cam [i] == FALSE) { if (grafo[atual][i].adj =='S') novadist = dc + grafo[atual][i].valor; else novadist = grafo[atual][i].valor; if (novadist < distancia[i]) { distancia[i] = novadist; precede[i] = atual; }

193

} return((long) distancia[destino]); }

} if (atual == k) parar = 'S'; else { atual = k; menor_cam [ atual] = FALSE; }

if (distancia[i] < menordist) { menordist = distancia[i]; k = i; } }

// ------------------------------------ Imprime_Cidades void Imprime_Cidades(void) { int i; char cidades[MAX_VERTICES][30] = {"[0] - (Spa) - Sao Paulo", "[1] - (Rio) - Rio de janeiro", "[2] - (Vit) - Vitoria", "[3] - (Rec) - Recife", "[4] - (Sal) - Salvador", "[5] - (Nat) - Natal"}; for (i = 0;i < MAX_VERTICES;i++) printf("%s\n",cidades[i]); newline(); } // ------------------------------------ main int main(void) { Tinfo grafo[MAX_VERTICES][MAX_VERTICES]; int precede[MAX_VERTICES]; char rotulos[MAX_VERTICES][5] = {"Spa", "Rio", "Vit", "Rec", "Sal", "Nat"},tecla; int origem, destino, aux1, aux2; long int result; Inicializa_Grafo(grafo); Cria_Aresta(grafo, 0, 1, 300); Cria_Aresta(grafo, 0, 3, 400); Cria_Aresta(grafo, 0, 4, 100); Cria_Aresta(grafo, 1, 2, 100); Cria_Aresta(grafo, 1, 5, 70); Cria_Aresta(grafo, 2, 3, 50); Cria_Aresta(grafo, 4, 5, 50); Cria_Aresta(grafo, 3, 5, 150); do { system("cls"); Imprime_Matriz(grafo); Imprime_Cidades(); Imprime_Grafo(grafo, rotulos); Entrada_Origem_Destino(MAX_VERTICES-1,&origem, &destino); result = Dijkstra(grafo, origem, destino, precede); if (result == LIMITE || result == 0) printf("\nNao ha trajeto entre %s e %s", rotulos[origem], rotulos[destino]); else {

194

printf("\nMenor caminho entre %s e %s = %ld", rotulos[origem], rotulos[destino], result); printf("\nCaminho INVERSO Percorrido: "); aux1 = precede[destino]; aux2 = destino; while (aux1 != origem) { printf("\n %s -> %s (%d)", rotulos[aux1], rotulos[aux2], grafo[aux1][aux2].valor); aux2 = aux1; aux1 = precede[aux1]; printf("\n %s -> %s (%d)", rotulos[aux1], rotulos[aux2], grafo[aux1][aux2].valor); } } newline(); printf("\nRepetir [S/N]? "); do { tecla = getchar(); } while (!strchr("SsNn",tecla)); } while (strchr("Ss",tecla)); return(0); }

195

Vous aimerez peut-être aussi