MC102 |
VETORES (ARRAY) |
Lembra de nosso programa que tirava a média de n números inteiros? Vamos repetí-lo para 10 números:
PROGRAM notas; VAR num : integer; {número digitado} media : real; {média dos dados} cont : integer; {contador do for} soma : integer; {soma dos dados} BEGIN soma := 0; FOR cont := 1 TO 10 DO BEGIN write('entre um dado: '); readln(num); soma := soma + num END; media := soma / n; writeln('a média é ',media:4:2) END. |
Mas, e se quiséssemos guardar os vários valores de num? Como fazemos? Usamos um vetor (array):
PROGRAM notas; 1. VAR num : ARRAY[1..10] OF integer; {vetor dos números digitados} media : real; {média dos dados} cont : integer; {contador do FOR} soma : real; {soma dos dados} BEGIN soma := 0; FOR cont := 1 TO 10 DO BEGIN write('entre um dado: '); 2. readln(num[cont]); 3. soma := soma + num[cont] END; media := soma / n; writeln('a média é ',media:4:2) END. |
Agora vamos por partes. antes de mais nada, o que é um vetor? Um vetor pode ser pensado como uma variável que consegue guardar vários valores de um determinado tipo. Assim, quando definimos:
VAR num : ARRAY[1..10] OF integer; {vetor dos números digitados} |
estamos criando uma variável, chamada num, que é capaz de guardar até 10 inteiros. Ou seja, na prática, esta seria uma variável assim:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
onde em cada quadrado cabe um inteiro.
Então, quando fazemos
n[5] := 20; |
estamos colocando o inteiro 20 na 5ª posição do vetor:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|
20 |
Veja que, na linha 2 do nosso programa acima, abastecemos cada posição de "num" (usando, para isso, o contador "cont") com o inteiro dado pelo usuário.
Agora, como usamos esses valores armazenados? Da mesma forma que uma variável comum, só que com sintaxe um pouco diferente (veja a linha 3 do nosso programa):
VAR n : ARRAY[1..10] OF integer; x : integer; BEGIN x := n[8]; {x recebe o valor que está na 8ª posição do vetor} x := n[3] + 2*n[5]; {x recebe o dobro do valor que está na 5ª posição somado ao que está na 3ª posição do vetor} |
A forma geral da declaração de um vetor é:
ARRAY[limite_inferior..limite_superior] OF tipo; |
Naturalmente, podemos definir um tipo com o vetor:
TYPE vetor = ARRAY[1..10] OF integer; VAR v : vetor; |
A vantagem desse uso é que posso passar um vetor como parâmetro de uma função ou procedimento. Assim, posso fazer:
TYPE vetor = ARRAY[1..10] OF integer; VAR v : vetor; PROCEDURE P(x : vetor); BEGIN ... END; |
Vale notar que, como na passagem por valor, o valor da variável é copiado para o parâmetro, x será um vetor que conterá uma cópia dos valores contidos no vetor a ele passado.
Como isso pode consumir muita memória, se o vetor for grande, é aconselhável efetuar a passagem por referência, desse modo:
TYPE vetor = ARRAY[1..10] OF integer; VAR v : vetor; PROCEDURE P(VAR x : vetor); BEGIN ... END; |
Essa, na verdade, é a única maneira de se passar um vetor como parâmetro, já que o seguinte não é permitido:
PROCEDURE P(x : ARRAY[1..10] OF integer;); BEGIN ... END; |
Da mesma forma, posso usar esse tipo como o retorno de uma função:
TYPE vetor = ARRAY[1..10] OF integer; VAR v : vetor; FUNCTION F(x : real) : vetor; BEGIN ... END; BEGIN v := F(2.3); END. |
enquanto que o mostrado abaixo não é permitido:
TYPE vetor = ARRAY[1..10] OF integer; VAR v : vetor; FUNCTION F(x : real) : ARRAY[1..10] OF integer; BEGIN ... END; BEGIN v := F(2.3); END. |
: alguns compiladores só aceitam tipos simples como retorno de função, ou seja, nem esse artifício acima funciona. Para esses, você não poderá usar funções, terá que escrever tudo na forma de precedimentos.
Vamos agora dar uma olhada no tipo dos dados que um vetor pode conter. Primeiro, que tipos são aceitos? Qualquer um! Então, posso ter:
TYPE cor = (verde,vermelho,azul); complexo = RECORD re :real; im : real END; vetor1 = ARRAY[1..10] OF cor; vetor2 = ARRAY[1..10] OF complexo; vetor3 = ARRAY[1..10] OF real; VAR v1 : vetor1; v2 : vetor2; v3 : vetor3; BEGIN {carrego a 2ª posição de v1 com "verde"} v1[2] := verde; {carrego a 5ª posição de v2 com "3 - 4i"} v2[5].re := 3; v2[5].im := -4; {carrego a 3ª posição de v2 com "2 + 3i"} v2[3].re := 2; v2[3].im := 3; {somo o imaginário da 3ª posição ao da 5ª e guardo na 10ª} v2[10].re := v2[5].re + v2[3].re; v2[10].im := v2[5].im + v2[3].im; {guardo na 1ª posição de v3 o módulo do complexo na posição 10 de v2} v3[1] := Sqr(v2[10].re) + Sqr(v2[10].im) END. |
Reparou como faço para guardar e usar valores registro que estão dentro de vetores? É só fazer
variável_do_vetor[índice].nome_do_campo |
E quanto aos limites do vetor? Bom, esses, na verdade, devem ser um conjunto de valores seqüenciais:
TYPE limites = 15..20; cor = (vermelho, verde, azul); inferior = 12; superior = 15; VAR v1 : ARRAY[inferior..superior] OF real; v2 : ARRAY[limites] OF integer; v3 : ARRAY[cor] OF char; v4 : ARRAY['a'..'z'] OF cor; v5 : ARRAY['1'..'5'] OF boolean; |
e como acessamos ou guardamos valores nos vetores acima?
TYPE limites = 15..20; cor = (vermelho, verde, azul); inferior = 12; superior = 15; VAR v1 : ARRAY[inferior..superior] OF real; v2 : ARRAY[limites] OF integer; v3 : ARRAY[cor] OF char; v4 : ARRAY['a'..'z'] OF cor; v5 : ARRAY['1'..'5'] OF boolean; BEGIN v1[14] := 3.16; v2[16] := 12; v3[verde] := 'a'; v4['d'] := azul; v5['3'] := true; v1[2] := v1[14] + v2[16] / 5; v3[azul] := Chr(Ord(v3[verde]) + 3); {terá 'd'} v4[v3[verde]] := vermelho; {v4['a'] := vermelho} v5['2'] := v5['3'] OR v5['5'] END. |
Note que os limites não precisam começar de 1. Esses valores são apenas índices, podem começar de qualquer valor, desde que o limite inferior seja maior que o superior e os valores escolhidos como índices sejam seqüenciais.
Agora, como exemplo do uso de vetores, vamos fazer um programa que conte o número de vezes que cada letra foi digitada pelo usuário. O usuário termina o texto com '#'. Repare como fazemos para contar cada letra:
PROGRAM contador; TYPE vetor = ARRAY['A'..'Z'] OF integer; VAR ch : char; {o caracter digitado} v : vetor; {guarda o número de vezes que cada letra foi digitada} cont : integer; {contador do FOR} {retorna true se c for letra, false se não} FUNCTION letra(c : char) : boolean; BEGIN letra := ((c>='a') AND (c<='z')) OR ((c>='A') AND (c<='Z')) END; BEGIN ch := readkey; WHILE ch<>'#' DO BEGIN {escrevo o ch na tela} write(ch); {se for letra...} IF letra(ch) THEN BEGIN {transformo em maiúscula} ch := Upcase(ch); {conto a letra correta - veja como faço} v[ch] := v[ch] + 1 END; {leio o próximo} ch := readkey END; {imprimo o vetor} writeln('Resultado:'); FOR cont:='A' TO 'Z' DO BEGIN writeln('v[',cont,'] = ',v[cont]) END END. |
Ao final desse programa, o vetor v será algo como:
'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
100 | 20 | 10 | 5 | 7 | 6 | 12 | 3 | 43 | 23 | 6 | 7 | 54 | 3 | 6 | 0 | 23 | 65 | 23 | 1 | 9 | 57 | 0 | 12 | 5 | 0 |
Ou seja, cada índice contém, em seu elemento correspondente no vetor, o número de vezes que a letra do índice foi digitada no texto.
Vejamos outro exemplo, a coidificação de um texto. Nesse exemplo, o usuário digita um caracter e, se este for letra, nós o codificamos conforme a seguinte chave:
Caracter | Código | Caracter | Código |
---|---|---|---|
'A' | 'C' | 'N' | 'K' |
'B' | 'Z' | 'O' | 'L' |
'C' | 'O' | 'P' | 'S' |
'D' | 'R' | 'Q' | 'E' |
'E' | 'A' | 'R' | 'H' |
'F' | 'G' | 'S' | 'M' |
'G' | 'B' | 'T' | 'P' |
'H' | 'N' | 'U' | 'I' |
'I' | 'U' | 'V' | 'X' |
'J' | 'T' | 'W' | 'Q' |
'K' | 'D' | 'X' | 'V' |
'L' | 'Y' | 'Y' | 'J' |
'M' | 'F' | 'Z' | 'W' |
Queremos, então, um programa que leia o caracter digitado pelo usuário, o substitua pelo caracter do código e escreva este último, mostrando ao usuário. Novamente, façamos o texto ser terminado por '#'.
PROGRAM codigo; TYPE vetor = ARRAY['A'..'Z'] OF integer; VAR ch : char; {o caracter digitado} chave : vetor; {guarda a chave do código} {retorna true se c for letra, false se não} FUNCTION letra(c : char) : boolean; BEGIN letra := ((c>='a') AND (c<='z')) OR ((c>='A') AND (c<='Z')) END; {retorna true se c for letra maiuscula} FUNCTION maiuscula(c : char) : boolean; BEGIN maiuscula := letra(c) AND (c >= 'A') AND (c <= 'Z') END; {retorna a correspondente minúscula de c} FUNCTION mai_para_min(c : char) : char; BEGIN IF maiuscula(c) THEN mai_para_min := Chr(Ord(c) - Ord('A') + Ord('a')) ELSE mai_para_min := c END; {inicializa a chave} PROCEDURE inicializa(c : vetor); BEGIN v['A'] := 'C'; v['B'] := 'Z'; v['C'] := 'O'; v['D'] := 'R'; v['E'] := 'A'; v['F'] := 'G'; v['G'] := 'B'; v['H'] := 'V'; v['I'] := 'U'; v['J'] := 'T'; v['K'] := 'D'; v['L'] := 'Y'; v['M'] := 'F'; v['N'] := 'K'; v['O'] := 'L'; v['P'] := 'S'; v['Q'] := 'E'; v['R'] := 'H'; v['S'] := 'M'; v['T'] := 'P'; v['U'] := 'I'; v['V'] := 'X'; v['W'] := 'Q'; v['X'] := 'V'; v['Y'] := 'J'; v['Z'] := 'W' END; BEGIN ch := readkey; WHILE ch<>'#' DO BEGIN IF letra(ch) THEN BEGIN IF maiuscula(ch) THEN write(v[ch]) ELSE {é minúscula} write(mai_para_min(v[Upercase(ch)])) END ELSE {não é letra} write(ch); {leio a próxima} ch := readkey END END. |
Estude bem esse programa.
MATRIZES |
Vetores também podem ser usados para representar matrizes. Considere a matriz:
[ |
|
] |
Seria interessante podermos representar isso, não? Como faríamos? Podemos criar um vetor de vetores:
TYPE coluna = ARRAY[1..2] OF integer; matriz = ARRAY[1..2] OF coluna; |
e como abasteceríamos a matriz nessa estrutura de dados?
TYPE coluna = ARRAY[1..2] OF integer; matriz = ARRAY[1..2] OF coluna; VAR m : matriz; BEGIN m[1][1] := 1; m[1][2] := 2; m[2][1] := 3; m[2][2] := 4 END. |
Bastante truculento, não é? Bem, felizmente o Pascal tem um modo mais fácil de representar uma matriz:
TYPE matriz = ARRAY[1..2,1..2] OF integer; VAR m : matriz; BEGIN m[1,1] := 1; m[1,2] := 2; m[2,1] := 3; m[2,2] := 4 END. |
Simples, não? Nós agora representamos uma matriz 2 × 2. Considere agora a matriz 3 × 3:
A = | [ |
|
] |
Como podemos representá-la em Pascal?
TYPE matriz = ARRAY[1..3,1..3] OF integer; VAR A : matriz; BEGIN A[1,1] := 1; A[1,2] := 2; A[1,3] := 3; A[2,1] := 4; A[2,2] := 5; A[2,3] := 6; A[3,1] := 7; A[3,2] := 8; A[3,3] := 9 END. |
Note que a prepresentação do elemento Ai,j é A[i,j]. Realmente mnemônico.
Como representamos agora uma matriz 3 × 2, como a abaixo?
A = | [ |
|
] |
Assim:
TYPE matriz = ARRAY[1..3,1..2] OF integer; VAR A : matriz; BEGIN A[1,1] := 1; A[1,2] := 2; A[2,1] := 3; A[2,2] := 4; A[3,1] := 5; A[3,2] := 6 END. |
E a 2 × 3 abaixo?
A = | [ |
|
] |
Assim:
TYPE matriz = ARRAY[1..2,1..3] OF integer; VAR A : matriz; BEGIN A[1,1] := 1; A[1,2] := 2; A[1,3] := 3; A[2,1] := 4; A[2,2] := 5; A[2,3] := 6 END. |
Agora podemos criar funções para soma e multiplicação de matrizes:
PROGRAM matrizes; TYPE matriz = ARRAY[1..2,1..2] OF integer; VAR m1,m2,m3 :matriz; FUNCTION soma(m1,m2:matriz) : matriz; BEGIN soma[1,1] := m1[1,1] + m2[1,1]; soma[1,2] := m1[1,2] + m2[1,2]; soma[2,1] := m1[2,1] + m2[2,1]; soma[2,2] := m1[2,2] + m2[2,2] END; BEGIN m1[1,1] := 1; m1[1,2] := 2; m1[2,1] := 3; m1[2,2] := 4; m2[1,1] := 5; m2[1,2] := 6; m2[2,1] := 7; m2[2,2] := 8; m3 := soma(m1,m2); writeln(m3[1,1],' ',m3[1,2],' ',m3[2,1],' ',m3[2,2]) END. |
Novamente, alguns compiladores podem não aceitar isso, então, uma versão alternativa com procedimentos é:
PROGRAM matrizes; TYPE matriz = ARRAY[1..2,1..2] OF integer; VAR m1,m2,m3 :matriz; PROCEDURE soma(m1,m2:matriz; VAR m3:matriz); BEGIN m3[1,1] := m1[1,1] + m2[1,1]; m3[1,2] := m1[1,2] + m2[1,2]; m3[2,1] := m1[2,1] + m2[2,1]; m3[2,2] := m1[2,2] + m2[2,2] END; BEGIN m1[1,1] := 1; m1[1,2] := 2; m1[2,1] := 3; m1[2,2] := 4; m2[1,1] := 5; m2[1,2] := 6; m2[2,1] := 7; m2[2,2] := 8; soma(m1,m2,m3); writeln(m3[1,1],' ',m3[1,2],' ',m3[2,1],' ',m3[2,2]) END. |
as funções para subtração, multiplicação e divisão ficam como exercício.
Então, como vimos, matrizes nada mais são que vetores em 2 dimensões. Mas, será que posso fazer em 3 dimensões? Posso fazer em quantas eu quiser...
PROGRAM matrizes; TYPE matriz3D = ARRAY[1..2,1..2,1..2] OF integer; matriz5D = ARRAY[1..3,1..5,1..2,1..2,1..1] of integer; etc |
E como acesso valores nessas matrizes?
PROGRAM matrizes; TYPE matriz3D = ARRAY[1..2,1..2,1..2] OF integer; matriz5D = ARRAY[1..3,1..5,1..2,1..2,1..1] of integer; VAR m1 : matriz3D; m2 : matriz5D; BEGIN m1[1,2,1] := 3; m2[1,1,3,2,1] := 5; etc... END. |
Quando você usará isso? Não sei, mas se precisar...
Por fim, como fazemos para ler todos os valores de uma matriz n × m, dados n e m, e imprimí-los na tela? (Suponha que ela já está carregada)
PROGRAM matrizes; CONST n = 20; m = 30; TYPE matriz = ARRAY[1..n,1..m] OF integer; VAR mat : matriz; {a matriz} cont1 : integer; {contador do primeiro FOR} cont2 : integer; {contador do segundo FOR} BEGIN FOR cont1:=1 TO n DO FOR cont2:=1 TO m DO writeln('mat[',cont1,',',cont2,'] = ',mat[cont1,cont2]) END. |
E para "zerarmos" uma matriz n × m?
PROGRAM matrizes; CONST n = 20; m = 30; TYPE matriz = ARRAY[1..n,1..m] OF integer; VAR mat : matriz; {a matriz} cont1 : integer; {contador do primeiro FOR} cont2 : integer; {contador do segundo FOR} BEGIN FOR cont1:=1 TO n DO FOR cont2:=1 TO m DO mat[cont1,cont2] := 0 END. |
Simples, não? Apenas 2 FORs. Na verdade, você deve usar um FOR para cada dimensão do vetor. Como uma matriz é um vetor em 2 dimensões, usamos 2 FORs, se tivesse k dimensões, teríamos que usar k FORs.
BUSCA BINÁRIA |
Suponha que temos um vetor ordenado, com n elementos, e queremos verificar se um dado elemento, x, está nesse vetor. Como faríamos?
A primeira idéia é comparar x a todo elemento do vetor. Mas isso é lento, pois temos que fazer n comparações, onde n é o número de elementos do vetor.
Podemos usar do fato do vetor estar ordenado para reduzir o tempo de busca. Considere o algoritmo:
1. Seja y0 o 1º elemento do vetor e y1 o último. 2. Seja y o elemento do meio do vetor, ou seja, y = (y0 + y1) DIV 2. 3. Comparo x com y e, se x > y, então x está na metade superior do vetor. Nesse caso faço y0 = y + 1 e volto a 2. Se y0 = y1, x não está no vetor. 4. Se x < y, x está na metade inferior. Então faço y1 = y - 1 e volto a 2. Se y0 = y1, x não está no vetor. 5. Se x = y, achei. y0 = y1, x não está no vetor. |
Notou como é mais rápido? Não comparo com todos, apenas com alguns. Vejamos um exemplo: suponha que queremos saber seo 27 está no vetor abaixo:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|
1 | 5 | 8 | 9 | 12 | 15 | 27 | 30 |
vamos rodar o algoritmo:
1: y0 = 1 e y1 = 8
2: y = 4
3: como 27 > 4, ignoro a 1ª metade do vetor, fazendo y0 = 5. Ou seja, nosso vetor ficou:
5 | 6 | 7 | 8 |
---|---|---|---|
12 | 15 | 27 | 30 |
2: y = 6
3: como 27 > 15, ignoro a 1ª metade do novo vetor, fazendo y0 = 7. Nosso vetor ficou:
7 | 8 |
---|---|
27 | 30 |
2: y = 7
3: falhou, pois 27 não é > 27
4: falhou, pois 27 não é < 27
5: como 27 = 27, achei.
Agora vamos procurar o número 7:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|
1 | 5 | 8 | 9 | 12 | 15 | 27 | 30 |
1: y0 = 1 e y1 = 8
2: y = 4
3: falha, pois 7 não é > 9
4: Como 7 < 9, ignoro a 2ª metade do vetor, fazendo y1 = 3. Nosso vetor fica:
1 | 2 | 3 |
---|---|---|
1 | 5 | 8 |
2: y = 2
3: como 7 > 5, ignoro a 1ª metade do vetor, fazendo y0 = 3. Nosso vetor fica:
3 |
---|
8 |
2: y = 3
3: falha, pois 7 não é > 8.
4: 7 < 8, mas como y0 = y1, então 7 não está no vetor.
Agora, vamos estruturar mais nosso algoritmo:
Seja y0 o 1º elemento do vetor, V, e y1 o último. Seja y o elemento do meio do vetor, ou seja, y = (y0 + y1) DIV 2. enquanto x ≠ V[y] e y0 < y1 se x > V[y] faço y0 = y + 1 senão se x < V[y] faço y1 = y - 1 faço y = (y0 + y1) DIV 2 se x = V[y] achei senão não achei |
Em Pascal isso fica: (Suponha que o vetor já foi carregado com os valores)
CONST MAX = 8; VAR v : ARRAY[1..MAX] OF integer; y0 : integer; y1 : integer; y : integer; x : integer; BEGIN {carreguei o vetor...} {começo o algoritmo} y0 := 1; y1 := MAX; y := (y0 + y1) DIV 2; write('Entre o inteiro a ser buscado: '); readln(x); WHILE (x <> v[y]) AND (y0 < y1) DO BEGIN IF x > v[y] THEN {parte superior} y0 := y + 1 ELSE IF x < v[y] THEN y1 := y - 1; y := (y1 + y0) DIV 2 END; IF x = v[y] THEN writeln('encontrado na posição: ',y) ELSE writeln('elemento não encontrado no vetor) END. |
O nome dessa busca é busca binária, pois, a cada passo, jogo fora metade do vetor em que estou trabalhando.