594 | Capítulo 9 – Estruturas, Uniões e Enumerações
Exemplo de execução do programa:
>>> Este programa apresenta a distancia entre oRio
>>> de Janeiro e uma cidade escolhida pelo usuario.
>>> Digite apenas [ENTER] para encerrar.
>>> Cidades Disponiveis <<<
Amsterdam
Jerusalem
Moscou
Otawa
Bagdad
Joao Pessoa
Nova Deli
Paris
Berlim
Lisboa
Nova Iorque
Viena
Beirute
Londres
Oslo
Zurich
>>> Escolha uma cidade para conhecer sua distancia ate' o
>>> Rio de Janeiro > Campina Grande
>>> A cidade "Campina Grande" nao foi encontrada
>>> Cidades Disponiveis <<<
Amsterdam
Jerusalem
Moscou
Otawa
Bagdad
Joao Pessoa
Nova Deli
Paris
Berlim
Lisboa
Nova Iorque
Viena
Beirute
Londres
Oslo
Zurich
>>> Escolha uma cidade para conhecer sua distancia ate' o
>>> Rio de Janeiro > Joao Pessoa
>>> A distancia do Rio de Janeiro ate' Joao Pessoa e' 2448Km
>>> Cidades Disponiveis <<<
Amsterdam
Jerusalem
Moscou
Otawa
Bagdad
Joao Pessoa
Nova Deli
Paris
Berlim
Lisboa
Nova Iorque
Viena
Beirute
Londres
Oslo
Zurich
>>> Escolha uma cidade para conhecer sua distancia ate' o
>>> Rio de Janeiro > [ENTER]
>>> Obrigado por usar este programa.
9.10.8 Operações sobre Conjuntos
Problema: Escreva um programa que implemente e teste as seguinte operações sobre
conjuntos cujos membros são valores do tipo int:
• Pertinência – que verifica se um valor do tipo int faz parte de um conjunto.
• Continência – que verifica se cada elemento de um conjunto faz parte de outro.
• Igualdade – que verifica se dois conjuntos são iguais; i.e., se cada elemento
de um conjunto também é elemento do outro conjunto.
• Cardinalidade – que calcula o número de elementos de um conjunto.
• União – que determina o conjunto formado por todos os elementos que fazem
parte de um dos dois conjuntos.
• Interseção – que determina o conjunto formado pelos elementos que fazem
parte de dois conjuntos simultaneamente.
• Diferença – que determina o conjunto formado pelos elementos que fazem
parte de um conjunto, mas não fazem parte de outro.
• Disjunção – que verifica se dois conjuntos são disjuntos; i.e., se eles não possuem nenhum elemento em comum.
9.10 Exemplos de Programação | 595
• Comparabilidade – que verifica se dois conjuntos são comparáveis; i.e., se
algum deles está contido no outro.
Solução:
O tipo utilizado para representar conjuntos no programa solicitado é definido como:
/* Tipo de uma variável que representa um conjunto */
typedef struct {
int elementos[MAX_ELEMENTOS];
int nElementos;
} tConjunto;
As definições de funções apresentadas a seguir implementam as operações sobre
conjuntos requeridas.
/****
*
* Pertence(): Determina se um elemento pertence a um conjunto
*
* Parâmetros:
*
x (entrada) - o elemento
*
*a (entrada) - o conjunto
*
* Retorno: 1, se o elemento pertence ao conjunto.
*
0, se o elemento NÃO pertence ao conjunto.
*
****/
int Pertence(int x, const tConjunto *a)
{
/* Se o conjunto estiver vazio,
*/
/* nenhum elemento pertence a ele */
if (!a->nElementos) {
return 0;
}
}
/* Verifica se o elemento encontra-se no array */
/* que armazena os elementos do conjunto
*/
return EmArray(a->elementos, a->nElementos, x) >= 0;
/****
*
* EstaContido(): Determina se um conjunto está contido em outro
*
* Parâmetros:
*
*a (entrada) - conjunto que se verificará se está contido
*
*b (entrada) - conjunto que se verificará se contém o primeiro
*
* Retorno: 1, se o primeiro conjunto estiver contido no segundo;
*
0, em caso contrário.
*
****/
int EstaContido(const tConjunto *a, const tConjunto *b)
{
int i;
/* O conjunto vazio, é subconjunto e qualquer conjunto */
if (!a->nElementos) {
return 1;
}
596 | Capítulo 9 – Estruturas, Uniões e Enumerações
/* O conjunto vazio, não contém nenhum */
/* conjunto, exceto o conjunto vazio
*/
if (!b->nElementos) {
return 0;
}
/* Verifica se existe algum elemento do */
/* conjunto 'a' que não pertence a 'b' */
for (i = 0; i < a->nElementos; ++i) {
if ( !Pertence(a->elementos[i], b) ) {
return 0;
}
}
}
/* Se ainda não houve retorno, todos os */
/* elementos de 'a' pertencem a 'b'
*/
return 1;
/****
* SaoIguais(): Determina se dois conjuntos são iguais
*
* Parâmetros:
*
*a, *b (entrada) - conjuntos que se verificarão
*
se são iguais
* Retorno: 1, se os conjuntos forem iguais; 0, em caso contrário
*
****/
int SaoIguais(const tConjunto *a, const tConjunto *b)
{
/* Dois conjuntos são iguais se */
/* cada um está contido no outro */
return EstaContido(a, b) && EstaContido(b, a);
}
/****
*
* SaoDisjuntos(): Determina se dois
*
* Parâmetros:
*
*a, *b (entrada) - conjuntos
*
disjuntos
* Retorno: 1, se os conjuntos forem
*
****/
int SaoDisjuntos(const tConjunto *a,
{
tConjunto c;
}
conjuntos são disjuntos
que se verificarão se são
disjuntos; Caso contrário, 0.
const tConjunto *b)
/* Dois conjuntos são disjuntos quando não */
/* possuem nenhum elemento em comum; i.e., */
/* quando a interseção entre eles for vazia */
return Cardinalidade( Intersecao(b, a, &c) ) == 0;
/****
*
* SaoComparaveis(): Determina se dois conjuntos são comparáveis
*
9.10 Exemplos de Programação | 597
* Parâmetros:
*
*a, *b (entrada) - conjuntos que se verificarão se são
*
comparáveis
*
* Retorno: 1, se os conjuntos forem comparáveis; 0, em
*
caso contrário.
*
****/
int SaoComparaveis(const tConjunto *a, const tConjunto *b)
{
/* Dois conjuntos são comparáveis se */
/* um deles está contido no outro
*/
return EstaContido(a, b) || EstaContido(b, a);
}
/****
*
* Cardinalidade(): Determina o número de elementos de um conjunto
*
* Parâmetros:
*
*a (entrada/saída) - o conjunto cuja cardinalidade será
*
determinada
*
* Retorno: A cardinalidade do conjunto recebido como parâmetro
*
* Observação: Se o conjunto contiver elementos duplicados,
*
eles serão removidos
*
****/
int Cardinalidade(tConjunto *a)
{
/* A função RemoveDuplicatas() remove eventuais */
/* elementos duplicados e retorna o número de
*/
/* elementos restantes no conjunto
*/
return RemoveDuplicatas(a->elementos, &a->nElementos);
}
/****
*
* Uniao(): Determina a união de dois conjuntos
*
* Parâmetros:
*
*a (entrada/saída) - um conjunto
*
*b (entrada/saída) - outro conjunto
*
*u (saída) - a união dos conjuntos
*
* Retorno: Endereço da união dos dois conjuntos se ela couber no
*
array que armazenará o resultado; caso contrário, NULL
*
****/
tConjunto *Uniao(tConjunto *a, tConjunto *b, tConjunto *u)
{
tConjunto intersecao; /* Armazenará a interseção */
/* dos conjuntos
*/
int
numEle, /* Número de elementos no resultado */
nMax, /* Número máximo de elementos */
/* que o resultado pode conter */
i, j;
598 | Capítulo 9 – Estruturas, Uniões e Enumerações
/* Calcula o número de elementos no resultado. A função */
/* Cardinalidade() remove elementos duplicados.
*/
numEle = Cardinalidade(a) + Cardinalidade(b) Cardinalidade(Intersecao(a, b, &intersecao));
/* Determina qual é o número máximo de elementos */
/* que o resultado pode conter, que é exatamente */
/* o tamanho do array que contém os elementos
*/
nMax = sizeof(u->elementos)/sizeof(u->elementos[0]);
/* Verifica se o resultado caberá no array */
/* que armazena os elementos do conjunto
*/
if (nMax < numEle) {
return NULL; /* O resultado não vai caber no array */
}
/* Copia os elementos do primeiro conjunto */
/* para o conjunto que conterá o resultado */
for (i = 0; i < a->nElementos; ++i) {
u->elementos[i] = a->elementos[i];
}
/* O número parcial de elementos da união */
/* é igual ao último valor assumido por i */
u->nElementos = i;
/* Copia para o conjunto que conterá o resultado */
/* os elementos do segundo conjunto que ainda não */
/* fazem parte do resultado parcial
*/
for (j = 0; j < b->nElementos; ++j) {
if (!Pertence(b->elementos[j], u)) {
u->elementos[i] = b->elementos[j];
++i;
}
}
/* É preciso atualizar o número de elementos da união em */
/* virtude de algum acréscimo de elementos do conjunto b */
u->nElementos = i;
}
return u; /* Retorna o endereço do conjunto resultante */
/****
*
* Intersecao(): Determina a interseção de dois conjuntos
*
* Parâmetros:
*
*a (entrada) - um conjunto
*
*b (entrada) - outro conjunto
*
*c (saída) - a interseção dos dois conjuntos
*
* Retorno: O endereço da estrutura que contém a interseção
*
dos dois conjuntos
*
****/
tConjunto *Intersecao( const tConjunto *a, const tConjunto *b,
tConjunto *c )
{
9.10 Exemplos de Programação | 599
int i, j;
/* Acrescenta ao conjunto resultante cada
*/
/* elemento que pertence aos dois conjuntos */
for (j = i = 0; i < a->nElementos; ++i) {
if (Pertence(a->elementos[i], b)) {
c->elementos[j] = a->elementos[i];
++j;
}
}
/* O número de elementos da interseção é */
/* igual ao último valor assumido por j */
c->nElementos = j;
/* Remove elementos duplicados da interseção e
*/
/* atribui o número de elementos restantes ao campo */
/* que armazena o número de elementos do conjunto
*/
RemoveDuplicatas( c->elementos, &c->nElementos );
}
return c; /* Retorna o endereço do conjunto resultante */
/****
*
* Diferenca(): Determina a diferença entre dois conjuntos
*
* Parâmetros:
*
*a (entrada) - primeiro conjunto
*
*b (entrada) - segundo conjunto
*
*c (entrada) - a diferença a - b
*
* Retorno: O endereço da estrutura que contém a diferença
*
entre o primeiro conjunto e o segundo conjunto
*
* Observação: A diferença calculada é a - b (e não b - a)
*
****/
tConjunto *Diferenca( const tConjunto *a, const tConjunto *b,
tConjunto *c )
{
int i, j;
/* Acrescenta ao conjunto resultante cada
*/
/* elemento que pertence ao primeiro conjunto */
/* mas não pertence ao segundo conjunto
*/
for (j = i = 0; i < a->nElementos; ++i) {
if (!Pertence(a->elementos[i], b)) {
c->elementos[j] = a->elementos[i];
++j;
}
}
/* O número de elementos da diferença é */
/* igual ao último valor assumido por j */
c->nElementos = j;
600 | Capítulo 9 – Estruturas, Uniões e Enumerações
/* Remove elementos duplicados da diferença e
*/
/* atribui o número de elementos restantes ao campo */
/* que armazena o número de elementos do conjunto
*/
RemoveDuplicatas( c->elementos, &c->nElementos );
}
return c; /* Retorna o endereço do conjunto resultante */
Análise: As funções implementadas acima utilizam as seguintes funções já discutidas
no Capítulo 7:
• EmArray() [Seção 7.11.4]
• RemoveElemento() [Seção 7.11.8]
• RemoveDuplicatas() [Seção 7.11.8]
• ExibeArrayInts() [Seção 7.9.2]
A implementação de uma função main() que testa as operações sobre conjuntos é
deixada como exercício para o leitor, assim como acrescentar as linhas que complementam
o programa. O programa completo encontra-se no site do livro (www.ulysseso.com/ip).
9.10.9 Traduzindo Expressões Telefônicas
Preâmbulo: Telefones convencionais modernos incluem em cada tecla, além de um dígito, uma sequência de três letras que permitem ao usuário memorizar facilmente alguns
números. Por exemplo, para ligar para uma determinada farmácia, o usuário poderia
digitar as teclas que correspondem às letras F, A, R, M, A, C, I e A, que é bem mais fácil
de memorizar do que o número correspondente de telefone (nesse caso, 32762242)
que será efetivamente chamado.
Problema: Escreva um programa que apresenta números de telefones correspondentes
a expressões contendo letras, '0', '1' ou '-'.
Solução:
/*********************** Includes *************************/
#include
#include
#include
#include
#include
<stdio.h>
<string.h>
<ctype.h>
<stdlib.h>
"leitura.h"
/*
/*
/*
/*
/*
putchar() e printf()
strchr()
isalpha() e toupper()
exit()
LeString()
*/
*/
*/
*/
*/
/***************** Constantes Simbólicas ******************/
/* Tamanho máximo de um string que
*/
/* representa uma expressão telefônica */
#define MAX_EXPRESSAO 30
/* Número máximo de caracteres associados a um dígito */
#define MAX_CAR_POR_DIGITO 4
/****************** Definições de Tipos *******************/
/* Tipo de estrutura que representa uma */
/* correspondência entre as letras de
*/
/* um string e um dígito de telefone
*/
typedef struct {
char letras[MAX_CAR_POR_DIGITO + 1];
int digito;
/* Dígito correspondente a */
/* qualquer letra do string */
} tCorrespondencia;