Pensamento Computacional - Arrays Unidimensionais no Java

De MediaWiki do Campus São José
Ir para navegação Ir para pesquisar

Conceito de Array

Um array unidimensional ou vetor pode ser visto como uma variável (uma caixa) dividida em partes menores (CAIXAS menores) acessadas por um índice (posição). Podemos dizer que cada elemento do vetor pode ser acessado através da indexação do vetor. Os elementos do vetor possuem um tipo único.


PRG1-vetor armario.png


Uma boa analogia é comparar o vetor com uma tabela de tamanho fixo onde em cada linha pode ser armazenado um elemento.


PRG1-tabela vetor.png

Observe que com o mecanismo de criação de vetor será possível armazenar dados de uma forma organizada e de forma que se possa operar em diversos momentos do processamento.

Exemplo 1

Suponha que em uma determinada turma de 5 alunos queremos armazenar os valores das notas finais (valores inteiros de 0 a 10).

Neste caso o tamanho do array será 5. As indexações possíveis do array serão de 0 a 4 portanto. O tipo de cada elemento é inteiro, devido as notas inteiras.

Uma possível solução para isso seria:

import java.util.Scanner;

public class TabelaNotas {
    public static void main(String[] args) {
        int[]  TabelaNotas = new int[5];
        Scanner teclado = new Scanner(System.in);

        for (int i = 0; i < 5; i++) {
            System.out.println("Entre com a nota do aluno " + i);
            TabelaNotas[i] = teclado.nextInt();
        }
        System.out.println("Dados armazenados!!!");
        /* imprimindo os dados lidos... */
        for (int i = 0; i < 5; i++) {
            System.out.println("Nota da posição " + i + " é " + TabelaNotas[i]);
        }
        teclado.close();
    }
}

DISCUSSÃO:

Inicialmente a instrução:

int[]  TabelaNotas = new int[5];

Declara a referência para o vetor TabelaNotas e cria um vetor de tamanho 5 associado a esta referÊncia. De agora em diante, podemos trabalhar este vetor (lendo e escrevendo sobre cada elemento dele).

Observe que as 5 notas serão "lidas" para o vetor de inteiros TabelaNotas. Preste atenção a forma como é indexado o vetor:

            TabelaNotas[i] = teclado.nextInt();

Verifique o uso de colchetes com o índice do elemento que está sendo acessado. Na realidade, o índice pode ser qualquer expressão inteira que resulte em 0 a 4. Um ponto importante a ser observado é que este limite da indexação deve ser respeitado. Vamos a um exemplo que teremos problemas por acesso indevido:

import java.util.Scanner;

public class TabelaNotas {
    public static void main(String[] args) {
        int[]  TabelaNotas = new int[5];
        Scanner teclado = new Scanner(System.in);

        for (int i = 0; i < 5; i++) {
            System.out.println("Entre com a nota do aluno " + i);
            TabelaNotas[i+5] = teclado.nextInt();
        }
        System.out.println("Dados armazenados!!!");
        /* imprimindo os dados lidos... */
        for (int i = 0; i < 5; i++) {
            System.out.println("Nota da posição " + i + " é " + TabelaNotas[i]);
        }
        teclado.close();
    }
}

DISCUSSÃO : Ao tentar executar este código teremos um erro logo de início:

Entre com a nota do aluno 0
9
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
       at TabelaNotas.main(TabelaNotas.java:11)

A instrução:

           TabelaNotas[i+5] = teclado.nextInt();

logo no primeiro laço do loop, quando i estiver em 0, tentará escrever na posição 5 do vetor o que não é permitido pois o vetor não possui eta posição.

Um outro ponto importante é que uma array não pode ser redimensionado. Uma vez criado ele manterá sempre o seu tamanho. Isto pode ser contornado através da criação de um novo array de tamanho maior ou menor e, então, copiando devidamente os elementos do array original.

Exemplo 2

Vamos a um problema um pouco mais complexo: Implementar um programa Java para ler 5 notas inteirass para um vetor e imprimir a quantidade (o número) de números acima da média.

DICA: Definir um contador, iniciado em zero. Ler os 5 números para um vetor e calcular a media. Fazer um segundo loop sobre o vetor testando cada item para verificar se é maior que a média. Incrementar o contador a cada item acima da média.

Este problema exige que os dados sejam armazenados previamente, de forma que a média calculada possa posteriormente ser usada para a computação da quantidade de números que estão acima da média.

DADOS DE ENTRADA: 5 números a serem fornecidos.
DADOS DE SAÍDA: Quantidade de números acima da média.
import java.util.Scanner;

