Capítulo 7 Vectores Vectores (array) uni-dimensionais e bi-dimensionais Algoritmos básicos com vectores: contagem e pesquisa de elementos Alteração de dimensão de vectores Vectores dinâmicos (array list) Classes wrapper, auto-boxing e o ciclo for generalizado A importância dos vectores • Como determinar quais as temperaturas da semana acima da média? ... int count; double temperature, sum, average; Scanner keyboard = new Scanner(System.in); System.out.println(“Enter the 7 temperatures of the week “); for (int count = 0; count < 7; count++) { temperature = keyboard.nextDouble(); sum = sum + temperature } average = sum / 7; ... Introdução à Programação 2007/08 A. Lopes Vectores (arrays) • Um vector é uma sequência de valores do mesmo tipo. Dito de outra forma, é uma colecção de variáveis do mesmo tipo • Construção e armazenamento de um vector // vector armazenado numa variável do tipo double[] double[] data = new double[10]; • Na criação de um vector, os seus elementos são inicializados com valores de acordo com o respectivo tipo • números: com o valor 0 • tipo boolean: com o valor false • referências a objectos: com o valor null Introdução à Programação 2007/08 A. Lopes Vectores • Acesso a um elemento • utilização de [ ] • o índice é um expressão cujo resultado é um número inteiro data[2] = 29.95; // armazena um valor no vector referência a um vector e ao valor do elemento Introdução à Programação 2007/08 A. Lopes Vectores • Utilização de um valor guardado no vector System.out.println("The value of this data item is " + data[4]); • A dimensão do vector pode ser consultada em data.length. Este atributo é definido aquando da criação do vector e não é alterável • Os índices variam de 0 a length - 1 • Acesso a um elemento não existente resulta num erro de limites do vector double[] data = new double[10]; data[10] = 29.95; // incorrecto • Os vectores têm comprimento fixo - a sua dimensão - o que pode ser limitativo em alguns casos Introdução à Programação 2007/08 A. Lopes Construção de um vector new typeName [ length ] Exemplo: new double[10] Objectivo: Construir um vector com determinada dimensão (ou comprimento) Introdução à Programação 2007/08 A. Lopes Acesso a um elemento de um vector arrayReference [ index ] Exemplo: data[2] Objectivo: Aceder a um elemento do vector Introdução à Programação 2007/08 A. Lopes Vectores parcialmente preenchidos • O comprimento de um vector é o número máximo de elementos no vector • Geralmente, um vector nunca está totalmente preenchido. É pois conveniente utilizar uma variável em paralelo, que guarde o número de elementos efectivamente definidos no vector • Essa variável em paralelo é actualizada sempre que existam alterações no número de elementos efectivos no vector Introdução à Programação final int DATA_LENGTH = 100; double[] data = new double[DATA_LENGTH]; int dataSize = 0; data[dataSize] = x; dataSize++; 2007/08 A. Lopes Cópia de vectores cópia da referência ao vector • A cópia de uma variável do tipo array origina a existência de uma segunda referência ao mesmo vector double[] data = new double[10]; // preenche o vector ... double[] prices = data; duas variáveis para o mesmo vector Introdução à Programação 2007/08 A. Lopes Cópia de vectores clonagem • Utilização do método clone de modo a que a cópia seja totalmente efectiva cast é obrigatório double[] prices = (double[]) data.clone(); Introdução à Programação 2007/08 A. Lopes Cópia de vectores cópia dos elementos de um vector System.arraycopy(from, fromStart, to, toStart, count); Introdução à Programação 2007/08 A. Lopes Inserção de um elemento num vector System.arraycopy(data, i, data, i + 1, data.length - i - 1); data[i] = x; o espaço a libertar, para inserir x Introdução à Programação 2007/08 A. Lopes Remoção de um elemento de um vector System.arraycopy(data, i + 1, data, i, data.length - i - 1); o elemento a remover Introdução à Programação 2007/08 A. Lopes Crescimento de um vector • Quando a capacidade do vector é atingida, e sendo necessário mais espaço, o vector tem de crescer. Para isso: • cria-se um novo vector, de maior dimensão (o dobro por exemplo) double[] newData = new double[2 * data.length]; • copiam-se todos os elementos do vector em uso para esse novo vector System.arraycopy(data, 0, newData, 0, data.length); • armazena-se a referência desse novo vector na variável em causa data = newData; Introdução à Programação 2007/08 A. Lopes Crescimento de um vector 1 double[] newData = new double[2 * data.length]; 2 System.arraycopy(data, 0, newData, 0, data.length); 3 data = newData; 3 2 1 Introdução à Programação 2007/08 A. Lopes Vectores e elementos de vectores em métodos • Uma variável indexada de um vector pode ser utilizada em qualquer parte em que uma variável do mesmo tipo é utilizada. Por exemplo, como argumento de um método • A declaração de um vector num método é análoga à declaração normal de um vector • Um método pode retornar um vector Introdução à Programação 2007/08 A. Lopes Vectores e elementos de vectores em métodos import java.util.*; public class vectorMetodosDemo { ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! } public static int[] geraNumeros(int n) { ! int [] aleatorios = new int[n]; ! Random gerador = new Random(); ! for (int i=0; i<n; i++) ! ! aleatorios[i] = gerador.nextInt(n); // um numero em [0..n[ ! return aleatorios; } public static void mostraNumeros(int[] vec) { ! for (int i=0; i< vec.length; i++) ! ! System.out.println("Numero " + i + ": " + vec[i]); }! public static void main(String[] args) { ! ! ! ! Scanner in = new Scanner(System.in); ! System.out.println("Quantidade de numeros aleatorios a gerar: "); ! int n = in.nextInt(); ! int [] numeros = geraNumeros(n); ! mostraNumeros(numeros);! } Introdução à Programação 2007/08 A. Lopes Vectores de objectos em vez de vectores paralelos // evitar vectores paralelos int[] accountNumbers; double[] balances; Introdução à Programação 2007/08 A. Lopes Vectores de objectos em vez de vectores paralelos • Os vectores paralelos devem dar lugar a vectores de objectos de determinada classe, e os seus métodos passam a ser aplicados aos elementos do vector BankAccount[] accounts = new BankAccount(10); ... System.out.println(“Saldo da conta: “ + accounts[0].getBalance()); Introdução à Programação 2007/08 A. Lopes Exemplo de utilização de vectores um banco com contas bancárias 1 Bank Bank - accounts : BankAccount[] - accountsCounter : int + Bank( limit : int ) + addAccount( acc : BankAccount) + removeAccount( indAccount : int ) + getTotalBalance() : double + accountsAtLeast( atLeast : double ) : int + getMaximum() : BankAccount + find( accountNumber : int ) : BankAccount + accountAt( indAccount : int ) : BankAccount + getNumberAccounts() : int + getLimitAccounts() : int Introdução à Programação 2007/08 * BankAccount BankAccount - balance : double - accountNumber : int + BankAccount( number : int ) + BankAccount( number : int, initialBalance : int ) + deposit( amount : int ) + withdraw( amount : int ) + getBalance() : double + getAccountNumber() : int A. Lopes Algoritmos básicos com vectores pesquisar um valor • Analisa todos os elementos até encontrar o/um que procura /** Finds a bank account with a given number. @param accountNumber the number to find accounts @return the account with the given number, or null if there is no such account */ 1001 123.40 public BankAccount find(int accountNumber) { 1002 34.50 for (int i = 0; i < accountsCounter; i++) 1007 1993.0 { if (accounts[i].getAccountNumber() == accountNumber) 1003 57.80 // found an element return accounts[i]; 1005 1123.20 } return null; // no element has been found 1006 1678.30 } Introdução à Programação 2007/08 A. Lopes Algoritmos básicos com vectores contagem de determinado elemento • Analisa todos os elementos e conta os que têm determinada característica que procura até chegar ao fim do vector /** Counts the number of bank accounts whose balance is at least a given value. @param atLeast the balance required to count an account @return the number of accounts having at least the given balance */ accounts 1001 123.40 1002 34.50 public int accountsAtLeast(double atLeast) { int matches = 0; for (int i = 0; i < accountsCounter; i++) { if (accounts[i].getBalance() >= atLeast) matches++; // found an element } return matches; 1003 57.80 1005 1123.20 1006 1678.30 } Introdução à Programação 1007 1993.0 2007/08 A. Lopes Algoritmos básicos com vectores pesquisa o máximo e o mínimo • Inicializa o potencial candidato com um elemento inicial. De seguida, percorrendo o vector, compara o candidato com os restantes elementos, actualizando-o se encontrar um elemento de maior (menor) valor • O método só funciona se existir pelo menos um elemento no vector. Se o vector estiver vazio, deve devolver null /** Gets the bank account with the largest balance. @return the account with the largest balance, or null if the bank has no open accounts */ public BankAccount getMaximum() { if (accountsCounter == 0) return null; BankAccount largestYet = accounts[0]; for (int i = 1; i < accountsCounter; i++) { BankAccount acc = accounts[i]; if (acc.getBalance() > largestYet.getBalance()) largestYet = acc; } return largestYet; } Introdução à Programação 2007/08 accounts 1001 123.40 1002 34.50 1007 1993.0 1003 57.80 1005 1123.20 1006 1678.30 A. Lopes Algoritmos básicos com vectores remove um elemento /** Removes an account located at the specified indice in the bank, and moves the last account to that position. @param indAccount is the indice in the bank of the account to be removed @return the removed account or null if the operation is not valid */ public BankAccount removeAccount(int indAccount) { accounts 1001 123.40 if (indAccount >= 0 && indAccount < accountsCounter) { 1002 34.50 BankAccount acc = accounts[indAccount]; accountsCounter--; 1007 1993.0 accounts[indAccount] = accounts[accountsCounter]; 1003 57.80 // the last one has just been moved to this position return acc; } return null; 1006 1678.30 } Introdução à Programação 1005 1123.20 2007/08 A. Lopes Ficheiro Bank.java Introdução à Programação 2007/08 A. Lopes Ficheiro BankAccount.java Introdução à Programação 2007/08 A. Lopes Ficheiro BankTester.java Introdução à Programação 2007/08 A. Lopes Vectores bi-dimensionais • Para construir um vector bi-dimensional, é preciso indicar o número de linhas e de colunas que se pretende • Os elementos do vector são acedidos através de um índice duplo a[i][j] final int ROWS = 3; final int COLUMNS = 3; String[][] board = new String[ROWS][COLUMNS]; board[i][j] = "x"; Introdução à Programação 2007/08 A. Lopes Percurso em vectores bi-dimensionais • Por norma, utilizam-se dois ciclos for encadeados quando se pretende preencher ou pesquisar o vector for (int i = 0; i < ROWS; i++) for (int j = 0; j < COLUMNS; j++) board[i][j] = " "; Introdução à Programação 2007/08 A. Lopes Vectores bi-dimensionais de dimensão diferenciada • O Java permite a existência de vectores cujo comprimento das linhas difere entre si int[][] vec = new int[3][]; // vector com 3 linhas vec[0] = new int[4]; // 1ª linha terá 4 inteiros vec[1] = new int[5]; // 2ª linha terá 5 inteiros vec[2] = new int[2]; // 3ª linha terá 2 inteiros vec[0][0] = 34; ... for (int i=0; i < vec.length; i++) for (int j=0; j < vec[i].length; j++) System.out.println(“vec[“+i+”][“+j+”] : “+vec[i][j]); // exemplo, em alternativa, de inicialização na declaração int[][] vec = { {34, 2, 5, 6}, {1, 2, 3, 4, 5}, {2, 1} }; Introdução à Programação 2007/08 A. Lopes Ficheiro TicTacToe.java Introdução à Programação 2007/08 A. Lopes Ficheiro TicTacToeTester.java Introdução à Programação 2007/08 A. Lopes Vectores dinâmicos (array list) • A classe ArrayList permite manipular uma sequência de objectos, que pode aumentar ou diminuir se necessário • São disponibilizados vários métodos para tarefas comuns, como por exemplo para inserir ou remover elementos. O método size indica o número de elementos • A classe ArrayList é uma classe genérica: ArrayList<T> “colecciona” objectos do tipo T ArrayList<BankAccount> accounts = new ArrayList<BankAccount>(); accounts.add(new BankAccount(1001)); accounts.add(new BankAccount(1015)); accounts.add(new BankAccount(1022)); Introdução à Programação 2007/08 A. Lopes Acesso a elementos de um vector dinâmico • os índices começam em 0 e não pode se pode aceder a nenhum elemento fora dos respectivos limites // obtém o 3º elemento do vector BankAccount anAccount = accounts.get(2); int i = accounts.size(); anAccount = accounts.get(i); // erro: os índices têm de estar entre 0 e i-1 Introdução à Programação 2007/08 A. Lopes Inserção de elementos • escrever sobre um valor existente BankAccount anAccount = new BankAccount(1729); accounts.set(2, anAccount); • inserir um valor antes do valor que está num índice 1 2 accounts.add(i, a) • para acrescentar accounts.add(a) Introdução à Programação 2007/08 A. Lopes Remoção de elementos • remover um elemento num índice 1 2 accounts.remove(i) • remover todos os elementos accounts.clear() Introdução à Programação 2007/08 A. Lopes Ficheiro ArrayListTester.java ... com a classe BankAccount Introdução à Programação 2007/08 A. Lopes Wrappers • Não é possível colocar tipos primitivos directamente em vectores dinâmicos. Para processar valores desse tipo, é necessário utilizar classes wrapper ArrayList<Double> data = new ArrayList<Double>(); data.add(29.95); double x = data.get(0); Objecto de uma classe Wrapper Introdução à Programação 2007/08 A. Lopes Wrappers existentes Introdução à Programação 2007/08 A. Lopes Auto-boxing • Com auto-boxing (Java 5.0), a conversão entre um tipo primitivo e a correspondente classe wrapper é automática • Auto-boxing também funciona em expressões aritméticas Double d = 29.95; // auto-boxing; // equivalente a Double d = new Double(29.95); double x = d; // auto-unboxing; // equivalente a double x = d.doubleValue(); 1. auto-unbox d num double Double e = d + 1; 2. adiciona 1 3. auto-box o resultado num novo Double Introdução à Programação 2007/08 4. armazena a referência no recém criado objecto wrapper em e A. Lopes Ciclo for generalizado • Percorre todos os elementos da colecção, não permitindo alterações nas referências a esses elementos (ou nos próprios se forem do tipo primitivo) double[] data = ...; double sum = 0; for (double e : data) // "para cada e em data" { sum += e; } • Alternativa clássica: double[] data = ...; double sum = 0; for (int i = 0; i < data.length; i++) { double e = data[i]; sum += e; } Introdução à Programação 2007/08 A. Lopes Ciclo for generalizado • Com vectores dinâmicos ArrayList<BankAccount> accounts = ... ; double sum = 0; for (BankAccount a : accounts) { sum += a.getBalance(); } • equivalente ao ciclo clássico: double sum = 0; for (int i = 0; i < accounts.size(); i++) { BankAccount a = accounts.get(i); sum += a.getBalance(); } Introdução à Programação 2007/08 A. Lopes Ciclo "for each" for (type variable : collection) statement Exemplo: for (double e : data) sum += e; Objectivo: Para executar um ciclo para cada elemento da colecção. Em cada iteração, a variável e é associada ao próximo elemento da colecção. De seguida, executa a instrução. Note-se que, dentro do ciclo, não é possível alterar a variável e Introdução à Programação 2007/08 A. Lopes