class
Transcrição
class
Estrutura de Dados com Orientação a Objetos Professor Dr. Artur Henrique Kronbauer Classes e Objetos • Programadores que utilizam POO criam e/ou usam objetos a partir de classes, que são relacionadas diretamente com os modelos descritos. • Classes são estruturas utilizadas para descrever os modelos, ou seja, contém a descrição das variáveis (atributos) e das rotinas (métodos) que podem ser realizadas sobre eles. • Um objeto ou instância é a materialização da classe. • As variáveis contidos em uma classe são conhecidos como campos ou atributos daquela classe. Nome da Classe Atributo 1 Atributo 2 Atributo 3 ••• Método 1 Método 2 • Cada campo deve ter um nome e ser de um tipo de dado nativo ou uma classe existente. • As rotinas contidas são os métodos. • Métodos podem receber argumentos (parâmetros). • O nome mais os parâmetros do método são chamados de assinatura. ••• 2 Classes e Objetos • Para que objetos ou instâncias possam ser manipulados, é necessária a criação de referências a estes objetos, que são variáveis do “tipo” da classe. • Classe -> Planta do edifício, que descreve o edifício, mas não corresponde fisicamente a ele. • Instância -> Edifício construído. • Referência -> Nome do Objeto (ilhaDoSol) Classe Edifício instâncias Edifício ilhaDoSol Edifício palaci Edifício iguatemi 3 Classes e Objetos • • Uma classe em Java será declarada com a palavra-chave class seguida do nome da classe. • O nome não pode conter espaços. • Deve começar com uma letra. • Deve ser diferente das palavras reservadas. • Caracteres maiúsculos e minúsculos são diferenciados. • Conteúdo da classe limitado pelas chaves { }. Exemplo: class Empregado Nome da classe { String Nome; Atributo public String getNome( ) { return Nome; } Método } 4 Campos declarados nas classes • Os campos das classes (atributos) devem ser declarados dentro do corpo da classe. • Cada campo deve ser representado por um determinado tipo de dado. • Em linguagens OO, é possível declarar campos como referências a instâncias de outras classes já existentes (Objetos). • Também é possível declarar campos de tipos primitivos da própria linguagem (Variáveis). • A declaração é simples, basta declarar o tipo de dado, seguido dos nomes dos campos que são daquele tipo. • Podemos observar que, para cada dado do modelo existe um campo correspondente na classe. • Campos podem ser referências a uma classe. 5 Tipos Primitivos (Nativos da linguagem Java) Tipo byte short int long float double char boolean • Faixa de Valores -128 a 127 -32.768 a 32.767 -2.147.483.648 até 2.147.483.647 -9.223.372.036.854.775.808 a 9.223.372.036.854.775.807 1.401298464324811707e-45 a 3.40282346638528860e+38 4.94065645841246544e-324 a 1.79769313486231570e+308 Representam um único caracter True ou False Armazenamento Inteiro de 8 bits Inteiro de 16 bits Inteiro de 32 bits Inteiro de 64 bits Ponto Flutuante de 32 bits 8 bytes ou 64 bits 16 bits 1 bit A classe String é usada para representar cadeias de caracteres. (Não são dados nativos, sendo instâncias da classe String) 6 Operadores da Linguagem Java • • Operadores Aritméticos + (soma) - (subtração) * (multiplicação) / (divisão) % (resto de uma divisão inteira) int(A) / int(B) (parte inteira de uma divisão) Operação com instâncias da classe String. • + (concatenação) • • Operadores Relacionais < (menor) > (maior) <= (menor ou igual) >= (maior ou igual) == (igual) != (diferente) Operadores Lógicos && (and) II (or) ! (não lógico) Operadores relacionais para a classe String equals if (nome.equals(“Maria”) !equals if (!nome.equals(“Maria”) 7 Composição de uma programação Orientada a Objetos • Programas orientados a objetos, são compostos por: • conjuntos de objetos que representam os objetos existentes no negócio modelado. • conjuntos de objetos que representam estruturas adequadas para a manipulação de dados. • Os objetos que compõem o programa comunicam-se por trocas de mensagens. • O programa precisa ter um ponto de entrada que indique à máquina virtual onde iniciar a execução. public class Aplicacao { public static void main(String[] s) { } } 8 Composição de uma programação Orientada a Objetos • public static void main(String[] args) • public: é visível para qualquer outra classe. • static: dispensa a criação de objetos. • void: nenhum retorno esperado. • main: convenção para indicar a máquina virtual qual o ponto de entrada da aplicação. • String[] args: parâmetros passados pela aplicação via linha de comando. args é o identificador. 9 Saída de Dados Padrão • Representada por um atributo estático da classe System System.out.println(...) • Tipos primitivos podem ser concatenados a Strings através do operador + • Exemplo: class saidaDados { public static void main (String args[]) { System.out.println(“saida de dados”); } } 10 Entrada de Dados Padrão • Toda a classe que for se utilizar de entrada de dados via teclado deve utilizar o package Java.io.*. Esse pacote contêm as classes que tratam de entrada de dados. import java.io.* • Para obter valores do teclado em uma classe Java é necessário criar um objeto da classe Scanner. A classe Scanner pertence ao pacote java.util. Então é necessário colocar o import java.util.*; Scanner leitor = new Scanner(System.in); • Todo a entrada de dados está sujeita a erros, já que fica a mercê da digitação do usuário final. A forma mais simples de se tratar essa exceção é solicitar que a exceção não seja tratada localmente através da linha de comando: throws java.io.IOException 11 Realizando a Leitura pelo Teclado • Para realizar a leitura via teclado usaremos a classe Scanner. Instanciando o objeto leitor da classe Scanner usando a entrada padrão do Sistema. Scanner leitor = new Scanner(System.in); Lendo um número inteiro int i = leitor.nextInt(); Lendo um número float int i = leitor.nextFloat(); Lendo uma String int i = leitor.next(); 12 Conversão de String para tipos primitivos • O Java só permite a entrada de Strings, desta forma, para que possamos informar valores numéricos é necessário fazer uma conversão de String para o tipo numérico desejado, como podemos ver a seguir: A variável str é uma String. Conversão de String para inteiro int i = Integer.valueOf(str).intValue(); Conversão de String para long long l = Long.valueOf(str).longValue(); Conversão de String para float float f = Float.valueOf(str).floatValue(); Conversão de String para double double d = Double.valueOf(str).doubleValue(); 13 Exemplo de Entrada e Saída de Dados import java.io.*; class Soma { public static void main (String args[ ] ) throws java.io.IOException { String aux; int a, b; BufferedReader obj = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Digite o primeiro número: "); aux = obj.readLine(); a = Integer.valueOf(aux).intValue(); System.out.println("Digite o segundo número: "); aux = obj.readLine(); b = Integer.valueOf(aux).intValue(); a = a + b; System.out.println("O resultado é : " + a); } } 14 Conversões entre tipos numéricos • Conversão entre Tipos Numéricos: Sempre que for realizada uma operação numérica (+, -, *, /) entre dois tipos diferentes será considerado como se os operadores fossem do mesmo tipo. Para isso, o operador de maior capacidade dita o tipo a ser considerado. Menor Maior byte short int long float double • Conversões Explicitas: Para fazer conversões que não seguem a regra anterior é necessário realizar conversões explicitar, veja o exemplo: double x = 9.997; int nx = (int) x; Sintaxe para uma conversão Explicita Resultado após a conversão nx = 9 15 Comandos de Decisão (if-else) • if – else if (expressão_booleana ) { bloco de comandos do if; } [else] { bloco de comandos do else; } Observações: O comando else é opcional. Na construção de if’s aninhados, o else refere-se sempre ao if mais próximo. Procure usar chaves para delimitar os blocos. O operador de comparação igual a é representado por == e não por =. Bloco de comandos pode ser um único comando (terminado por ponto-evírgula) ou vários comandos (delimitados por {}). É indispensável o uso de parênteses ( ) na expressão_booleana. 16 Comandos de Decisão (switch) switch switch(variávelDeControle) { case constante1: bloco1; break; case constante2: bloco2; break; [default: bloco3; break;] } • Observações: Usual para selecionar alguma ação de um número de alternativas. A variável de controle só pode ser inteira ou char. O case define o ponto de entrada da execução. Se você quiser que só um bloco de declarações seja executado use break. 17 A opção default é opcional. Comandos de Repetição (while) while while (expressão_booleana) { Bloco de comandos; } • Observações: É indispensável o uso de parênteses ( ) na expressão booleana. O laço permanece em execução enquanto a expressão booleana for verdadeira. Um erro comum é não atualizar as variáveis de controle do laço, o que acarreta um loop infinito. Outro erro frequente é colocar o ponto e vírgula após o while. A fase de atualização das variáveis de controle ficam fora do laço, gerando um loop infinito. Use sempre chaves para delimitar o Bloco de comandos. 18 Comandos de Repetição (do while) do - while do { Bloco de comandos; } while (expressão_booleana); • Observações: É semelhante ao comando while, sendo que a condição de parada do laço é testada após o bloco de comandos. Pelo menos uma vez o bloco de comandos será executado. Observe as mesmas considerações do comando while. 19 Comandos de Repetição (for) for for(inicialiazação; terminação; iteração) { bloco de comandos; } • Observações: Num loop for é explicita as quatro partes de uma iteração. Um erro comum é colocar o ponto e vírgula após o for, ficando o bloco de comandos fora do laço. O resultado é um loop que nada realiza. 20 Exemplo de uma classe com estruturas condicionais class DataSimples { byte dia,mes; short ano; Tipos primitivos definidos como atributos (variáveis) DataSimples(byte dia,byte mes,short aano) { if (dataEValida(dia,mes,ano) == true) { this.dia = dia; this.mes=mes; this.ano=ano; } else { this.dia = 0; this.mes=0; this.ano=0; } Método } da classe Construtor da classe Parâmetros baseados em tipos primitivos boolean dataEValida(byte dia,byte mes,short ano) { if ((dia>=1) && (dia<=31) && (mes>=1) && (mes<=12)) return true; else return false; } 21 Exemplo de uma classe com estruturas condicionais boolean eIgual(DataSimples outraDataSimples) { if ((dia == outraDataSimples.dia) && ( mes == outraDataSimples.mes) && (ano == outraDataSimples.ano)) return true; else return false; Método } da classe Parâmetros baseados em um objeto da própria classe void mostraDataSimples() { System.out.println(dia + “/” + mês + “/” + ano); } } 22 Exemplo de uma classe com estruturas de repetição public class exemploCondicaoRepeticao { public static void main (String args[]) { double valor = 1; char letra='A'; int contador; while(valor <= 20) { System.out.println(valor); valor = valor * 2; if (valor >= 20) { System.out.println("Fim da exemplificação do while e if"); } } for (contador=0; contador < 10; contador++) { System.out.println(contador); } System.out.println("Fim da exemplificação do for"); 23 Exemplo de uma classe com estruturas de repetição do { switch (letra) { case 'A' : System.out.println(letra + " é uma vogal"); break; case 'E' : System.out.println(letra + " é uma vogal"); break; case 'I' : System.out.println(letra + " é uma vogal"); break; case 'O' : System.out.println(letra + " é uma vogal"); break; case 'U' : System.out.println(letra + " é uma vogal"); break; } letra++; } while (letra != 'Z'); System.out.println("Fim da exemplificação do switch e do-while"); } } 24 Escopo de Variáveis e Objetos • O escopo dos campos e variáveis dentro de uma classe determina a sua visibilidade. • Campos declarados em uma classe são válidos por toda a classe, mesmo que os campos estejam declarados depois dos métodos que os usam. • Variáveis e instâncias de objetos declarados dentro de métodos só serão válidos dentro desse método. • Dentro de métodos e blocos de comandos, as variáveis e objetos devem ser declarados antes de serem utilizadas. • Variáveis passadas como argumentos para métodos só são válidas dentro dos métodos. • Exemplo: Veja o exemplo da classe Data. 25 Modificadores de Acesso • Modificadores de acesso podem ser usados tanto em campos como em métodos de uma classe. • O objetivo é proteger a integridade e a consistência dos dados e operações que uma determinada classe manipula. Exemplo de Proteção aos Atributos (dados) • Por exemplo na classe dataSimples analisada anteriormente, observamos que ao ser inicializada uma data, os campos dia, mês e ano passam por um processo de consistência, ao ser chamado o método dataEValida. • Entretanto, como não são usados modificadores, não podemos garantir que sempre as datas serão validadas, pois os campos da classe podem ser acessados diretamente, sem a utilização dos métodos da classe. 26 Modificadores de Acesso Exemplo de Proteção aos Métodos (ações) • Outro exemplo, seria um método imprimeNumeroDaPagina de uma classe Relatório. • Esta classe teria o método imprimeRelatorio que sempre que necessário se utilizaria do método imprimeNumeroDaPágina. • Seria inadequado a execução de imprimeNumeroDaPagina desatrelado do método imprimeRelatorio. • No primeiro exemplo apresentado, seria conveniente usar um modificador para proteger os dados, assim garantindo que as datas sempre seriam validados. • No segundo exemplo, seria conveniente usar um modificador para restringir o acesso ao método imprimeNumeroDaPagina, já que este só deve ser usado através do método imprimeRelatorio. 27 Modificadores de Acesso Existem quatro modificadores de acesso • public: garante que o campo ou método da classe declarado com este modificador poderá ser acessados ou executado a partir de qualquer outra classe. • private: só podem ser acessados, modificados ou executados por métodos da mesma classe, sendo ocultos para o programador usuário que for usar instâncias desta classe ou criar classes herdeiras ou derivadas. • protected: funciona como o modificador private, exceto que classes herdeiras ou derivadas também terão acesso ao campo ou método. • Finalmente, campos e métodos podem ser declarados sem modificadores. Nesse caso, eles serão considerados como pertencentes à categoria package, significando que seus campos e métodos serão visíveis para todas as classes de um mesmo pacote. 28 Exemplo de Escopo e Modificadores public determina que essa classe pode ser instanciada dentro de qualquer outra classe. public class Data { private byte dia, mes; private short ano; private determina que os dados só podem ser manipulados dentro da própria classe. Como “dia”, “mês” e “ano” são declarados fora dos métodos, são variáveis globais (atributos). public void inicializaData(byte dia,byte mes, short ano) { public indica que o método pode ser acessado sem restrições if (dataEValida(dia,mes,ano) == true) { this. dia = dia; this.mes=mes; this.ano=ano; } else { this.dia = 0; this.mes=0; this.ano=0; As variáveis “dia”, “mes” e “ano” são parâmetros (argumentos) e só podem ser manipulados dentro desse método. } } 29 Exemplo de Escopo e Modificadores private indica que esse método só pode ser acessado através de outros métodos da própria classe. private boolean dataEValida(byte dia,byte mes,short ano) A variáveis “validade” é uma variável local e só podem ser manipulada dentro desse método. { boolean validade = false; if ((dia>=1) && (dia<=31) && (mes>=1) && (mes<=12)) validade = true; return validade; } protected indica que esse método só pode ser acessado através de métodos dessa classe ou de classes herdeiras ou derivadas. protected void mostraData() { } } System.out.println(dia + “/” + mes + “/” + ano); 30 Garbage Collection • Garbage Collection Gerenciador de memória para aplicações java. Thread chamada Automatic Garbage Collector. Retorna a memória ocupada por objetos que não estão mais sendo usados. Monitora a criação de objetos através do new. Cria um contador de referência para cada objeto. Libera a memória quando o contador chegar a zero. • Referência NULA Objetos armazenam uma referência nula até serem inicializados. A referência nula é representada pela palavra reservada null. Pode-se desfazer uma referência para um objeto atribuindo a ela a 31 palavra null. Operador New • Operador NEW new instancia um novo objeto. new aloca o espaço necessário para armazenar o estado do objeto e uma tabela para indicar o corpo do código necessário para efetuar suas operações. new executa as tarefas de inicialização do objeto conforme o seu Construtor. new ‘retorna’ o identificador do objeto criado e o operador de atribuição é utilizado para copiar este endereço para uma variável, que servirá para futuras referências ao objeto. O compilador e a máquina virtual Java verificam o tipo da variável e o tipo da referência retornada. 32 Construtores • Construtor é um tipo especial de membro de classe chamado automaticamente quando instâncias são criadas através da palavra chave new. • Construtores são úteis para: inicializar os atributos de uma classe; realizar rotinas complexas de inicialização; realizar inicializações segundo parâmetros passados no momento da criação do objeto. • Na declaração de um construtor deve-se considerar que: Construtores devem ter exatamente o mesmo nome da classe; Construtores não possuem tipo de retorno, nem mesmo void; Construtores são, normalmente, públicos. Programador não pode chamar construtores diretamente; • Toda classe possui um construtor. • Caso o programador não forneça uma versão explícita do construtor, o Java utiliza uma versão de construtor implícita que não recebe nenhum parâmetro. 33 Exemplo da Utilização de Construtores public class Empregado { String nome, endereço, CPF; float salario; int idade; public Empregado ( String nome, String endereco, String CPF, int idade) { this.nome = nome; this.endereco = endereco; Construtor da classe Empregado. this.CPF = CPF; Observe que não foi definido um this.idade = idade; tipo de retorno e possui o mesmo nome da classe. } public String getCPF( ) { return CPF; } public String getNome( ) { return Nome; } } 34 Exemplo da Utilização de Construtores Utilização do Construtor da classe Empregado para instanciar um objeto. class CriaEmpregado { public static void main(String args[]) { Empregado obj = new Empregado(“Maria Silva”, “Rua X nº 246", "403.234.567-33",58); Nome da classe Nome do Objeto System.out.println("O nome é = ” +obj.getNome()); System.out.println("O CPF é = "+ obj.getCPF()); } } 35 Reutilização de Classes • Um dos maior benefício que a Programação Orientada a Objeto nos proporciona é a reutilização de código. • A reutilização se caracteriza pelo aproveitamento de classes e seus métodos que já estejam escritos e que já tenham o seu funcionamento testado e comprovado. • A Reutilização de código diminui a necessidade de escrever novos métodos e classes gerando economia de tempo e segurança. • Existe duas maneiras de conseguir esse reaproveitamento: Através de Composição ou através de Herança. 36 Composição • A composição é o conceito mais usual no desenvolvimento de aplicações baseadas em Orientação a Objetos. • Parte do pressuposto que uma determinada classe vai instanciar objetos de outras classes, utilizando-se do que esses objetos fazem para compor as funcionalidades da nova classe. • Esse conceito pode ser visto em exemplos anteriores (classe criaEmpregado), que instanciaram objetos da classe Empregado. CriaEmpregado Empregado 37 Herança • Herança é a capacidade de uma classe definir o seu comportamento e sua estrutura aproveitando definições de outra classe, normalmente conhecida como classe base ou classe pai. • A herança não precisa ser interrompida na derivação de uma camada de classes. A coleção de todas as classes que se estendem de um pai comum chama-se hierarquia de herança. • A palavra reservada extends é que define que uma classe está herdando de outra. Empregado Gerente Secretária Analista de Sistemas 38 Herança • Através do mecanismo de herança é possível definirmos classes genéricas que agreguem um conjunto de definições comuns a um grande número de objetos (Generalização). A partir destas especificações genéricas podemos construir novas classes, mais específicas, que acrescentem novas características e comportamentos aos já existentes (Especialização). Funcionário Gerente Gerente de Banco Gerente de Empresas • codBanco • codAgência • codSetor • nome • salário Secretária Analista de Sistemas • idiomas • linguagem 39 Herança e a Referência super • A palavra reservada super, nos possibilita: referência a classe base (pai) do objeto; acesso a variáveis escondidas (shadow), ou seja, variáveis de uma classe que tem o mesmo nome de uma variável definida em uma subclasse; acesso a métodos que foram redefinidos, ou seja, métodos que possuem a mesma assinatura na classe Pai e na classe derivada; utilização pela classe derivada do construtor da classe pai. 40 Exemplo de Herança public class Automovel Classe Pai { public static final byte movidoAGasolina = 1; Declaração de constantes. public static final byte movidoAAlcool = 2; public static final byte movidoADiesel = 3; private static final byte numeroMaximoDePrestacoes = 24; Atributos private String modelo, cor; private byte combustivel; Construtor public Automovel(String m, String c, byte comb) { modelo = m; cor = c; combustivel = comb; } public byte quantasPrestacoes() { return numeroMaximoDePrestacoes; } 41 Exemplo de Herança public float quantoCusta() { float preco = 0; switch (combustivel) { case movidoAGasolina: preco = 12000.0f; break; case movidoAAlcool: preco = 10500.0f; break; case movidoADiesel: preco = 11000.0f; break; } return preco; } public String toString() { String resultado; resultado = modelo+" "+cor+"\n"; switch(combustivel) { case movidoAGasolina: resultado += "Gasolina \n"; break; case movidoAAlcool: resultado += "Álcool \n"; break; case movidoADiesel: resultado += "Diesel \n"; break; } return resultado; } 42 Exemplo de Herança public class AutomovelBasico extends Automovel { private boolean retrovisorDoLadoDoPassageiro; private boolean limpadorDoVidroTraseiro; private boolean radioAMFM; Atributos A palavra extends é que determina que AutomovelBasico herda de Automovel. public AutomovelBasico (String m, String c, byte comb, boolean r, boolean l, boolean af) { super(m,c,comb); A palavra super, indica retrovisorDoLadoDoPassageiro = r; que deve ser usado o limpadorDoVidroTraseiro = l; construtor da classe Pai. radioAMFM = af; } public AutomovelBasico (String m, String c, byte comb) { super(m,c,comb); retrovisorDoLadoDoPassageiro = true; limpadorDoVidroTraseiro = true; radioAMFM = true; } 43 Exemplo de Herança public float quantoCusta() Os dois métodos { float preco = super.quantoCusta(); apresentados nesse slide if (retrovisorDoLadoDoPassageiro == true) possuem a mesma assinatura preco = preco + 280; da classe Automovel, o que if (limpadorDoVidroTraseiro == true) caracteriza uma redefinição de preco = preco + 650; métodos da classe Pai. if (radioAMFM == true) preco = preco + 190; return preco; A palavra super, indica que } deve ser chamado o método quantoCusta() e toString() da public String toString() classe Pai. { String resultado = super.toString(); if (retrovisorDoLadoDoPassageiro == true) resultado += "Com retrovisor do lado direito \n"; if (limpadorDoVidroTraseiro == true) resultado += "Com limpador traseiro \n"; if (radioAMFM == true) resultado += "Com radio \n"; return resultado; } 44 } Exemplo de Herança public class DemoAutomovel Instância de um objeto da classe Automovel. { public static void main(String arg[]) { Automovel a = new Automovel("Fusca","verde", Automovel.movidoAAlcool); System.out.println(a.toString()); System.out.println(a.quantoCusta()); System.out.println(a.quantasPrestacoes()); Instância de um objeto da classe AutomovelBasico. AutomovelBasico ab = new AutomovelBasico("Corsa","cinza", Automovel.movidoAGasolina,true,true,false); System.out.println(ab.toString()); System.out.println(ab.quantoCusta()); System.out.println(ab.quantasPrestacoes()); } } Observe que o método quantasPrestacoes() está sendo acessado através de um objeto da classe AutomovelBasico. Isso só é possível porque a classe AutomovelBasico herda da classe Automovel, assim todos os atributos e 45 métodos da classe Pai podem ser usados pela classe derivada. Principais componentes gráficos usados no curso • jLabel: São utilizados para identificar ações sobre outros componentes em uma interface. Principal método: setVisible(Boolean); Exemplo: jLabel1.setVisible(false); • jTextField: São usados para possibilitar que o usuário digite informações para a aplicação. Principais métodos: getText(); setText(String) Exemplo: jTextField1.getText(); jTextField1.setText(“”); • jButton: São usados para permitir o início da execução de alguma tarefa pelo aplicativo. Principal método: setLabel(String); Exemplo: jButton.setLabel(“Entrar”); • list: São usados para permitir que dados sejam mostrados na tela em forma de relatório. Principal método: add(String); 46 Exemplo: list1.add(“”+numero); Principais componentes gráficos usados no curso • JOptionPane.showMessageDialog: Este componente permite apresentar mensagens para o usuário. A classe deve importar a seguinte biblioteca: import javax.swing.JOptionPane; • A sintaxe para o uso do comando é: JOptionPane.showMessageDialog(null,“Mensagem"); • A plataforma utilizada é a JDK 7u51 with NetBeans 7.4 • Link para a plataforma: http://www.oracle.com/technetwork/java/javase/downloads/jdk-7netbeans-download-432126.html • Baixar a opção: jdk-7u51-nb-7_4-windows-x64.exe 47 Tratamento de Exceções • • • • Exceções são eventos estranhos, que podem fazer um programa falhar. Por exemplo, quando se espera que um usuário entre com um número e este digita uma letra. As exceções na linguagem Java são objetos reais, instâncias de classe que herdam da classe Throwable. Um objeto da classe Throwable é criada, quando uma exceção é gerada. A linguagem Java permite que se tratem exceções através das palavras try, catch e finally. – try : no bloco try você protege o código que poderia gerar uma exceção. – catch : no bloco catch você testa e trata da exceção gerada. – finally : no bloco finally você possibilita que seu programa execute linhas de código tendo ou não ocorrido exceções. Existem vários tipos de exceções na linguagem Java. Para que você possa tratá-las adequadamente é necessário descobrir quais são as exceções que podem ser geradas (levantadas) por um determinado método. – Algumas exceções da linguagem Java • IOException • EOFException • FileNotFoundException • MalformedURLException • SocketException 48 Tratamento de Exceções import javax.swing.JOptionPane; public class Principal extends javax.swing.JFrame { public Principal() { initComponents(); } private void initComponents() { // Este método é definido pelo NetBeans e não pode ser alterado } 49 Tratamento de Exceções // Aqui está a lógica da Aplicação private void jButton1MouseClicked(java.awt.event.MouseEvent evt) { int n; try { n = Integer.valueOf(jTextField1.getText()).intValue(); } catch (Exception obj) { JOptionPane.showMessageDialog(null,"Você deve digitar apenas números inteiros!"); return; } finally { jTextField1.setText(""); } list1.add(""+n); } 50 Tratamento de Exceções public static void main(String args[]) { // Este método é definido pelo NetBeans e não deve ser alterado java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new Principal().setVisible(true); } }); } // Estes atributos são criados pelo NetBeans e não devem ser alterados private javax.swing.JButton jButton1; private javax.swing.JLabel jLabel1; private javax.swing.JTextField jTextField1; private java.awt.List list1; } 51 Estrutura Estática - Array (Vetor) • Conjunto finito e ordenado de elementos homogêneos. • Declaração utilizando tipos primitivos int[] Vet; Vet = new int[12]; • ou int[] Vet = new int[12] Declaração utilizando tipos não primitivos (array de uma classe qualquer) Button[] Botoes; Botoes = new Button[10] ou Button[] Botoes = new Button[10] 52 Estrutura Estática - Utilização de Array import javax.swing.JOptionPane; public class Array extends javax.swing.JFrame { int vet[]; int total=0; public Array() { vet = new int[100]; total=0; initComponents(); } public void ordenar() { int i,j, aux; for(i=0; i < total; i++) { for(j=i+1; j < total; j++) { if (vet[i] > vet[j]) { aux = vet[i]; vet[i]=vet[j]; vet[j]=aux; } } } } 53 Estrutura Estática - Utilização de Array private void jButton1MouseClicked(java.awt.event.MouseEvent evt) { try { vet[total]=Integer.valueOf(jTextField1.getText()).intValue(); list1.add(jTextField1.getText()); total++; jTextField1.setText(""); } catch (Exception e) { JOptionPane.showMessageDialog(null,“Digite apenas números inteiros!"); return; } } private void jButton2MouseClicked(java.awt.event.MouseEvent evt) { ordenar(); for(int i=0; i<total; i++) { list2.add(vet[i]+""); } } 54 Estrutura Estática - Utilização de Array public static void main(String args[]) { // Este método é definido pelo NetBeans e não deve ser alterado java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new Array().setVisible(true); } }); } // Estes atributos são criados pelo NetBeans e não devem ser alterados private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JTextField jTextField1; private java.awt.List list1; private java.awt.List list2; 55 } Estrutura Dinâmica - Lista Encadeada • É uma sequência de estruturas (elementos) interligados, com a capacidade de inserção e remoção em qualquer posição da lista. • A cabeça da lista contém um ponteiro para o primeiro elemento da lista (nodo), que armazena um conjunto de dados e um ponteiro para o nodo seguinte. Esse nodo, da mesma forma, armazena um item de dados e um ponteiro para o nodo seguinte, e assim por diante. O último nodo possui um ponteiro null para indicar o final da lista. • Representação Estrutural Cabeça da Lista Ponteiro para o primeiro nodo • nodo Dados Próximo nodo Dados Próximo nodo nodo Dados Próximo Dados Próximo null O critério utilizado em listas determina que as inserções e remoções podem ser realizadas em qualquer posição da lista. Por conveniência utilizaremos a inserção por ordem de chave (informação única que destingue um elemento 56 de outro). Estrutura Dinâmica – Classe Nodo public class Nodo { int info; Nodo prox; public Nodo(int n) { info = n; prox = null; } } 57 Estrutura Dinâmica - Lista Simplesmente Encadeada public class ListaSimplesmenteEncadeada { Nodo inicio = null, fim = null; int qtd = 0; public Nodo pesquisa(int n) { Nodo atual = inicio; while ((atual != null) && (atual.info != n)) { atual = atual.prox; } return atual; } 58 Estrutura Dinâmica - Lista Simplesmente Encadeada public boolean insere(int n) { Nodo novo = new Nodo(n); qtd++; if (inicio == null) // ins. no início da lista { fim = novo; inicio = novo; return true; } if (n < inicio.info) // antes do 1º { novo.prox=inicio; inicio = novo; return true; } if (n > fim.info) // no final { fim.prox = novo; fim = novo; return true; } // pesquisa elemento Nodo atual=inicio; Nodo aux = inicio; while (atual.info < n) { aux = atual; atual=atual.prox; } if (atual.info == n) { qtd--; return false; } // info. existente else // inserção no meio { novo.prox = atual; aux.prox = novo; } return true; } 59 Estrutura Dinâmica - Lista Simplesmente Encadeada public boolean remove(int n) else { Nodo aux = inicio; { // remoção no final Nodo atual=inicio; if (atual == fim) if (n == inicio.info) // remoção do início { fim=aux; { inicio=inicio.prox; fim.prox=null; } if (atual == fim) // remoção do único else // remoção no meio { fim=null; { aux.prox = atual.prox; } } qtd--; qtd--; return true; return true; } } } else } { while ((atual != null) && (atual.info != n)) { aux=atual; atual=atual.prox; } if (atual == null) // elemento não encontrado 60 { return false; } Exemplo de Aplicação de Lista Encadeada import javax.swing.JOptionPane; public class AplicacaoListaSimplesmenteEncadeada extends javax.swing.Jframe { ListaSimplesmenteEncadeada objLista; public AplicacaoListaSimplesmenteEncadeada() { objLista = new ListaSimplesmenteEncadeada(); initComponents(); } 61 Exemplo de Aplicação de Lista Encadeada // Ações do botão Inserir private void jButton1MouseClicked(java.awt.event.MouseEvent evt) { int n; try { n = Integer.valueOf(jTextField1.getText()).intValue(); } catch (Exception e) { JOptionPane.showMessageDialog(null,“Digite apenas números inteiros!"); return; } if (objLista.insere(n) == true) { list1.removeAll(); mostraLista(objLista); } else { JOptionPane.showMessageDialog(null,"Elemento Existente!"); } 62 jTextField1.setText(""); } Exemplo de Aplicação de Lista Encadeada // Ações do botão Remover private void jButton2MouseClicked(java.awt.event.MouseEvent evt) { int n; try { n = Integer.valueOf(jTextField1.getText()).intValue(); if (objLista.remove(n) == true) { JOptionPane.showMessageDialog(null,"Elemento removido com sucesso!"); list1.removeAll(); mostraLista(objLista); } else { JOptionPane.showMessageDialog(null,"Elemento não encontrado!"); } } catch (Exception e) { JOptionPane.showMessageDialog(null,“Digite apenas números inteiros!"); } 63 jTextField1.setText(""); } Exemplo de Aplicação de Lista Encadeada // Ações do botão Consultar private void jButton3MouseClicked(java.awt.event.MouseEvent evt) { int n; try { n = Integer.valueOf(jTextField1.getText()).intValue(); if (objLista.pesquisa(n) != null) { JOptionPane.showMessageDialog(null,"Elemento Encontrado na Lista!"); } else { JOptionPane.showMessageDialog(null,"Elemento Não Encontrado na Lista!"); } } catch (Exception e) { JOptionPane.showMessageDialog(null,“Digite apenas números inteiros!"); } jTextField1.setText(""); 64 } Exemplo de Aplicação de Lista Encadeada public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new AplicacaoListaSimplesmenteEncadeada().setVisible(true); } }); } void mostraLista(ListaSimplesmenteEncadeada objLista) { Nodo aux = objLista.inicio; while (aux != null) { list1.add(aux.info+""); aux=aux.prox; } } private javax.swing.JButton jButton1; private javax.swing.JButton jButton3; private javax.swing.JTextField jTextField1; } private javax.swing.JButton jButton2; private javax.swing.JLabel jLabel1; private java.awt.List list1; 65 Estrutura Dinâmica - Lista Duplamente Encadeada • Em algumas aplicações que utilizam listas encadeadas pode ser de extrema necessidade percorre-la da esquerda para a direita, bem como da direita para a esquerda. Este tipo de estrutura é chamada de Lista Duplamente Encadeada. • A cabeça da lista contém dois ponteiros, um para o primeiro elemento da lista e outro para o último elemento da lista. Os nodos devem ter dois ponteiros, um para o próximo nodo e um para o nodo anterior. • Representação Estrutural Cabeça de Lista Ponteiro para o primeiro nodo Ponteiro para o último nodo null nodo nodo nodo nodo Dados Próximo Anterior Dados Próximo Anterior Dados Próximo Anterior Dados Próximo Anterior null 66 Estrutura Dinâmica – Classe NodoDupEnc public class NodoDupEnc { int info; NodoDupEnc prox; NodoDupEnc ant; NodoDupEnc(int n) { info = n; prox = null; ant = null; } } 67 Estrutura Dinâmica - Lista Duplamente Encadeada public class ListaDuplamenteEncadeada { NodoDupEnc inicio=null, fim=null; int qtd=0; public NodoDupEnc pesquisaDirEsq(int n) { NodoDupEnc atual = fim; while ((atual != null) && (atual.info != n)) { atual = atual.ant; } return atual; } public NodoDupEnc pesquisaEsqDir(int n) { NodoDupEnc atual = inicio; while ((atual != null) && (atual.info != n)) { atual = atual.prox; } return atual; } 68 Estrutura Dinâmica - Lista Duplamente Encadeada public boolean insere(int n) { NodoDupEnc novo = new NodoDupEnc(n); qtd++; if (n > fim.info) // no final { novo.ant = fim; fim.prox = novo; fim = novo; return true; } if (inicio == null) // no início da lista { fim = novo; inicio = novo; return true; } // pesquisa o local de inserção NodoDupEnc atual = inicio; while ((atual != null) && (atual.info < n)) { atual = atual.prox; } if (atual.info == n) // informação já existe return false; else // no meio { novo.prox = atual; novo.ant = atual.ant; atual.ant.prox = novo; atual.ant = novo; } 69 return true; if (n < inicio.info) // antes do 1º { novo.prox=inicio; inicio.ant=novo; inicio = novo; return true; } } Estrutura Dinâmica - Lista Duplamente Encadeada public boolean remove(int n) { NodoDupEnc atual = pesquisaDirEsq(n); if (atual == null) // elemento não encontrado { return false; } qtd--; if (atual == inicio) // rem do 1º da lista { inicio=atual.prox; if (atual == fim) // rem. do único { fim=null; } else // atualiza o novo início { inicio.ant=null; } } return true; } if (atual == fim) // rem. do último { fim=fim.ant; fim.prox=null; return true; } // rem. no meio da lista NodoDupEnc anterior=atual.ant; NodoDupEnc posterior=atual.prox; anterior.prox=posterior; posterior.ant=anterior; return true; 70 Estrutura Dinâmica - Listas Circulares • Em algumas aplicações que utilizam listas encadeadas pode ser de extrema necessidade que o último nodo aponte para o primeiro. Este tipo de estrutura é chamada de Lista Circular. • Representação Estrutural da lista Circular Cabeça da Lista Ponteiro para o primeiro nodo • nodo Dados Próximo Dados Próximo nodo nodo Dados Próximo Dados Próximo Representação Estrutural da lista Circular Duplamente Encadeada Cabeça de Lista Ponteiro para o primeiro nodo Ponteiro para o último nodo • nodo nodo nodo nodo nodo Dados Próximo Anterior Dados Próximo Anterior Dados Próximo Anterior Dados Próximo Anterior Exercício: Implemente as duas Representações Estruturais. 71 Fila FIFO - Fist-In, First-Out (O 1º a Entrar é o 1º a Sair) Início Final A Início B Início C (a) B insere (A) insere (B) insere (C) Final remove(Início) C (b) B Final C D E insere (D) insere (E) (c) 72 Estrutura Estática – Fila Estática public class FilaEstatica { int informacoes[]; int inicio=0, fim=0, tamanho; public int retira() { if (inicio == fim) return -1; public FilaEstatica(int tamanho) { this.tamanho = tamanho; informacoes = new int[tamanho]; } // fila vazia int valor=informacoes[inicio]; inicio=(inicio+1) % tamanho; return valor; } public boolean insere(int info) { if (inicio == ((fim + 1) % tamanho)) // testa se a fila está cheia { return false; } informacoes[fim] = info; fim = (fim+1) % tamanho; return true; } 73 Estrutura Estática – Fila Estática public boolean consulta(int n) { FilaEstatica filaAux = new FilaEstatica(tamanho); int aux; boolean achou = false; while (inicio != fim) { aux = retira(); if (n == aux) { achou = true; } filaAux.insere(aux); } while (filaAux.inicio != filaAux.fim) { aux = filaAux.retira(); insere(aux); } return achou; } } 74 Estrutura Dinâmica – Fila Dinâmica public class FilaDinamica { Nodo inicio = null, fim = null; int qtd = 0; public void insere(int n) { Nodo novo = new Nodo(n); if (inicio == null) // ins. 1º elemento { fim = novo; inicio = novo; } else // inserção no final da fila { fim.prox = novo; fim = novo; } qtd++; } class Nodo { int info; Nodo prox; Nodo(int n) { info = n; prox = null; } } 75 Estrutura Dinâmica – Fila Dinâmica public Nodo remove() { if (inicio == null) // fila vazia return null; else // remoção do inicio da fila { Nodo atual=inicio; inicio=inicio.prox; qtd--; return atual; } } public boolean consulta(int n) { FilaDinamica filaAux = new FilaDinamica(); Nodo aux; boolean achou = false; while (inicio != null) { aux = remove(); if (n == aux.info) { achou = true; } filaAux.insere(aux.info); } while (filaAux.inicio != null) { aux = filaAux.remove(); insere(aux.info); } return achou; } } 76 Pilha LIFO - Last-In, First-Out (O Último a Entrar é o 1º a Sair) topo A B C (a) A empilha(A) empilha(B) empilha(C) topo desempilha(topo) B (b) A B topo D E empilha(D) empilha(E) (c) 77 Estrutura Estática – Pilha Estática public class PilhaEstatica { int informacoes[]; int topo, tamanho; public int desempilha() { if (topo == 0) { return -1; // pilha vazia } topo--; return informacoes[topo]; } public PilhaEstatica(int maxPilha) { topo=0; tamanho=maxPilha; public boolean consulta(int n) informacoes = new int[tamanho]; { boolean resultado = false; } PilhaEstatica pilhaAux; pilhaAux = new PilhaEstatica(tamanho); while ((topo > 0) && (informacoes[topo-1] != n)) public boolean empilha(int n) { pilhaAux.empilha(desempilha()); { if (topo == tamanho) } { return false; // pilha cheia if (topo != 0) } resultado=true; while (pilhaAux.topo > 0) informacoes[topo]=n; empilha(pilhaAux.desempilha()); topo++; return resultado; return true; } 78 } } Estrutura Dinâmica – Pilha Dinâmica public class PilhaDinamica { Nodo topo=null; int qtd=0; public boolean consulta(int n) { boolean resultado = true; PilhaDinamica pilhaAux; pilhaAux = new PilhaDinamica(); public void empilha(int n) Nodo aux; { Nodo novo = new Nodo(n); while ((topo != null) && (topo.info != n)) if (topo != null) { aux = desempilha(); novo.prox=topo; pilhaAux.empilha(aux.info); topo=novo; } qtd++; if (topo == null) } { resultado=false; } public Nodo desempilha() while ((pilhaAux.topo != null)) { if (topo == null) // Pilha vazia { aux = pilhaAux.desempilha(); return null; empilha(aux.info); else // remoção no topo da Pilha } { Nodo aux = topo; return resultado; topo = topo.prox; } qtd--; } return aux; 79 } } Recursividade • Definição: A recursividade pode ser considerada um método eficaz para resolver um problema originalmente complexo, reduzindo-o em pequenas ocorrências do problema principal. Assim, segue a ideia de dividir para conquistar. Resolvendo, isoladamente, cada uma das pequenas partes, podemos obter a solução do problema original como um todo. • Características de uma função recursiva Definição de parâmetros; Condição de parada da recursão, para que a rotina não seja chamada infinitamente; Chamada da função dentro dela própria; • Rotinas recursivas e pilhas O controle de chamadas e de retorno de rotinas é efetuado por uma pilha (criada e mantida dinamicamente pelo sistema). Quando uma rotina é chamada, empilha-se o endereço da rotina e todas as variáveis locais são recriadas. Quando ocorre o retorno da rotina as variáveis locais que foram criadas deixam de existir. • Vantagens: Facilidade na resolução de alguns tipos de problemas. • Desvantagens: computador. Uso demasiado dos recursos computacionais de 80 um Recursividade – Exemplo de Aplicação import javax.swing.JOptionPane; public class Recursividade extends javax.swing.JFrame { String resposta; public Recursividade() { initComponents(); } private void jButton1MouseClicked(java.awt.event.MouseEvent evt) { int n; try { n = Integer.valueOf(jTextField1.getText()).intValue(); } catch (Exception e) { JOptionPane.showMessageDialog(null,"Digite apenas números inteiros!"); return; } int fat = fatorial(n); list1.removeAll(); list1.add("O fatorial de "+ n + " é "+fat); 81 jTextField1.setText(""); } Recursividade – Exemplo de Aplicação private void jButton2MouseClicked(java.awt.event.MouseEvent evt) { int n; try { n = Integer.valueOf(jTextField1.getText()).intValue(); } catch (Exception e) { JOptionPane.showMessageDialog(null,"Digite apenas números inteiros!"); return; } list1.removeAll(); resposta=""; binario(n); list1.add("O valor de "+ n + " em binário é "+resposta); jTextField1.setText(""); jTextField1.requestFocus(); // TODO add your handling code here: } 82 Recursividade – Exemplo de Aplicação public int fatorial(int n) { int res; if (n == 0) { return 1; } else { res = fatorial(n-1); res = res * n; return res; } } public void binario(int n) { int resto=0; if (n > 0) { resto = n % 2; binario(n / 2); resposta+=resto; } } public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new Recursividade().setVisible(true); } }); } private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JTextField jTextField1; private java.awt.List list1; } 83 Árvores Definição: Relação de hierarquia ou de composição entre os dados (nós). Conjunto finito T de um ou mais nós, tais que: (a) existe um nó denominado raiz da árvore; (b) os demais nós formam m >= 1 conjuntos disjuntos S1,...,Sm, onde cada um desses conjuntos é uma árvore. As árvores Si recebem a denominação de subárvores. Terminologia: Cada nó da árvore é a raiz de uma subárvore. O número de subárvores de um nó é o grau daquele nó. Um nó de grau igual a zero é denominado folha ou nó terminal. A raiz da árvore tem nível 0. Os demais nós: nível = número de "linhas" que o liga à raiz. Altura: nível mais alto da árvore. 84 Árvores • Representação Estrutural: Grau = 3; Nível =0 (raíz) A C B E F D G H I Grau = 1; Nível = 1 Grau = 3; Nível = 2 J Grau = 0 (Folha) K Grau = 0; Nível = 3 Árvore com altura igual a 3 85 Árvores Binárias • Uma árvore binária é uma estrutura de dados útil quando precisam ser tomadas decisões bidirecionais em cada ponto de um processo. • O Grau de cada nó é menor ou igual a 2 (Subárvores da esquerda e da direita). • Se grau = 1, deve ser especificado se a sua subárvore é a da esquerda ou a da direita. • Árvore Estritamente Binária: é a árvore onde todo o nó que não é folha possuí subárvores a esquerda e a direita. • Uma Árvore Binária Completa é uma árvore estritamente binária sendo que todas as folhas devem estar no mesmo nível. 86 Árvores Binárias • Representação Estrutural: Árvore Estritamente Binária Árvore Binária Completa 4 5 2 8 9 6 5 2 1 7 4 6 9 7 • Regra Geral de Inserção: Os valores menores devem ficar a esquerda da raiz e os maiores a direita. Os valores repetidos não devem ser inseridos. • Exercício: Insira os seguintes nós: 14, 15, 4, 9, 7, 18, 2, 5, 16, 4, 20, 17, 9, 5. 87 Árvores Binárias • Como Percorrer uma árvore? Pré-ordem 1º. visitamos a raiz 2º. subárvore esq. em pré-ordem 3º. subárvore dir. em pré-ordem Em ordem 1º. subárvore esq. em ordem 2º. visitamos a raiz 3º. subárvore dir. em ordem Pós-ordem 1º. subárvore esq. em pós-ordem 2º. subárvore dir. em pós-ordem 3º. Visitamos a raiz (Centro, Esquerda, Direita) (Esquerda, Centro, Direita) (Esquerda, Direita, Centro) 88 Árvores Binárias Exemplos: 20 10 5 4 7 2 3 5 9 6 4 8 Pré-ordem: 5, 4, 2, 3, 9, 7, 6, 8, 10 Em ordem: 2, 3, 4, 5, 6, 7, 8, 9, 10 Pós-ordem: 3, 2, 4, 6, 8, 7, 10, 9, 5 6 2 10 15 12 7 18 17 19 20, 10, 5, 2, 4, 6, 7, 15, 12, 18, 17, 19 2, 4, 5, 6, 7, 10, 12, 15, 17, 18, 19, 20 4, 2, 7, 6, 5, 12, 17, 19, 18, 15, 10, 20 89 Estrutura Dinâmica – Classe NodoArvore public class NodoArvore { int info; NodoArvore pai; NodoArvore f_esq; NodoArvore f_dir; boolean deletado; NodoArvore(int n, NodoArvore p) { info = n; pai = p; f_esq = null; f_dir = null; deletado = false; } } 90 Estrutura Dinâmica – Árvore Binária import java.awt.List; public class ArvoreBinaria { NodoArvore raiz=null; int qtd=0; public void preOrdem(NodoArvore subRaiz, List objList) { if (subRaiz != null) { if (subRaiz.deletado == false) { objList.add(""+subRaiz.info); } preOrdem(subRaiz.f_esq, objList); preOrdem(subRaiz.f_dir, objList); } } 91 Estrutura Dinâmica – Árvore Binária public void ordem(NodoArvore subRaiz, List objList) { if (subRaiz != null) { ordem(subRaiz.f_esq, objList); if (subRaiz.deletado == false) { objList.add(""+subRaiz.info); } ordem(subRaiz.f_dir, objList); } } public void posOrdem(NodoArvore subRaiz, List objList) { if (subRaiz != null) { posOrdem(subRaiz.f_esq, objList); posOrdem(subRaiz.f_dir, objList); if (subRaiz.deletado == false) { objList.add(""+subRaiz.info); } } } 92 Estrutura Dinâmica – Árvore Binária public boolean insere(int n) { NodoArvore aux, pai, novo; if (raiz == null) // inserção da raiz { novo = new NodoArvore(n, null); raiz = novo; } else { aux = raiz; pai = raiz; // pesq. posição de inserção while ((aux != null) && (n != pai.info)) { pai = aux; if (n < pai.info) aux = pai.f_esq; else aux = pai.f_dir; } if (n == pai.info) { if (pai.deletado == true) { pai.deletado = false; return true; } else { return false; } } novo = new NodoArvore(n, pai); if (n < pai.info) { pai.f_esq = novo; } else { pai.f_dir = novo; } } qtd++; return true; 93 Estrutura Dinâmica – Árvore Binária public NodoArvore consulta(int n) { NodoArvore aux=raiz, pai=raiz; if (raiz == null) return null; // árvore sem elementos while ((aux != null) && (n != pai.info)) { pai = aux; if (n < pai.info) aux = pai.f_esq; else aux = pai.f_dir; } if ((n == pai.info) && (pai.deletado == false)) return pai; // informação encontrada else return null; // informação não encontrada } public boolean retira(int n) { NodoArvore remover; remover = consulta(n); if ((remover != null) && (n == remover.info)) { remover.deletado=true; return true; } else { return false; } } 94 Árvores AVL • Definição: Uma árvore AVL é uma árvore binária de busca construída de tal modo que a altura de sua Sub-árvore direita difere da altura da Sub-árvore esquerda de no máximo 1. • O que pode acontecer quando um novo nó é inserido numa árvore balanceada ? Nós 9 ou 11 podem ser inseridos sem balanceamento . Sub-árvore com raiz 10 passa a ter uma Sub-árvore e Sub-árvore com raiz 8 vai ficar melhor balanceada ! Inserção dos nós 1, 3, 5 ou 7 requerem que a árvore seja balanceada! • Fator de Balanceamento de um nó: É a altura da Sub-árvore direita do nó menos a altura da Sub-árvore esquerda do nó . FB= altura direita - altura esquerda Se todos os FB forem [-1, 0, 1] a árvore está balanceada. 95 Árvores AVL • Balanceamentos: Nos casos abaixo considere P como sendo o nó raiz de uma Sub-árvore desbalanceada e U como sendo o nó filho dessa raiz. Caso 1: Altura Esquerda de P > Altura Direita de P Caso 1.1 : Rotação Simples a Direita Caso 1.2 : Rotação Dupla a Direita Rotação para a esquerda e em seguida para a direita 96 Árvores AVL Caso 2: Altura Direita de P > Altura Esquerda de P Caso 1.2: Rotação Simples a Esquerda Caso 2.2 : Rotação Dupla a Esquerda Rotação para a direita e em seguida para a esquerda 97 Árvores AVL • Exemplos de Rotações ( Rotação simples a direita): 4 Rotação a Direita 2 8 3 6 10 • Exemplos de Rotações ( Rotação dupla a direita): Rotação a Esquerda e a Direita 98 Árvores AVL • Exemplos de Rotações ( Rotação simples a esquerda): 10 Rotação a Esquerda 15 8 4 12 9 • Exemplos de Rotações ( Rotação dupla a esquerda): 10 5 10 Rotação a Direita e a Esquerda 20 25 5 30 20 25 30 99 Árvores AVL • Regras para as rotações: Rotação Simples a Direita: rotaciona o U sobre o P para a direita, sendo que o filho da direita de U passa a ser o filho da esquerda de P. Rotação Simples a Esquerda: rotaciona o U sobre o P para a esquerda, sendo que o filho da esquerda de U passa a ser o filho da direita de P. Rotação Dupla a Direita: rotaciona o V sobre U para a esquerda, sendo que o filho da esquerda de V passa a ser o filho da direita de U. Após, rotaciona V sobre P para a direita, sendo que o filho da direita de V passa a ser o filho da esquerda de P. Rotação Dupla a Esquerda: rotaciona o V sobre U para a direita, sendo que o filho da direita de V passa a ser o filho da esquerda de U. Após, rotaciona V sobre P para a esquerda, sendo que o filho da esquerda de V passa a ser o filho da direita de P. 100 Árvores B • Definição: É a Construção e manutenção de árvores de busca de grandes dimensões. Ponteiros referem-se a áreas de memória secundária, em vez de representarem endereços da memória principal. Busca: acesso a disco (com os inerentes atrasos de acesso). Sub-árvores representadas em unidades, do ponto de vista de acesso páginas Reduz o número de acessos ao disco. Necessita de esquema de crescimento controlado. Todo nó, exceto a raiz, deve possuir entre n e 2n chaves, para uma dada constante n. • Características: Cada página (nó) contém no máximo, 2n elementos (chaves); cada página, exceto a que contém a raiz, contém no mínimo n chaves; os nós chamados folhas não têm descendentes e os demais(nós de derivação) possuem m + 1 descendentes, onde m é a quantidade de 101 chaves; todas as folhas têm o mesmo nível. Árvores B • Representação Estrutural: K1 P0 K2 P1 P2 ... ... Km Pm-1 Pm • Exemplo: Árvore B (ordem 2): Raiz 30 15 2689 22 17 18 20 21 40 50 27 29 36 38 39 42 45 48 51 53 55 56 102 Árvores B • Regras para redistribuir chaves: 1) Redistribuir a chave mais a esquerda de uma página que extrapolou os limites da ordem. Suba o elemento mais a esquerda para a página pai e desça o elemento de ligação para a página irmã esquerda. Caso não seja possível executar a redistribuição porque a página irmão está cheia ou não exista, passe para a segunda regra. 2) Redistribuir a chave mais a direita de uma página que extrapolou os limites da ordem. Suba o elemento mais a direita para a página pai e o elemento de ligação para a página irmã direita. Caso não seja possível executar a redistribuição porque a página irmão está cheia ou não exista, passe para a terceira regra. 3) Quebre em duas a página que extrapolou os limites da ordem e suba o elemento do meio para a página pai. 103