public class NumerosAcimaMedia {
    public static void main(String[] args) {
        int[]  TabelaNotas = new int[5];
        Scanner teclado = new Scanner(System.in);
        double media;
        int somaAc, contAcima;

        for (int i = 0; i < 5; i++) {
            System.out.println("Entre com a nota do aluno " + i);
            TabelaNotas[i] = teclado.nextInt();
        }     
        /* os números já estão no vetor... Vamos calcular a média deles... */
        somaAc = 0;
        for (int i = 0; i < 5; i++) {
            somaAc += TabelaNotas[i];
        }          
        media = (double) somaAc / 5; 
        System.out.println("Media calculada é " + media); 
        /* agora vamos olhar para cada elemento do vetor e contar as ocorrências acima da média */  
        contAcima = 0;
        for (int i = 0; i < 5; i++) {
            if ( TabelaNotas[i] > media )
                contAcima++;
        }    
        System.out.println("Notas acima da média: " + contAcima);         
    }
}

Exercício 1

Modificar o exemplo anterior para que seja calculada a média das notas notas abaixo de 6.

Exercício 2

Modificar o exemplo anterior para que seja calculado o desvio padrão da turma. Ver o que é desvio padrão aqui. OBS: Será necessário usar a função de raiz quadrada e de potenciação da biblioteca matemática.

Inicialização de um Vetor

Um vetor pode ser inicializado com valores já na sua criação:

 String tabelaNomes[] = new String[] {"IFSC", "IFRS", "IFRN"};

A dimensão da tavelaNomes será 3 neste caso, pois não fornecido o tamanho do vetor.

Exemplo 3 - Controle de Acesso

Um sistema de controle de acesso permite armazenar até 5 senhas alfanuméricas. De fábrica o produto vem com uma tabela já predefinida da forma:

 String[] tabelaSenhas  = new String[]{"alfa","beta","delta","gama", "epson"};

Elaborar um programa Java para abrir a porta para um usuário cuja senha está na tabela.

import java.util.Scanner;

public class ControleAcesso {
    public static void main(String[] args) {
        String[] tabelaSenhas  = new String[]{"alfa","beta","delta","gama", "epson"};
        Scanner teclado = new Scanner(System.in);
        String senhaLida;
        boolean itemEncontrado;

        while (true) {
            System.out.println("Entre com uma senha");
            senhaLida = teclado.nextLine();
            itemEncontrado = false;
            for (  int i = 0; i < tabelaSenhas.length; i++) {
                if (tabelaSenhas[i].equals(senhaLida)) {
                    System.out.println("Abrir a porta");
                    itemEncontrado = true;
                    break;
                }
            }
            if ( itemEncontrado == false ) {
                System.out.println("Usuário não reconhecido!!!");
            }
        }
    }
}

Exercício 3

Modifique o exemplo anterior para que exista também um USERID por cada senha. Para tanto, faça uma estratégia que cada linha para da tabela armazene o USERID e a na sequência a senha. OBS: Esta talvez não seja a melhor solução para este tipo de problema, como será visto nas UCs que se seguem.

Formas de "iterar" um array

O termo ITERAÇÃO é usado em computação para denotar a repetição de uma mesma ação sobre diferentes elementos de um dado conjunto.

No exemplo acima, os elementos do vetor foram "iterados" usando um comando for da forma:

            for (  int i = 0; i < tabelaSenhas.length; i++) {
                if (tabelaSenhas[i].equals(senhaLida)) {
                    System.out.println("Abrir a porta");
                    itemEncontrado = true;
                    break;
                }
            }

Esta abordagem pode ser usada também com comandos while() e do while().

É possível também usar a seguinte variação na iteração, conhecida como "for each" (para cada):

            for (  String senha : tabelaSenhas ) {
                if ( senha.equals(senhaLida) ) {
                    System.out.println("Abrir a porta");
                    itemEncontrado = true;
                    break;
                }
            }

Notar aqui que o comando for não contém as tradicionais três partes separadas por ponto-e-vírgula. É implícito que a cada laço do loop a variável senha assumirá o próximo valor armazenado no vetor. É importante observar que esta forma de acessar pode não ser a mais conveniente em determinadas situações que exijam, por exemplo, modificar um item de um array. Na abordagem de armazenamento de USERID seguido de SENHA no exemplo de controle de acesso também pode ser necessário um processamento extra.

Passando um vetor como parâmetro de um método

Observe a seguir o método mediaVetor(), que tem como parâmetro um vetor cuja média será computada e retornada:

