IPC2
1999/2000F. Nunes Ferreira
Acetatos baseados no livro
C: How to Program (second edition)
H. M. Deitel P. J. Deitel
Prentice Hall, 1994
Arrays
2
u Array é uma estrutura de dados, todos do mesmo tipo. Vectores (1D) e Matrizes (2D, 3D, ...) são exemplos de arrays
u Estrutura/Struct é uma estrutura de dados, os quais podem ser de tipos diferentes
u Ambos os casos são estruturas que, enquanto existem, mantêm o mesmo tamanho.
u Mais tarde, também serão consideradas estruras dinâmicas (listas, filas de espera, pilhas e árvores)
Arrays
Introdução
3 u
Um array de 6 elementos
c[0] 6 - O primeiro elemento é c[0] ... c[1] 742 c[2] -15 - c[4 + 1] += 2; faz c[5] = 20 c[3] 0 c[4] 32 c[5] 18 uDeclaração
int c[6];
Arrays
Um exemplo
4
u
Declaração com inicialização
int c[6] = {6, 742, -15, 0, 32, 18};
int n[30] = {9, 45}; /* os 2 primeiros elementos
de n[] são inicializados com 9 e 45,
e os restantes 28 com 0 */
int m[] = {6, 742, -15}; /* cria e inicializa um array com 3 elementos */
Arrays
5
Arrays
Um exemplo
u Os elementos de um array são inicializados com
c[j] = 10 + 5 * j;
#include <stdio.h> #define SIZE 10 int main(void) { int c[SIZE], j; for (j = 0; j <= SIZE - 1; j++) c[j] = 10 + 5 * j;printf("%s%10s\n", "Indice", "Valor");
for (j = 0; j <= SIZE - 1; j++) printf("%6d%10d\n", j, c[j]); return 0; } Indice Valor 0 10 1 15 2 20 3 25 4 30 5 35 6 40 7 45 8 50 9 55
u Numa turma de 40 alunos, foi feito um inquérito à qualidade da comida de uma cantina: 1- má; ... 10- excelente. As
respostas ao inquérito são colocadas num array de 40
elementos e um programa sumariza o resultado numa tabela de 10 entradas #include <stdio.h> #define N_ALUNOS 40 #define NIVEIS 11 int main(void) {
int resposta, nivel;
int respostas[N_ALUNOS] = {5, 6, 4, 8, 4, 10, 8, 4, 5, 4, 5, 2, 5, 1, 5, 7, 3, 5, 9, 5, 7, 6, 6, 5, 5, 3, 6, 7, 6, 8, 2, 5, 7, 6, 4, 3, 9, 5, 3, 7}; int frequencia[NIVEIS] = {0};
for (resposta = 0; resposta <= N_ALUNOS - 1; resposta++) ++frequencia[respostas[resposta]];
printf("%s%10s\n", "Nivel", "Votacao");
for (nivel = 1; nivel <= NIVEIS - 1; nivel++)
printf("%5d%10d\n", nivel, frequencia[nivel]); return 0; } Nivel Votacao 1 1 2 2 3 4 4 5 5 11 6 6 7 5 8 3 9 2 10 1
7
u Definir o tamanho dos arrays com constantes simbólicas torna os programas mais portáveis
u Utilizar letras maiúsculas para as constantes simbólicas lembra os programadores que estas constantes não variáveis
u Garantir que nenhuma referência a um array se fará para além dos seus limites
Arrays
8
u Uma cadeia de caracteres (string) é um array de caracteres
u
char experienc1[] = "um";
cria e inicializa um array de comprimento 3, com os caracteres 'u' 'm' e '\0'.
É equivalente a char experienc1[] = {'u', 'm', '\0'};
u Quando se preenche um array de caracteres a partir do teclado, é necessário prever espaço no array até ao primeiro caracter whitespace (ver exemplo seguinte)
Arrays
u Inicialização de cadeias de caracteres através de uma constante literal e do teclado
#include <stdio.h> int main(void)
{
char cadeia1[20], cadeia2[] = "constante literal"; int i;
printf("Indicar uma cadeia: "); scanf("%s", cadeia1);
printf("cadeia1 e': %s\ncadeia2 e': %s\n", cadeia1, cadeia2);
for (i = 0; cadeia1[i] != '\0'; i++) printf("%c ", cadeia1[i]);
printf("\n"); return 0;
}
Indicar uma cadeia: uma cadeia cadeia1 e': uma
cadeia2 e': constante literal u m a
& não é
u Arrays estáticos e dinâmicos #include <stdio.h> void iniEstatica(void); void iniDinamica(void); int main(void) { printf("Primeira chamada:\n"); iniEstatica(); iniDinamica(); printf("\n\nSegunda chamada:\n"); iniEstatica(); iniDinamica(); return 0; } void iniEstatica(void) {
static int a[] = {3, 2, 1}; for (i = 0; i <= 2; i++) printf("a[%d] = %d ", i, a[i] += 5); } void iniDinamica(void) { int b[] = {3, 2, 1}; for (i = 0; i <= 2; i++) printf("b[%d] = %d ", i, b[i] += 5); } Primeira chamada:
a[0] = 8 a[1] = 7 a[2] = 6 b[0] = 8 b[1] = 7 b[2] = 6 Segunda chamada:
a[0] = 13 a[1] = 12 a[2] = 11 b[0] = 8 b[1] = 7 b[2] = 6
11
Arrays
Arrays como argumentos de funções
u C passa arrays completos para funções, simulando uma chamada por referência.
u Boa solução em termos de desempenho
u O nome de um array corresponde ao endereço do seu primeiro elemento, &nome-array[0]
u A especificação de conversão %p é utilizada na visualização de apontadores em hexadecimal
#include <stdio.h> int main(void)
{
char cadeia[5];
printf(" cadeia = %p\n&cadeia[0] = %p\n", cadeia, &cadeia[0]);
return 0; }
cadeia = 0064FDF0 &cadeia[0] = 0064FDF0
#include <stdio.h> #define TAMANHO 5
void modificArray(int [], int); int main(void)
{
int i, a[5] = {0, 10, 20, 30, 40}; printf("Valores originais:\n");
for (i = 0; i <= TAMANHO - 1; i++) printf("%4d", a[i]);
modificaArray(a, TAMANHO);
printf("\nValores modificados:\n"); for (i = 0; i <= TAMANHO - 1; i++)printf("%4d", a[i]); return 0;
}
void modificaArray(int x[], int comprimento) {
int j;
for (j = 0; j <= comprimento - 1; j++) x[j] *= 5;
}
• O que resultaria se fosse:
modificaArray(&a[2], TAMANHO - 2);
Valores originais: 0 10 20 30 40 Valores modificados: 0 50 100 150 200
13
Arrays
Qualificador const aplicado a arrays
u Qualificador const utilizado para evitar alterações (não desejadas) de arrays dentro de funções
void tentaModificar(const int []); int main(void) { int a[] = {10, 20, 30}; tentaModificar(a); . . . return 0; }
void tentaModificar(const int b[]) {
b[0] *= 10; b[1] *= 20; b[2] *= 30; }
• Desempenho da referência, segurança da passagem por valor
Erros de compilação, por tentativa de modificar constantes ! . . .
14
Arrays
Ordenação - bubble sort
u O array vai ser percorrido tantas vezes quantos os seus elementos menos 1.
Em cada percurso o maior valor encontrado é puxado para o final... ... Vai comparando pares de valores ... ... e trocando-os entre si, se necessário
u Pouco eficiente, mas fácil de programar
1 2 3 4 5 6 7 8 9 Valores originais: 5 1 7 3 2 4 0 9 8 6 Valores em ordenacao: 1 5 3 2 4 0 7 8 6 9 1 3 2 4 0 5 7 6 8 9 1 2 3 0 4 5 6 7 8 9 1 2 0 3 4 5 6 7 8 9 1 0 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9
#include <stdio.h> #define TAMANHO 10 int main(void)
{
int i, passo, temp;
int array[TAMANHO] = {5, 1, 7, 3, 2, 4, 0, 9, 8, 6}; printf("Valores originais:\n");
for (i = 0; i <= TAMANHO - 1; i++) printf("%3d", array[i]);
printf("\nValores em ordenacao:\n");
for (passo = 1; passo <= TAMANHO - 1; passo++){ for (i = 0; i <= TAMANHO - 2; i++)
if (array[i] > array[i + 1]){ temp = array[i];
array[i] = array[i + 1]; array[i + 1] = temp;
}
for (i = 0; i <= TAMANHO - 1; i++) printf("%3d", array[i]); printf("\n"); } return 0; } 5 1 7 3 2 4 0 9 8 65 1 7 3 2 4 0 9 8 6
16
Arrays
Ordenação - bubble sort
u Uma versão em que o bubble sort só trata da ordenação
#include <stdio.h> #define DIM_MAX 100 #define N_COL 6
int leVector(int vec[], int dim);
void visuVector(const int vec[], int dim, int nCol); void bubleSort(int vec[], int dim);
int main(void) {
...
- ler nº inteiros a ordenar - ler vector
- visualizar vector a ordenar -
ordenar vector
int main(void) {
int valores[DIM_MAX], num; do {
printf("\nNumero valores (< %d):\n", DIM_MAX); scanf("%d", &num);
} while (num < 1 || num > 100);
printf("\nLeitura dos elementos do vector:"); leVector(valores, num);
printf("\n\nVector a ordenar:\n"); visuVector(valores, num, N_COL); bubleSort(valores, num);
printf("\nVector ordenado:\n"); visuVector(valores, num, N_COL); return 0;
int leVector(int vec[], int dim) {
int i;
for(i = 0; i < dim; i++) { printf("\nInteiro: "); scanf("%d", &vec[i]); } return i; }
void visuVector(const int vec[], int dim, int nCol) {
int i, c;
for (i = 0; i <= dim - 1; i++) {
putchar(c = (i % nCol == 0) ? '\n' : ' '); printf("%6d", vec[i]);
} }
19
• Recebe um vector de inteiros e devolve-o
ordenado
void bubleSort(int vec[], int dim)
{
int passo, i, temp;
for (passo = 1; passo <= dim - 1; passo++)
for (i = 0; i <= dim - 2; i++)
if (vec[i] > vec[i + 1]){
temp = vec[i];
vec[i] = vec[i + 1];
vec[i + 1] = temp;
}
}
Arrays
20
u Pesquisa linear (arrays pequenos e não necessariamente ordenados)...
u Pesquisa binária (arrays grandes e necessariamente ordenados)...
u O programa cria um array com valores inteiros (vamos supor que são apenas inteiros pares) e responde da seguinte maneira:
u Função a usar...
const
int procuraLin( int a[], int valor, int tamanho)
Indicar o valor inteiro a procurar: 36 Valor encontrado na posicao 18
Indicar o valor inteiro a procurar: 37 Valor nao encontrado
Arrays
#include <stdio.h> #define SIZE 10
int procuraLin (int [], int, int); int main(void)
{
int a[SIZE], i, valor, indice;
/* criar um array de inteiros */ for (i = 0; i < SIZE; i++)
a[i] = 2 * i;
printf("Valor a procurar: "); scanf("%d", &valor);
indice = procuraLin(a, valor, SIZE);
if (indice == -1)
printf("Valor nao encontrado\n"); else
printf("Valor encontrado na posicao de indice %d\n", indice); return 0;
int procuraLin (int a[], int valorProcurado,
int comprimento)
{
int i;
for (i = 0; i < comprimento; i++)
if (a[i] == valorProcurado)
return i;
return -1;
}
23
u Idêntido ao anterior, mas com pesquisa binária
int procBin(const int quad[], int valor, int indInf, int indSup)
Indicar um valor entre 0 e 28: 25
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 2 4 6 8 10 12 14* 16 18 20 22 24 26 28 16 18 20 22* 24 26 28 24 26* 28 24*
25 nao foi encontrado
Indicar um valor entre 0 e 28: 6
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 2 4 6 8 10 12 14* 16 18 20 22 24 26 28 0 2 4 6* 8 10 12
6 foi encontrado na posicao 3
Arrays
Exercício: pesquisa binária
índice vector
24
Arrays
arrays multidimensionais
u Array bidimensional: int q [3][4]
Coluna Coluna Coluna Coluna
0 1 2 3
Linha 0 q[0][0] q[0][1] q[0][2] q[0][3] Linha 1 q[1][0] q[1][1] q[1][2] q[1][3] Linha 2 q[2][0] q[2][1] q[2][2] q[2][3]
u array de 3 linha e 4 colunas: array 3 x 4
ou
u array de 3 elementos, sendo cada um deles um array de 4 elementos (inteiros)
u Exemplo, q[1] corresponde a um array de 4 inteiros
25
Arrays
arrays multidimensionais
u Para percorrer um array (linha a linha, coluna ...) soma = 0;
for (linha = 0; linha <= 2; linha++)
for (coluna = 0; coluna <= 3; coluna++) soma += q[linha][coluna]; u
Inicialização
int a[2][3] = {{1, 2, 3},{4, 5, 6}}; a: 1 2 3 4 5 6 int b[2][3] = {1, 2, 3, 4, 5}; b: 1 2 3 4 5 0 int c[2][3] = {{1, 2}, {4}}; c: 1 2 0 4 0 026
Exercícios
Simulação de um helicóptero digital - 1
u
Um helicóptero imaginário é comandado
através do teclado. O helicóptero, quando no
ar, não deixa rasto. Para deixar rasto
deverá estar em contacto com o terreno.
Comando Efeito1 Põe o helicóptero no ar
2 Põe o helicóptero em contacto com o terreno 3 Faz o helicóptero rodar 90o para a direita
4 Faz o helicóptero rodar 90o para a esquerda 5 d Desloca o helicóptero (pelo ar ou em
contacto com o terreno) d posições para a frente 6 Visualiza o terreno (com os rastos feitos
pelo helicóptero)
7 Limpa os rastos do helicóptero no terreno 9 Termina o programa
27
Exercícios
Simulação de um helicóptero digital - 2
u O terreno é suposto ser um quadrado de dimensão 20 x 20, a que corresponde 20 x 20 células, cada uma
identificada pela linha e coluna respectivas. O
helicóptero é caracterizado pela sua posicao, dada pela linha e coluna onde se encontra (não
necessariamente uma linha e uma coluna do terreno, pois o helicóptero pode deslocar-se para fora dos limites daquele), e é ainda caracterizado pela sua orientacao (um dos pontos cardeais: N, S, E ou O) e situacao (no ar ou no plano do terreno).
linha 20 --- Helicóptero --- posição: 16 11 --- situação: terreno ---H--- orientação: N ... linha 1
---N
28
Exercícios
Simulação de um helicóptero digital - 3
u O helicóptero é visualizado pela letra H, as células ainda não visistadas por ele são visualizadas com -, enquanto que as já visitadas serão representadas por O. Por exemplo, após o comando 5 com d=2, obtém-se: linha 20
--- Helicóptero
---H--- posição: 18 11 ---O--- situação: terreno ---O--- orientação: N
...
linha 1
---• Exemplo de uma sessão com o programa
helicoptero-digital, em que as condições iniciais correspondem a terreno limpo e o helicóptero com posicao: 16 11;
29
Exercícios
Simulação de um helicóptero digital - 4
u Comando: 3 ; roda para a direita 90o
u Comando: 5 ; avança
u Posicoes em frente: 3 ; 3 posições
u Comando: 4 ; roda para a esquerda 90o
u Comando: 5 ; ... u Posicoes em frente: 2 u Comando: 4 u Comando: 5 u Posicoes em frente: 6 u Comando: 6 linha 20 ... linha 1
---30
Exercícios
Simulação de um helicóptero digital - 5
u 1- Definir e implementar, se necessário, uma abstracção de dados compatível com o problema exposto.
u 2- Fazer uma abordagem de-cima-para-baixo ao
programa helicoptero-digital, para identificar as suas tarefas e sub-tarefas principais.
u 3- Escrever em C o programa helicoptero-digital, tomando por base os resultados da abordagem
anterior.
u Nota:
O helicóptero na sua deslocação pode ultrapassar os limites do terreno, situação em que não deixa rasto. O programa continuará a actualizar as suas
características, de acordo com os comandos que vai recebendo.
31
Exercícios
Bubble sort
u
A ordenação bubble sort já apresentada é
extremamente ineficiente para arrays de
grandes dimensões. Introduzir os seguintes
melhoramentos àquela solução.
1- Depois do 1º passo é garantido que o maior
valor está na última posição, que não
necessitará de ser visitada no passo
seguinte...
2- O array a ordenar pode já estar próximo da
ordenação pretendida, não sendo necessários
todos os passos. Basta detectar quando, num
dado passo, não se verifique qualquer
32
• Recebe um vector de inteiros e devolve-o
ordenado
void bubleSort(int vec[], int dim)
{
int passo, i, temp;
for (passo = 1; passo <= dim - 1; passo++)
for (i = 0; i <= dim - 2; i++)
if (vec[i] > vec[i + 1]){
temp = vec[i];
vec[i] = vec[i + 1];
vec[i + 1] = temp;
}
}
Arrays
33
Exercícios
Bucket Sort - 1
u Um array contém n inteiros positivos para ordenar. Considerar um array auxiliar 10 x n. Cada uma das suas 10 linhas é designada por bucket. Escrever a função bucketSort que toma um array de inteiros e o seu comprimento como argumentos e implementa o
seguinte algoritmo:
1- Percorre o array e coloca os seus elementos nas linhas do array 10 x n, de acordo com o seu dígito das unidades. Por exemplo, 97 é colocado na linha 7, 3 é colocado na linha 3, e 100 na linha 0.
2- Percorre o array auxiliar e obtém o array inicial agora ordenado da seguinte maneira: 100, 3, 97. 3- Repete 1- e 2- agora com o dígito das dezenas,
depois das centenas, ... e termina quando é tratado o dígito mais significativo do maior número.
34
Exercícios
Bucket Sort - 2
Array a 10 buckets ordenar B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 97 3 100 100 3 97 100 3 97 100 97 3 100 3 97 3 100 973 97 100 <--- termina, pois não há mais dígitos... Se continuasse, cairiam todos em B0.
35
u
O algoritmo Selection sort inicia-se
procurando o elemento mais pequeno de um
array. Esse elemento é trocado com o primeiro
elemento do array. O processo continua com o
sub-array constituido a partir do segundo
elemento do array...
O processo termina quando o sub-array tem
apenas um elemento.
Escrever uma função recursiva para este
algoritmo.
Exercícios
Selection sort
36
u Foi apresentado um exemplo relativo à procura linear (para arrays pequenos e com os respectivos elementos
não ordenados). Escrever agora uma função recursiva que faz a mesma pesquisa e recebe como argumentos um array de inteiros, um inteiro que é o valor a procurar e um inteiro que é o tamanho daquele array. Se o valor é
encontrado, a função devolve a sua posição. Se não for encontrado, devolve -1.
u Também foi apresentado um exemplo relativo à procura binária (para arrays grandes e com os respectivos
elementos ordenados). Escrever a função recursiva que faz a mesma pesquisa e recebe como argumentos um array de inteiros, um inteiro que é o valor a procurar, e
dois inteiros que representam, respectivamente, o índice mais baixo e o índice mais alto do array a
pesquisar. Se o valor é encontrado, a função devolve a sua posição. Caso não seja encontrado, devolve -1.
Exercícios
37
u
Escrever a função recursiva visuArray que
toma um array e o seu tamanho como argumentos
e não devolve nada. A função visualiza os
elementos do array e pára quando recebe um
array de tamanho zero.
u
Escrever a função recursiva
visuCadeiaAoContrario que toma um array de
caracteres como argumento e visualiza a
cadeia ao contrário, com um espaço entre
caracteres. A função pára quando encontra o
caracter nulo, '\0'.
Exercícios
Recursividade
#include <stdio.h>
void visuCadeiaAoContrario(char []); int main(void)
{
char cadeia[] = "123abcdfgh";
printf("\nCadeia original: %s\n", cadeia); printf("\nCadeia ao contrario: "); if ('\0' != cadeia[0]) visuCadeiaAoContrario(cadeia); printf("\n"); return 0; }
void visuCadeiaAoContrario(char cadeia[]) { if ('\0' == cadeia[1]) printf("%c ", cadeia[0]); else { visuCadeiaAoContrario(&cadeia[1]); printf("%c ", cadeia[0]); } }
39
u
Escrever a função recursiva minNoarray que
toma um array de inteiros e um inteiro que é
o seu tamanho como argumentos e devolve o
mais pequeno valor no array. A função pára
quando recebe um array com um valor.
u
Escrever a função recursiva capicua que toma
uma cadeia de caracteres como argumento e
devolve 1 se essa cadeia for uma capicua ou
zero, se não for capicua.
Exercícios
Recursividade
#include <stdio.h> #define TAMANHO 10
int minNoarray(int [], int); int main(void)
{
int i;
int array[TAMANHO] = {9, 8, 7, 6, -5, 4, 0, 2, 1, 78}; printf("\nValores originais:\n");
for (i = 0; i <= TAMANHO - 1; i++) printf("%3d", array[i]);
printf("\nValor minimo: %d\n", minNoarray(array, TAMANHO)); return 0;
}
int minNoarray(int quad[], int tamanho) {
int valorMin;
if (1 == tamanho) return quad[0]; else{
valorMin = minNoarray(&quad[1], --tamanho); return
quad[0] < valorMin? quad[0]: valorMin; }
#include <stdio.h> #include <string.h> int capicua(char []);
int capicuaAux(char [], size_t); int main(void)
{
char cadeia[] = "abc d cba";
printf("\nCadeia original: %s\n", cadeia); if (capicua(cadeia))
printf("E uma capicua\n"); else
printf("Nao e uma capicua\n"); return 0;
}
int capicua(char cadeia[]) {
return capicuaAux(cadeia, strlen(cadeia)); }
int capicuaAux(char cadeia[], size_t comp) {
if (comp == 0 || comp == 1) return 1;
else
return cadeia[0] == cadeia[comp - 1] && capicuaAux(&cadeia[1], comp - 2); }