public class MediaVetor {
    public static double mediaVetor(int[] meuVetor) {
        int somaAc = 0;
        for ( int x : meuVetor) {
            somaAc += x;
        }
        return (double) somaAc / meuVetor.length;
    }
    public static void main(String[] args) {
        int[] vetorTeste1 = new int[]{10, 20, 5, 10};

        System.out.println("Média do vetor teste 1 é " + mediaVetor(vetorTeste1));
    }
}

Aparentemente, a sintaxe usada segue o que foi visto até agora. Entretanto, existe uma diferença semântica: arrays são passados como REFERÊNCIA. Isto quer dizer que se o vetor for modificado dentro do método, o vetor original será modificado. Ou seja, ao contrário de parãmetros inteiros, double etc., que recebem cópias dos valores na chamada do método, arranjos são passados por endereço.

Exemplo 4

public class MediaVetorZerando {
    public static double mediaVetorZerando(int[] meuVetor) {
        int somaAc = 0, i;

        i = 0;
        for ( int x : meuVetor) {
            somaAc += x;
            meuVetor[i] = 0;
            i++;
        }

        return (double) somaAc / meuVetor.length;
    }
    public static void main(String[] args) {
        int[] vetorTeste1 = new int[]{10, 20, 5, 10};

        System.out.println("Média do vetor teste 1 é " + mediaVetorZerando(vetorTeste1));
        for ( int x : vetorTeste1) {
            System.out.println(x);
        }        
    }
}

Exemplo 5

Implementar um método que recebe um arranjo de inteiros como parâmetro. O método deve zerar todos os elementos negativos. O A quantidade de elementos zerados deve ser retornada.

import java.util.Arrays;
public class SubstituirNegativos {

    public static int substituirNegativosPorZero(double[] array) {
        int countZeros = 0;
        for (int i = 0; i < array.length; i++) {
            if (array[i] < 0) {
                array[i] = 0;
                countZeros++;
            }
        }
        return countZeros;
    }

    public static void main(String[] args) {
        double[] numeros = {2.5, -1.3, 4.8, -3.0, 5.7};

        System.out.println("Array original: " + Arrays.toString(numeros));

        int quantidadeZeros = substituirNegativosPorZero(numeros);

        System.out.println("Array modificado: " + Arrays.toString(numeros));
        System.out.println("Quantidade de elementos substituídos por zero: " + quantidadeZeros);
    }
}

Exercício 4

Implementar um método capaz de retornar o index de um elemento de um array de strings que possui a primeira ocorrência de uma string também passada como parâmetro. O método deve retornar -1 caso não encontre uma ocorrência.

public class RetornoIndexArray {
    public static int indexArray(String[] vetorStrings, String stringProcurada) {
        /* implementar a busca aqui  */

        return -1;
    }
    public static void main(String[] args) {
        String[] teste = new String[] {"alfa", "beta", "gamma", "delta"};
        int retorno;

        retorno = indexArray(teste, "gamma");
        System.out.println("Index retornado é " + retorno);

    }
}

Exercício 5

Implementar um método em java que recebe um arranjo de inteiros e retorna a quantidade de números pares que estão no arranjo. Teste no método main() chamando pelo menos duas vezes.

Exercício 6

Implementar um método java que recebe um arranjo de inteiros como parâmetro e retorna true se os números estão em ordem crescente ou false se não estão. Testar chamando pelo menos duas vezes no método main().

Exercício 7

Considere um arranjo de strings que representa userids e senhas. Nas posições pares estão os userids e nas posições ímpares as respectivas senhas. Implemente um método que recebe como parâmetro uma tabela conforme este array, um userid (uma string) e uma nova senha (uma string). O método deve encontrar o userid e substituir a senha. Ele retorna false se nada foi modificado e verdadeiro se houve uma modificação.

Retorno de Array em Métodos

Um ponto importante é que é possível retornar um array (por referência) em um método. Vamos a um exemplo.

Exemplo 6

Implementar um método que recebe 2 arrays de double de mesma dimensão como parâmetros e retorna um array contendo a soma dos mesmos.

public class SomaArrays {

    public static double[] somarrArrays(double[] array1, double[] array2) {
        /* Aqui seria interessante fazer um tratamento de exceção para o caso de dimensões diferentes */

        double[] resultado = new double[array1.length];
        for (int i = 0; i < array1.length; i++) {
            resultado[i] = array1[i] + array2[i];
        }
        return resultado;
    }

    public static void main(String[] args) {
        double[] array1 = {1.5, 2.0, 3.5, 4.0, 5.5};
        double[] array2 = {2.0, 1.5, 2.5, 2.0, 1.5};
        
        double[] resultado = somarArrays(array1, array2);

        System.out.print("Resultado da soma: ");
        for (double elemento : resultado) {
            System.out.print(elemento + " ");
        }
    }
}

Exercício 7

Implementar um método que recebe um array de strings e retorna um array com as strings capitalizadas. Use o método toUpperCase() associado a uma string conforme exemplo abaixo:

public class CapitalizarString {

    public static void main(String[] args) {
        String texto = "exemplo de string";
        String capitalizado = texto.toUpperCase();

        System.out.println("Original: " + texto);
        System.out.println("Capitalizado: " + capitalizado);
    }
}

Explorando o lado da criação dinâmica de arranjos

Observe que a criação "dinãmica" de arranjos simplifica determinadas soluções de problemas que exigem flexibilidade na criação de uma estrutura de dados cujo tamanho não é conhecido previamente à execução do programa.

import java.util.Scanner;

public class TabelaNotas {
    public static void main(String[] args) {
        int[]  TabelaNotas;
        Scanner teclado = new Scanner(System.in);

        System.out.println("Entre com o tamanho da turma");
        int tamanhoTurma = teclado.nextInt();
        TabelaNotas = new int[tamanhoTurma];

        for (int i = 0; i < TabelaNotas.length; i++) {
            System.out.println("Entre com a nota do aluno " + i);
            TabelaNotas[i] = teclado.nextInt();
        }
        System.out.println("Dados armazenados!!!");
        /* imprimindo os dados lidos... */
        for (int i = 0; i < TabelaNotas.length; i++) {
            System.out.println("Nota da posição " + i + " é " + TabelaNotas[i]);
        }
        teclado.close();
    }
}

Observe neste exemplo que a TabelaNotas é criada com a dimensão dos dados a serem armazenados:

    TabelaNotas = new int[tamanhoTurma];


Execícios Prova Turma 2

import java.util.Scanner;

public class Q1 {
    public static void main(String[] args) {
        Scanner teclado = new Scanner(System.in);
        double na1,na2,na3,nr1,nr2,nr3,vFreq;
        System.out.print("Entre coma nota 1 e a rec 1: ");
        na1 = teclado.nextDouble();
        nr1 = teclado.nextDouble();        
        System.out.print("Entre coma nota 2 e a rec 2: ");
        na2 = teclado.nextDouble();
        nr2 = teclado.nextDouble(); 
        System.out.print("Entre coma nota 3 e a rec3: ");
        na3 = teclado.nextDouble();
        nr3 = teclado.nextDouble(); 
        System.out.print("Entre com a frequência (%): ");
        vFreq = teclado.nextDouble();
        int notaFinal = calcularResultadoFinal(na1, nr1, na2, nr2, na3, nr3, vFreq);
        System.out.println("Resultado Final: " + notaFinal);
        if (notaFinal >= 6) 
            System.out.println("Aprovado");
        else
            System.out.println("Reprovado");
        teclado.close();
    }
    public static int calcularResultadoFinal(double a1, double r1, double a2, double r2, double a3, double r3, double freq) {
        if (freq  < 75) {
            return 0;
        } else {
            double res = media(maior(a1,r1), maior(a2,r2), maior(a3,r3));
            return (int) Math.round(res);
        }

    }   
    public static double maior(double num1, double num2) {
        double maiorNum;
        if (num1 > num2) {
            maiorNum = num1;
        } else {
            maiorNum = num2;
        }
        return maiorNum;
    }

    public static double media(double num1, double num2, double num3) {
        double res = (num1 + num2 + num3) / 3;
        return res;
    }    
}
import java.util.Scanner;

public class Q2 {
    public static void main(String[] args) {
        Scanner teclado = new Scanner(System.in);

        // Declare um arranjo de inteiros de tamanho 30 para armazenar os bits
        int[] bits = new int[30];

        System.out.println("Digite uma sequência de bits (0, 1) separados por espaços. Use -1 para indicar o fim:");

        // Lê a sequência de bits do teclado
        int bit;
        int index = 0;
        while (true) {
            bit = teclado.nextInt();

            // Verifica se o usuário digitou -1 para indicar o fim
            if (bit == -1 || index >= 30) {
                break;
            }

            // Armazena o bit no arranjo
            bits[index] = bit;
            index++;
        }

        // Calcula o número decimal a partir da representação binária
        int decimal = 0;
        for (int i = 0; i < index; i++) {
            decimal += bits[i] * Math.pow(2, index - 1 - i);
        }

        // Exibe o número decimal na tela
        System.out.println("O número decimal correspondente é: " + decimal);
    }
}