Estrutura de Dados - Paulo Roberto Gomes Luzzardi

Propaganda
Estruturas de Dados
em Java
por
Prof. Dr. Paulo Roberto Gomes Luzzardi
facebook: Paulo Roberto Gomes Luzzardi
WhatsApp: 91648037
e-mail: [email protected] e [email protected]
e-mail (Senac): [email protected]
DropBox: https://www.dropbox.com/sh/kea9kr4j2qttnjg/4xXvw0pvxX?m
Hostinger: http://pluzzardi.w.pw e http://pluzzardi.zz.mu (Home Page)
OS X Server (Apple): http://pluzzardi.no-ip.info:8080 (Home Page)
Versão 1.32
06/10/2014
Bibliografia recomendada
CORMEN, et al. Algoritmos - Teoria e Prática. Rio de Janeiro: Campus, 2002.
DEITEL, H. M. and DEITEL, P. J. Java: como programar, 8. ed.: São Paulo: Pearson, 2010
(ISBN 85-363-0123-6).
GOODRICH, Michael T. e TAMASSIA, Roberto. Estruturas de Dados e Algoritmos em Java,
Bookman, 2002.
PINTO, Wilson. Introdução ao Desenvolvimento de Algoritmos e Estrutura de Dados.
Editora Érica, 1994.
VELOSO, Paulo e SANTOS, Clésio. Estruturas de Dados. Rio de Janeiro: Editora Campus, 4
ed., 1986.
WIRTH, Niklaus. Algoritmos e Estruturas de Dados. Rio de Janeiro: Prentice-Hall do
Brasil, 1989.
1
Pelotas, segunda-feira, 6 de outubro de 2014 (11:14:40 am)
Sumário
1. Tipos de Dados ................................................................................................................................... 4
1.1 Conceitos Básicos .................................................................................................................... 4
1.1.1 Estruturas de Dados ........................................................................................................ 4
1.1.2 Organização de Arquivos ................................................................................................ 4
1.1.3 Conceito .............................................................................................................................. 4
1.1.4 Dados .................................................................................................................................... 4
1.1.5 Tipos de Dados .................................................................................................................. 4
1.2 Tipos Primitivos ...................................................................................................................... 5
1.2.1 Tipos primitivos da Linguagem de Programação Java ............................................ 5
1.3 Construção de Tipos (Estruturados ou Complexos) .................................................... 7
1.3.1 String (Cadeia de Caracteres) .................................................................................... 7
1.3.2 Vetor e Matriz (Agregados Homogêneos) .................................................................... 7
1.3.3 Classe (class) ................................................................................................................ 10
1.4 Operadores (Aritméticos, Relacionais e Lógicos) ...................................................... 11
1.4.1 Aritméticos ...................................................................................................................... 11
1.4.2 Relacionais ...................................................................................................................... 11
1.4.3 Lógicos .............................................................................................................................. 11
2. Vetores e Matrizes ......................................................................................................................... 13
2.1 Conceitos Básicos .................................................................................................................. 13
2.2 Exercícios com Vetores e Matrizes .................................................................................. 14
2.3 Alocação de Memória (RAM - Random Access Memory) .................................................... 21
2.3.1 Alocação Estática de Memória .................................................................................... 21
2.3.2 Alocação Dinâmica de Memória .................................................................................... 21
2.3.3 Célula, Nodo ou Nó ........................................................................................................ 21
3. Listas Lineares ............................................................................................................................... 22
3.1 Listas Genéricas .................................................................................................................... 22
3.2 Tipos de Representações ...................................................................................................... 24
3.2.1 Lista Representada por Contiguidade Física ........................................................ 24
3.2.2 Lista representada por Encadeamento ...................................................................... 61
3.2.3 Lista Encadeada com Descritor .................................................................................. 72
3.2.4 Lista Duplamente Encadeada ........................................................................................ 81
3.2.5 Listas Lineares com Disciplina de Acesso ............................................................ 88
3.2.5.1 Filas ...................................................................................................................... 88
Figura 12: Fila Circular ........................................................................................................ 89
3.2.5.1.1 Fila com Vetor ........................................................................................ 89
3.2.5.1.2 Fila Circular .......................................................................................... 93
3.2.5.1.3 Deslocamento dos elementos do vetor .............................................. 97
3.2.5.1.4 Fila com Alocação Dinâmica .............................................................. 100
3.2.5.2 Pilhas .................................................................................................................. 103
3.2.5.2.1 Pilha com Vetor .................................................................................... 104
3.2.5.2.2 Pilha com Alocação Dinâmica ............................................................ 109
3.2.5.3 Deque (“Double-Ended QUEue”) .................................................................. 112
4. Pesquisa de Dados ......................................................................................................................... 118
4.1 Pesquisa Seqüencial ............................................................................................................ 118
2
5.
6.
7.
8.
4.2 Pesquisa Binária .................................................................................................................. 124
4.3 Cálculo de Endereço (Hashing) ........................................................................................ 128
Classificação de Dados (Ordenação) ...................................................................................... 133
5.1 Classificação por Força Bruta ........................................................................................ 133
5.2 Vetor Indireto de Ordenação (Tabela de Índices) .................................................... 134
5.3 Classificação por Encadeamento ...................................................................................... 136
5.4 Métodos de Classificação Interna .................................................................................. 139
5.4.1 Método por Inserção Direta ...................................................................................... 139
5.4.2 Método por Troca .......................................................................................................... 142
5.4.2.1 Método da Bolha (Bubble Sort) .................................................................... 142
5.4.3 Método por Seleção ...................................................................................................... 144
5.4.3.1 Método por Seleção Direta ............................................................................ 144
Árvores ............................................................................................................................................. 147
6.1 Conceitos Básicos ................................................................................................................ 147
6.2 Árvores Binárias .................................................................................................................. 150
6.3 Representações ...................................................................................................................... 152
6.3.1 Representação por Contigüidade Física (Adjacência) ...................................... 152
6.3.2 Representação por Encadeamento .............................................................................. 154
6.4 Caminhamento em Árvores .................................................................................................... 154
6.4.1 Caminhamento Pré-Fixado (Pré-Ordem) .................................................................... 154
6.4.2 Caminhamento In-Fixado (Central) .......................................................................... 156
6.4.3 Caminhamento Pós-Fixado ............................................................................................ 156
6.4.4 Algoritmos recursivos para percorrer Árvores Binárias ................................ 157
6.4.4.1 Caminhamento Pré-Fixado (Pré-Ordem) ........................................................ 157
6.4.4.2 Caminhamento In-Fixado (Central) .............................................................. 158
6.4.4.3 Caminhamento Pós-Fixado ................................................................................ 158
6.5 Árvore de Busca Binária .................................................................................................... 160
6.6 Árvore AVL .............................................................................................................................. 163
6.6.1 Inserção em uma árvore AVL ...................................................................................... 164
6.6.2 Remoção em uma árvore AVL ........................................................................................ 172
Grafos ............................................................................................................................................... 175
7.1 Conceitos ................................................................................................................................ 175
7.2 Representação por Lista e Matriz de Adjacências .................................................... 183
7.2.1 Lista de Adjacências .................................................................................................. 183
7.2.2 Matriz de Adjacências ................................................................................................ 183
7.3 Percurso em Amplitude e Percurso em Profundidade .................................................. 184
7.4 Determinação do Caminho Mínimo ...................................................................................... 185
7.4.1 Algoritmo de Dijkstra ................................................................................................ 185
Programas exemplos ....................................................................................................................... 193
8.1 Torre de Hanoi (Pilha - Stack) ...................................................................................... 193
8.2 Analisador de Expressões (classes: PilhaInt e PilhaChar) .................................. 199
8.3 Analisador de Expressões usando Stack ........................................................................ 204
8.4 Calculadora Polonesa Reversa .......................................................................................... 207
8.5 Torre de Hanoi (classe Pilha) ........................................................................................ 210
8.6 Jogo Quebra-Cabeças ............................................................................................................ 215
Legenda de Cores
3
Vermelho <enter>: Entrada de dados do programa
Azul: Saída do programa (Resultado do Programa)
Verde: Texto em destaque
Preto: Texto normal
Preto: Método em destaque
Itálico: Código em Java
Negrito: Texto em destaque
Sublinado: Observações
1. Tipos de Dados
1.1 Conceitos Básicos
1.1.1 Estruturas de Dados
Estuda as principais técnicas de representação e manipulação de dados na memória
principal (Memória de Acesso Randômico, RAM – Random Access Memory).
1.1.2 Organização de Arquivos
Estuda as principais técnicas de representação e manipulação de dados na memória
secundária (Disco – Manipulação de Arquivos ou Banco de Dados).
1.1.3 Conceito
Figura 1: Representação de Dados e Informações
1.1.4 Dados
São as informações a serem representadas, armazenadas ou manipuladas.
1.1.5 Tipos de Dados
É o conjunto de valores que uma constante, variável, argumentos ou expressão
podem assumir, ou então um conjunto de valores que possam ser gerados ou retornados por
um método.
Na definição de uma variável, constante, expressão ou método deve-se definir o
Tipo de Dado, por algumas razões:
4
1) Representar um tipo abstrato de dado (Realidade);
2) Delimitar a faixa de abrangência (Limites);
3) Definir a quantidade de bytes para armazenamento;
4) E as operações que podem ser efetuadas sobre os dados.
Os tipos de dados podem ser: Primitivos
estruturados, são também chamados de Complexos.
ou
Estruturados,
sendo
que
os
1.2 Tipos Primitivos
São os tipos de dados que, além de depender das características do sistema,
dependem do processador e do co-processador aritmético contido na máquina.
1.2.1 Tipos primitivos da Linguagem de Programação Java
CARACTER: char ch;
INTEIRO: int i; byte i; short i; long i;
REAL: float f; double d;
LÓGICO: boolean flag;
Tabela 1: Tipos de Dados
Tipo
Bytes
Bits
boolean
char
byte
short
int
long
float
double
1
2
1
2
4
8
4
8
8
16
8
16
32
64
32
64
Faixa de valores
true ou false
0 à 65.535
-128 à 127
-32.768 à 32.767
-2.147.483.648 à 2.147.483.647
-2E63 à 2E63-1
1.40239846e-46 à 3.40282347e+38
4.94065645841246544e-324 à 1.7976931348623157e+308
Programa exemplo (1): Programa mostrando a declaração de variáveis de vários tipos.
// -------------------------------------------------- Fonte: Dados1.java
package dados1;
public class Dados1 {
public static void main(String[] args) {
boolean flag = true;
char ch = 'a';
byte b = 10;
short s = 155;
int i = 100;
long l = 123456;
float f = 1.23f;
// f significa float
double d = 12345.678;
5
String nome = “Paulo Roberto Gomes Luzzardi";
System.out.println("boolean: " + flag);
System.out.println("char: " + ch);
System.out.println("byte: " + b);
System.out.println("short: " + s);
System.out.println("int: " + i);
System.out.println("long: " + l);
System.out.println("float: " + f);
System.out.println("double: " + d);
System.out.println("String: " + nome);
}
}
Resultado do Programa:
boolean: true
char: a
byte: 10
short: 155
int: 100
long: 123456
float: 1.23
double: 12345.678
String: Paulo Roberto Gomes Luzzardi
Programa exemplo (2): Exemplo de programa para entrada de dados do tipo inteiro via
teclado e saída na tela usando métodos da classe “swing.
// -------------------------------------------------------- Fonte: Dados2.java
package dados2;
import javax.swing.*;
public class Dados2 {
public static void main(String[] args) {
String s;
// painel de entrada de dados
s = JOptionPane.showInputDialog("Número: ");
// converte string em inteiro
int x = Integer.parseInt(s);
JOptionPane.showMessageDialog(null, "Inteiro: " + x, "Resultado",
JOptionPane.PLAIN_MESSAGE);
}
}
Tabela 2: Tipos de Ícones (JOptionPane.showMessageDialog)
Tipo de Ícone
Ícone de erro
Ícone de informação “i”
Tipo de Mensagem
JOptionPane.ERROR_MESSAGE
JOptionPane.INFORMATION_MESSAG
6
E
JOptionPane.WARNING_MESSAGE
JOptionPane.QUESTION_MESSAGE
JOptionPane.PLAIN_MESSAGE
Ícone de advertência “!”
Ícone de pergunta “?”
Sem ícone
1.3 Construção de Tipos (Estruturados ou Complexos)
Tipos complexos obtidos através dos tipos primitivos do Java, podem ser:
// ------------------------------------ Cadeia de Caracteres
STRING: String s;
// ------------------------------------ Agregados Homogêneos
VETOR E MATRIZ: int [] vetor; int [][] matriz;
// ------------------------------------ Classe
CLASSE: public class nomeClasse {
1.3.1 String (Cadeia de Caracteres)
Tipo de dado que permite que uma variável possua um conjunto de caracteres.
Exemplos de declaração e inicialização:
String s = “”;
String s = new String(20);
String s = new String ("Pelotas");
1.3.2 Vetor e Matriz (Agregados Homogêneos)
Tipo de dado que permite que uma variável possua um conjunto de elementos do
mesmo tipo, todos alocados na memória ao mesmo tipo.
Exemplo:
// ------------------------------------------ constante tipada inteira
final int numElementos = 10;
float [] vetor = new float [numElementos];
// vetor[0] até vetor[9]
final int numLinhas = 3;
final int numColunas = 2;
double [][] matriz = new double[numLinhas][numColunas];
Exemplos de inicialização:
7
int [] vetor = {10, 20,30, 40, 50};
int [][] matriz = {{1,2},{3,4},{5,6}};
Programa exemplo (3): Programa demonstra a utilização de um vetor e uma matriz 2D.
// ---------------------------------------------------- Fonte: Dados3.java
package dados3;
public class Dados3 {
public static void main(String[] args) {
int [] vetor = {10, 20,30, 40, 50};
int [][] matriz = {{1,2},{3,4},{5,6}};
int numLinhas = 3, numColunas = 2;
System.out.println("Vetor Unidimensional");
for (int i = 0;i < vetor.length;i++) {
System.out.println("Vetor: " + vetor[i]);
}
System.out.println("Matriz Bidimensional ordem: " + numLinhas + " x " + numColunas);
for (int i = 0;i < numLinhas;i++) {
for (int j = 0;j < numColunas;j++) {
System.out.println("Matriz: " + matriz[i][j]);
}
}
}
}
Resultado do Programa:
Vetor Unidimensional
Vetor: 10
Vetor: 20
Vetor: 30
Vetor: 40
Vetor: 50
Matriz Bidimensional de ordem: 3 x 2
Matriz: 1
Matriz: 2
Matriz: 3
Matriz: 4
Matriz: 5
Matriz: 6
Programa exemplo (4): Uso de um vetor para ordenar valores inteiros positivos. O método
utilizado é o da força bruta.
// --------------------------------------------------------- Fonte: Dados4.java
package dados4;
public class Dados4 {
public static void main(String[] args) {
8
int[] vetor = {5, 40, 20, 10, 50, 30};
System.out.print("Vetor de Entrada: ");
for (int i = 1; i <= vetor[0]; i++) {
System.out.print(vetor[i] + " ");
}
System.out.println();
for (int i = 1; i < vetor[0]; i++) {
for (int j = i + 1; j <= vetor[0]; j++) {
if (vetor[i] > vetor[j]) {
int temp = vetor[i];
// sort
vetor[i] = vetor[j];
vetor[j] = temp;
}
}
}
System.out.print("Vetor Ordenado: ");
for (int i = 1; i <= vetor[0]; i++) {
System.out.print(vetor[i] + " ");
}
System.out.println();
System.out.println("Número de Elementos: " + vetor[0]);
}
}
Resultado do Programa:
Vetor de Entrada: 40 20 10 50 30
Vetor Ordenado: 10 20 30 40 50
Número de Elementos: 5
9
1.3.3 Classe (class)
Tipo de dado que permite instanciar (criar) objetos. Uma classe possui atributos
(conjuntos de variáveis que o objeto possui) e métodos (funções que manipulam os
atributos).
Programa exemplo (5): Programa mostra a declaração e uso de uma classe chamada Aluno.
// ---------------------------------------------- Fonte: Dados5.java
package dados5;
public class Dados5 {
public static void main(String[] args) {
Aluno aluno = new Aluno("Paulo", 10, 'm');
aluno.exibeAtributos();
System.out.println(aluno);
// chamada do método toString
}
}
// ---------------------------------------------- Fonte: Aluno.java
package dados5;
public class Aluno{
// -------------------------------------------- atributos da classe
private String nome;
private int matricula;
private char sexo;
// ------------------------------------------- construtor
Aluno(String nome, int matricula, char sexo) {
this.nome = nome;
this.matricula = matricula;
this.sexo = sexo;
}
// ------------------------------------------- exibeAtributos
public void exibeAtributos() {
System.out.println("Nome: " + nome);
System.out.println("Matricula: " + matricula);
if (sexo == 'M' || sexo == 'm') {
System.out.println("Sexo: Masculino");
}
else {
System.out.println("Sexo: Feminino");
}
}
// ------------------------------------------- toString
public String toString() {
return(nome + " ... " + matricula + " ... " + sexo);
}
}
10
Resultado do Programa:
Nome: Paulo
Matricula: 10
Sexo: Masculino
Paulo ... 10 ... m
1.4 Operadores (Aritméticos, Relacionais e Lógicos)
A seguir são descritos os operadores aritméticos, relacionais e lógicos da
Linguagem de Programnação Java.
1.4.1 Aritméticos
Responsáveis por
expressões matemáticas.
+
*
/
%
++
--
resolver
operações
matemáticas,
ou
seja,
utilziados
em
Tabela 3: Operadores Aritméticos
Adição
Subtração
Multiplicação
Divisão
Resto Inteiro da Divisão
Incremento
Decremento
1.4.2 Relacionais
Responsáveis por fazer comparações, ou seja, são utilizados em comandos que
possuem “condição”.
Tabela
>
<
>=
<=
==
!=
4: Operadores Relacionais
Maior
Menor
Maior ou Igual
Menor ou Igual
Igual
Diferente
1.4.3 Lógicos
Utilizados entre “condições” em comandos de seleção e repetição.
Tabela 5: Operadores Lógicos
&&
||
!
e
ou
não
Condição: Em Java um condição sempre tem um resultado true (v) ou false (f) dependendo
das varáveis ou expressões criadas pelo programador.
11
Exemplo:
boolean chuvendo = true;
if (!chuvendo) {
System.out.println("Está chuvendo");
} else {
System.out.println("Não está chuvendo");
}
}
Resultado da execução do programa: Não está chuvendo (porque?)
12
2. Vetores e Matrizes
Tipos de dados que permitem armazenamento de várias informações, na memória RAM,
no mesmo instante de tempo e com contigüidade física, ou seja, uma variável deste tipo
de dado possui vários elementos, igualmente distanciados, ou seja, um ao lado do outro
na memória principal e com a mesma quantidade de bytes de armazenamento(agregados
homogêneos).
2.1 Conceitos Básicos
Vetor: (É uma matriz unidimensional)
final int numElementos = 7;
int [] vetor = new int [numElementos];
Matriz: (Possui mais de uma dimensão)
final int numLinhas = 3;
final int numColunas = 4;
double [][] matriz = new double [numLinhas][numColunas];
Índice: Constante numérica inteira que referencia cada elemento do vetor ou da matriz.
Exemplos: Dada a definição acima:
vetor[0]......................................
vetor[numeroElementos - 1]....................
m[0][0].......................................
m[numLinhas - 1][numColunas - 1]..............
primeiro elemento
último elemento
primeiro elemento
último elemento
Entrada de um Vetor Unidimensional:
final int numElementos = 7;
int [] vetor = new int [numElementos];
for (int i = 0;i < numElementos;i++) {
s = JOptionPane.showInputDialog(“Valor: “);
vetor[i] = Integer.parseInt(s);
}
Entrada de uma Matriz Bidimensional:
13
final int numLinhas = 3;
final int numColunas = 4;
double [][] matriz = new double [numLinhas][numColunas];
for (int i = 0;i < numLinhas;i++) {
for (int j = 0;j < numColunas;j++) {
s = JOptionPane.showInputDialog(“Valor: “);
matriz[i][j] = Integer.parseInt(s);
}
}
2.2 Exercícios com Vetores e Matrizes
1) Escreva um programa em Java que lê uma matriz A (3 x 4) e cria 2 vetores SL e SC de
3 e 4 elementos que contenham respectivamente a soma das linhas (SL) e a soma das
colunas (SC). Imprimir os vetores SL e SC.
// ---------------------------------------------- Fonte: Matriz1.java
package matriz1;
import java.util.Scanner;
public class Matriz1 {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
String s;
final int numeroLinhas = 3, numeroColunas = 4;
int [][] a = new int[numeroLinhas][numeroColunas];
int [] sl = new int[numeroLinhas];
int [] sc = new int[numeroColunas];
for (int l = 0;l < numeroLinhas;l++) {
for (int c = 0;c < numeroColunas;c++) {
System.out.print("a [" + (l + 1) + "," + (c + 1) + "]: ");
s = entrada.nextLine();
a[l][c] = Integer.parseInt(s);
}
}
int k = 0;
for (int l = 0;l < numeroLinhas;l++) {
for (int c = 0;c < numeroColunas;c++) {
sl[k] = sl[k] + a[l][c];
}
k++;
}
System.out.println();
for (k = 0;k < numeroLinhas;k++) {
System.out.println("sl[" + (k + 1) + "]: " + sl[k]);
}
14
k = 0;
for (int c = 0;c < numeroColunas;c++) {
for (int l = 0;l < numeroLinhas;l++) {
sc[k] = sc[k] + a[l][c];
}
k++;
}
System.out.println();
for (k = 0;k < numeroColunas;k++) {
System.out.println("sc[" + (k + 1) + "]: " + sc[k]);
}
System.out.println();
}
}
Resultado do Programa:
a
a
a
a
a
a
a
a
a
a
a
a
[1,1]:
[1,2]:
[1,3]:
[1,4]:
[2,1]:
[2,2]:
[2,3]:
[2,4]:
[3,1]:
[3,2]:
[3,3]:
[3,4]:
1
2
3
4
1
2
3
4
5
6
7
8
sl[1]: 10
sl[2]: 10
sl[3]: 26
sc[1]:
sc[2]:
sc[3]:
sc[4]:
7
10
13
16
2) Escreva um programa em Java que lê uma matriz A (12 x 13) e divide todos os
elementos de cada uma das 12 linhas de A pelo valor do maior elemento daquela linha.
Imprimir a matriz A modificada.
Observação: Considere que a matriz armazena apenas elementos inteiros
// -------------------------------------------- Fonte: Matriz2.java
package matriz2;
public class Matriz2 {
public static void main(String[] args) {
int numeroLinhas = 12, numeroColunas = 13;
float [][] a = {{ 1,1,1,1,1,1,1,1,1,1,1,1,1},
15
{ 2,1,1,1,1,1,1,1,1,1,1,1,1},
{ 3,1,1,1,1,1,1,1,1,1,1,1,1},
{ 4,1,1,1,1,1,1,1,1,1,1,1,1},
{ 5,1,1,1,1,1,1,1,1,1,1,1,1},
{ 6,1,1,1,1,1,1,1,1,1,1,1,1},
{ 7,1,1,1,1,1,1,1,1,1,1,1,1},
{ 8,1,1,1,1,1,1,1,1,1,1,1,1},
{ 9,1,1,1,1,1,1,1,1,1,1,1,1},
{10,1,1,1,1,1,1,1,1,1,1,1,1},
{11,1,1,1,1,1,1,1,1,1,1,1,1},
{12,1,1,1,1,1,1,1,1,1,1,1,1}};
float [] maior = new float[numeroLinhas];
for (int l = 0;l < numeroLinhas;l++) {
for (int c = 0;c < numeroColunas;c++) {
if (a[l][c] > maior[l]) {
maior[l] = a[l][c];
}
}
}
for (int l = 0;l < numeroLinhas;l++) {
for (int c = 0;c < numeroColunas;c++) {
a[l][c] = a[l][c] / maior[l];
}
}
for (int l = 0;l < numeroLinhas;l++) {
System.out.printf("%4.1f -> ", maior[l]);
for (int c = 0;c < numeroColunas;c++) {
System.out.printf("%.2f ", a[l][c]);
}
System.out.println();
}
}
}
Resultado do Programa:
1,0
2,0
3,0
4,0
5,0
6,0
7,0
8,0
9,0
10,0
11,0
12,0
->
->
->
->
->
->
->
->
->
->
->
->
1,00
1,00
1,00
1,00
1,00
1,00
1,00
1,00
1,00
1,00
1,00
1,00
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
1,00
0,50
0,33
0,25
0,20
0,17
0,14
0,13
0,11
0,10
0,09
0,08
3) Escreva um programa em Java que insere números inteiros (máximo 5 elementos) em um
vetor mantendo-o ordenado. Quando o usuário digitar um ZERO o programa deve imprimir na
tela o vetor ordenado.
// ------------------------------------------------ Fonte: Ordenar.java
16
package ordenar;
import java.util.Scanner;
public class Ordenar {
public static void main(String[] args) {
Vetor vetor = new Vetor(5);
Scanner entrada = new Scanner(System.in);
int elemento;
do {
System.out.print("Elemento: ");
String s = entrada.nextLine();
elemento = Integer.parseInt(s);
if (elemento != 0) {
vetor.verificaPosicao(elemento);
}
vetor.exibeVetor();
} while (elemento != 0);
}
}
// ----------------------------------------------------- Fonte: Vetor.java
package ordenar;
public class Vetor {
private int n, u, max;
private int [] vet;
// atributos da classe
// atributos da classe
// --------------------------------------------- construtor
public Vetor(int numeroElementos) {
vet = new int[numeroElementos];
n = 0;
u = -1;
max = numeroElementos;
}
// --------------------------------------------- verificaPosicao
public void verificaPosicao(int elemento) {
int pos = 0;
for (int i = 0;i <= u;i++) {
if (elemento > vet[i]) {
pos = i + 1;
}
}
if (pos == 0) {
insereInicio(elemento);
}
else {
if (pos == u + 1) {
insereFim(elemento);
}
else {
inserePosicao(elemento, pos);
17
}
}
}
// --------------------------------------------- insereFim
private void insereFim(int elemento) {
if (n < max) {
u++;
vet[u] = elemento;
n++;
}
else {
System.out.println("ERRO: Vetor Lotado");
System.exit(0);
}
}
// --------------------------------------------- insereInicio
private void insereInicio(int elemento) {
if (n < max) {
if (n != 0) {
for (int i = u + 1; i >= 1;i--) {
vet[i] = vet[i-1];
}
}
u++;
vet[0] = elemento;
n++;
}
else {
System.out.println("ERRO: Vetor Lotado");
System.exit(0);
}
}
// --------------------------------------------- inserePosicao
private void inserePosicao(int elemento, int pos) {
if (n < max) {
if (n != 0) {
for (int i = u + 1; i > pos;i--) {
vet[i] = vet[i-1];
}
}
u++;
vet[pos] = elemento;
n++;
}
else {
System.out.println("ERRO: Vetor Lotado");
System.exit(0);
}
}
// --------------------------------------------- exibeVetor
public void exibeVetor() {
18
System.out.print("Vetor: [");
for (int i = 0;i < u;i++) {
System.out.print(vet[i] + ", ");
}
System.out.println(vet[u] + "]");
}
}
Resultado do Programa:
Elemento: 20 <enter>
Vetor: [20]
Elemento: 40 <enter>
Vetor: [20, 40]
Elemento: 10 <enter>
Vetor: [10, 20, 40]
Elemento: 30 <enter>
Vetor: [10, 20, 30, 40]
Elemento: 60 <enter>
Vetor: [10, 20, 30, 40, 60]
Elemento: 50 <enter>
ERRO: Vetor Lotado
4) Escreva um programa em Java que lê duas matrizes A e B e gera uma matriz C que é a
multiplicação da matriz A com a matriz B.
// ---------------------------------------------------- Fonte: MultMatriz.java
package multmatriz;
import java.util.Scanner;
public class MultMatriz {
public static void main(String[] args) {
int ma, na, mb, nb;
Scanner entrada = new Scanner(System.in);
String s;
System.out.print("Número de Linhas da Matriz A (mA): ");
s = entrada.nextLine();
ma = Integer.parseInt(s);
System.out.print("Número de Colunas da Matriz A(nA): ");
s = entrada.nextLine();
na = Integer.parseInt(s);
System.out.print("Número de Linhas da Matriz B(mB): ");
s = entrada.nextLine();
mb = Integer.parseInt(s);
System.out.print("Número de Colunas da Matriz B(nB): ");
s = entrada.nextLine();
nb = Integer.parseInt(s);
if (na != mb) {
System.out.println("Erro Fatal: Multiplicação Impossível");
System.out.println("Número de Colunas de A (nA) tem que ser igual número de linhas de B (mB)");
System.exit(0);
}
19
int [][] a = new int[ma][na];
int [][] b = new int[mb][nb];
int [][] c = new int[ma][nb];
System.out.println("Matriz A");
for (int lin = 0;lin < ma;lin++) {
for (int col = 0;col < na;col++) {
System.out.print("A[" + (lin + 1) + ", " + (col + 1) + "]: ");
s = entrada.nextLine();
a[lin][col] = Integer.parseInt(s);
}
}
System.out.println("Matriz B");
for (int lin = 0;lin < mb;lin++) {
for (int col = 0;col < nb;col++) {
System.out.print("B[" + (lin + 1) + ", " + (col + 1) + "]: ");
s = entrada.nextLine();
b[lin][col] = Integer.parseInt(s);
}
}
System.out.println("Matriz C = A x B");
for (int lin = 0;lin < ma;lin++) {
for (int col = 0;col < nb;col++) {
c[lin][col] = 0;
for (int k = 0;k < na;k++) {
c[lin][col] = c[lin][col] + a[lin][k] * b[k][col];
}
}
}
for (int lin = 0;lin < ma;lin++) {
for (int col = 0;col < nb;col++) {
System.out.println("C[" + (lin + 1) + ", " + (col + 1) + "]: " + c[lin][col]);
}
}
}
}
Resultado do Programa:
Número de Linhas da Matriz A (mA): 2 <enter>
Número de Colunas da Matriz A(nA): 2 <enter>
Número de Linhas da Matriz B(mB): 2 <enter>
Número de Colunas da Matriz B(nB): 3 <enter>
Matriz A
A[1, 1]: 1 <enter>
A[1, 2]: 2 <enter>
A[2, 1]: 3 <enter>
A[2, 2]: 4 <enter>
Matriz B
B[1, 1]: 1 <enter>
B[1, 2]: 2 <enter>
B[1, 3]: 3 <enter>
B[2, 1]: 4 <enter>
B[2, 2]: 5 <enter>
B[2, 3]: 6 <enter>
Matriz C = A x B
B[1, 1]: 9
20
B[1,
B[1,
B[2,
B[2,
B[2,
2]:
3]:
1]:
2]:
3]:
12
15
19
26
33
Operações sobre os Dados





Criação dos Dados
Manutenção dos Dados
o Inserção de um Componente
o Remoção de um Componente
o Alteração de um Componente
Consulta aos Dados
Destruição dos Dados
Pesquisa e Classificação
2.3 Alocação de Memória (RAM - Random Access Memory)
2.3.1 Alocação Estática de Memória
É a forma mais simples de alocação, na qual cada dado tem sua área reservada,
não variando em tamanho ou localização ao longo da execução do programa.
float f;
// variável “f” ocupa 4 bytes na memória RAM
2.3.2 Alocação Dinâmica de Memória
Nesta forma de alocação, são feitas requisições e liberações de porções da
memória ao longo da execução do programa (enquanto houver memória livre na máquina).
Observação: Em Java a liberação é feita automaticamente pelo coletor de lixo ( Garbage
Collector) ou por chamada formal do programador da seguinte forma:
System.gc(); // faz a chamada formal do coletor de lixo
2.3.3 Célula, Nodo ou Nó
Espaço reservado (alocado) na memória RAM para uma variável (tipo primitivo ou
complexo), ou seja, número de bytes “gastos” para o armazenamento de um dado. É uma
informação abstrata que independe do tipo de dado, ou seja, pode ser de qualquer tipo
de dado.
21
3. Listas Lineares
3.1 Listas Genéricas
Conceito
Conjunto de dados que mantém a relação de ordem Linear entre os componentes. É
composta de elementos (componentes ou nós), os quais podem conter um dado primitivo ou
estruturado.
Lista Linear
É uma estrutura que permite representar um conjunto de dados de forma a
preservar a relação de ordem entre eles.
Uma lista linear X é um conjunto de nodos (nós) X1, X2, ... Xn, Tais que:
1)
2)
3)
4)
Existem “n” nodos na lista (n >= 0);
X1 é o primeiro nodo da lista;
Xn é o último nodo da lista;
Para todo i,j entre 1 e n, se i<j, então o elemento Xi antecede o elemento
Xj;
5) Caso i = j-1, Xi é o antecessor de Xj e Xj é o sucessor de Xi.
Figura 2: Lista Linear
Observação: Quando n = 0, diz-se que a Lista é Vazia
Exemplos de Listas
·
·
·
Lista de clientes de um Banco;
Lista da Chamada de Alunos;
Fichário.
22
Operações sobre Listas
1) Percurso
Permite utilizar cada um dos elementos de uma lista, de tal forma que:
·
·
·
0 primeiro nodo utilizado é o primeiro da lista;
Para utilizar o nodo Xj, todos os nodos de X1 até X(j-1) já foram utilizados;
último nodo utilizado é o último nodo da lista.
2) Busca
Procura um nodo específico da lista linear, de tal forma que:
·
·
nodo é identificado por sua posição na lista;
nodo é identificado pelo seu conteúdo.
3) Inserção
Acrescenta um nodo X a uma lista linear, de tal forma que:
·
·
·
nodo X terá um sucessor e/ou um antecessor;
Após inserir o nodo X na posição i (i >= 1 e i <= n+1), ele passará a ser i-ésimo
nodo da lista;
número de elementos (n) é acrescido de uma unidade.
Figura 3: Inserção de Elementos em uma Lista Linear
4) Retirada (Exclusão)
Retira um nodo X da lista, de tal forma que:
·
·
Se Xi é o elemento retirado, o seu sucessor passa a ser o sucessor de seu
antecessor. X(i+1) passa a ser o sucessor de X(i-1). Se Xi é o primeiro nodo, o seu
sucessor passa a ser o primeiro, se Xi é o último, o seu antecessor passa a ser o
último;
número de elementos (n) é decrescido de uma unidade.
23
Operações Válidas sobre Listas
·
·
·
·
·
·
·
·
·
Acessar um elemento qualquer da lista;
Inserir um novo elemento à lista;
Concatenar duas listas;
Determinar o número de elementos da lista;
Localizar um elemento da lista com um determinado valor;
Excluir um elemento da lista;
Alterar um elemento da lista;
Criar uma lista;
Destruir a lista.
3.2 Tipos de Representações
3.2.1 Lista Representada por Contiguidade Física
Os nodos são armazenados em endereços contíguos, ou igualmente distanciados um
do outro.
Os elementos são armazenados na memória um ao lado do outro, levando-se em
consideração o tipo de dado, ou seja, a quantidade de bytes.
Se o endereço do nodo Xi é conhecido, então o endereço do nodo X(i+1) pode ser
determinado.
Figura 4: Contigüidade Física
·
·
Os relacionamentos são representados pela disposição física dos componentes na
memória;
A posição na estrutura lógica determina a posição na estrutura física.
Observação: Uma lista pode ser implementada através de um vetor de “m” elementos.
Atenção: Se “n” = “m” a Lista é chamada Cheia
24
Observação: Como o número de nodos armazenados na lista pode ser modificado durante a
execução do programa, deve-se representar como parte de um vetor de “m” elementos com
“n <= m”.
Figura 5: Lista Linear: Estrutura física e lógica
Representação: A lista X está representada por um vetor V de “m” elementos.
Componentes de uma Lista
·
·
·
Número de nodos da lista (n); // armazenado na posição 0 do vetor
Vetor de nodos (v);
Tamanho total da lista (m).
Figura 6: Componentes de uma Lista Linear
final int m = 7;
int [] v = new int [m];
Observação: O número de elementos da lista será armazenado na posição 0 do vetor, ou
seja: n = v[0].
Programa exemplo (6): O programa abaixo demonstra a construção de uma lista de m
elementos, onde o número de elementos é armazenado na posição zero do vetor, ou seja, n
= v[0].
25
// ---------------------------------------------------------- Fonte: Dados6.java
package dados6;
import javax.swing.*;
public class Dados6 {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
public static void main(String[] args) {
int m = 7;
int[] v = new int[m];
int valor;
int erro = 0;
criaLista(v);
do {
String s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = incluiFim(m, v, valor);
}
if (erro == LISTA_CHEIA) {
JOptionPane.showMessageDialog(null, "Erro: Lista Cheia", "Atenção", JOptionPane.PLAIN_MESSAGE);
exibeLista(v);
return;
}
} while (valor != 0);
exibeLista(v);
}
// -------------------------------------------------- criaLista
static void criaLista(int[] v) {
v[0] = 0;
}
// -------------------------------------------------- incluiFim
static int incluiFim(int m, int[] v, int valor) {
int n = v[0];
if (n < m - 1) {
v[0]++;
v[v[0]] = valor;
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- exibeLista
static void exibeLista(int[] v) {
String s = "";
int n = v[0];
if (n == 0) {
JOptionPane.showMessageDialog(null, "Erro: Lista Vazia", "Atenção", JOptionPane.PLAIN_MESSAGE);
} else {
26
for (int i = 1; i <= n; i++) {
s = s + v[i] + " ";
}
JOptionPane.showMessageDialog(null, "Lista: " + s, "Lista", JOptionPane.PLAIN_MESSAGE);
}
}
}
Programa exemplo (6a): O programa abaixo demonstra a construção de uma lista de m
elementos, onde o número de elementos é armazenado na posição zero do vetor, ou seja, n
= v[0]. O programa possui uma classe Lista.
// ----------------------------------------------------------- Dados6a.java
package dados6a;
import javax.swing.*;
public class Dados6a {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
public static void main(String[] args) {
Lista lista = new Lista(7);
String s;
int valor;
int erro = 0;
do {
s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = lista.incluiFim(valor);
}
if (erro == LISTA_CHEIA) {
JOptionPane.showMessageDialog(null, "Erro: Lista Cheia", "Atenção",
JOptionPane.PLAIN_MESSAGE);
lista.exibeLista();
return;
}
} while (valor != 0);
lista.exibeLista();
}
}
// --------------------------------------------------------------------- Lista.java
package dados6a;
import javax.swing.*;
public class Lista {
final static int SUCESSO = 0;
27
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
private final int[] v;
// -------------------------------------------------- criaLista
public Lista(int numElementos) {
v = new int[numElementos];
v[0] = 0;
}
// -------------------------------------------------- incluiFim
public int incluiFim(int valor) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
v[v[0]] = valor;
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- exibeLista
public void exibeLista() {
String s = "";
int n = v[0];
if (n == 0) {
JOptionPane.showMessageDialog(null, "Erro: Lista Vazia", "Atenção", JOptionPane.PLAIN_MESSAGE);
} else {
for (int i = 1; i <= n; i++) {
s = s + v[i] + " ";
}
JOptionPane.showMessageDialog(null, "Lista: " + s, "Lista", JOptionPane.PLAIN_MESSAGE);
}
}
}
Problema: Incluir dados em uma lista de números inteiros (máximo 10 elementos),
mantendo-a ordenada.
Programa exemplo (7): O programa abaixo demonstra a construção de uma lista de m
elementos ordenados diretamente na entrada dos dados.
// ----------------------------------------------------------- Fonte: Dados7.java
package dados7;
import javax.swing.*;
public class Dados7 {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
28
public static void main(String[] args) {
final int m = 7;
int [] v = new int [m];
int valor;
int erro = 0;
criaLista(v);
String s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = incluiInic(m, v, valor);
do {
s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = verificaPos(m, v, valor);
if (erro == LISTA_CHEIA) {
JOptionPane.showMessageDialog(null,
"Erro: Lista Cheia", "Atenção", JOptionPane.PLAIN_MESSAGE);
exibeLista(v);
return;
}
}
} while (valor != 0);
}
exibeLista(v);
}
// -------------------------------------------------- criaLista
static void criaLista(int [] v) {
v[0] = 0;
}
// -------------------------------------------------- incluiFim
static int incluiFim(int m, int [] v, int valor) {
int n = v[0];
if (n < m - 1) {
v[0]++;
v[v[0]] = valor;
return(SUCESSO);
} else {
return(LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiInic
static int incluiInic(int m, int [] v, int valor) {
int n = v[0];
if (n < m - 1) {
v[0]++;
for (int i = n + 1;i >= 2;i--) {
v[i] = v[i-1];
}
v[1] = valor;
29
return(SUCESSO);
} else {
return(LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiPos
static int incluiPos(int m, int [] v, int valor, int pos) {
int n = v[0];
if (n < m - 1)
{
v[0]++;
if (pos == n) {
v[v[0]] = v[n];
v[n] = valor;
} else {
for (int i = n + 1;i >= pos;i--) {
v[i] = v[i-1];
System.out.println("Valor: " + v[i]);
}
v[pos] = valor;
}
return(SUCESSO);
} else {
return(LISTA_CHEIA);
}
}
// -------------------------------------------------- tamanhoLista
static int tamanhoLista(int [] v) {
return(v[0]);
}
// -------------------------------------------------- verificaPos
static int verificaPos(int m, int [] v, int valor) {
int i = 1;
do {
if (valor < v[i]) {
return(incluiPos(m, v, valor, i));
}
i++;
} while (i <= v[0]);
return(incluiFim(m, v, valor));
}
// -------------------------------------------------- exibeLista
static void exibeLista(int [] v) {
String s = "";
int n = v[0];
if (n == 0) {
JOptionPane.showMessageDialog(null, "Erro: Lista Vazia",
"Atenção", JOptionPane.PLAIN_MESSAGE);
30
} else {
for (int i = 1; i <= n; i++) {
s = s + v[i] + " ";
}
JOptionPane.showMessageDialog(null, "Lista: " + s, "Lista",
JOptionPane.PLAIN_MESSAGE);
}
}
}
Programa exemplo (7a): O programa abaixo demonstra a construção de uma lista de m
elementos ordenados diretamente na entrada dos dados. O programa possui uma classe
ListaOrdenada.
// ------------------------------------------------------------------ Dados7a.java
package dados7a;
import javax.swing.*;
public class Dados7a {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
public static void main(String[] args) {
ListaOrdenada lista = new ListaOrdenada(7);
int valor;
int erro = 0;
String s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = lista.incluiInic(valor);
do {
s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = lista.verificaPos(valor);
if (erro == LISTA_CHEIA) {
JOptionPane.showMessageDialog(null, "Erro: Lista Cheia", "Atenção",
JOptionPane.PLAIN_MESSAGE);
lista.exibeLista();
return;
}
}
} while (valor != 0);
}
lista.exibeLista();
}
}
// -------------------------------------------------------------- ListaOrdenada.java
package dados7a;
31
import javax.swing.*;
public class ListaOrdenada {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
int [] v;
// -------------------------------------------------- criaLista
public ListaOrdenada(int numElementos) {
v = new int[numElementos];
v[0] = 0;
}
// -------------------------------------------------- incluiFim
public int incluiFim(int valor) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
v[v[0]] = valor;
return(SUCESSO);
} else {
return(LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiInic
public int incluiInic(int valor) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
for (int i = n + 1;i >= 2;i--) {
v[i] = v[i-1];
}
v[1] = valor;
return(SUCESSO);
} else {
return(LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiPos
public int incluiPos(int valor, int pos) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
if (pos == n) {
v[v[0]] = v[n];
v[n] = valor;
32
} else {
for (int i = n + 1;i >= pos;i--) {
v[i] = v[i-1];
System.out.println("Valor: " + v[i]);
}
v[pos] = valor;
}
return(SUCESSO);
} else {
return(LISTA_CHEIA);
}
}
// -------------------------------------------------- tamanhoLista
private int tamanhoLista() {
return(v[0]);
}
// -------------------------------------------------- verificaPos
public int verificaPos(int valor) {
int i = 1;
do {
if (valor < v[i]) {
return(incluiPos(valor, i));
}
i++;
} while (i <= v[0]);
return(incluiFim(valor));
}
// -------------------------------------------------- exibeLista
public void exibeLista() {
String s = "";
int n = v[0];
if (n == 0) {
JOptionPane.showMessageDialog(null, "Erro: Lista Vazia",
"Atenção", JOptionPane.PLAIN_MESSAGE);
} else {
for (int i = 1; i <= n; i++) {
s = s + v[i] + " ";
}
JOptionPane.showMessageDialog(null, "Lista: " + s, "Lista",
JOptionPane.PLAIN_MESSAGE);
}
}
}
Problema: Incluir dados em uma lista linear de números inteiros (máximo 50) sem
repetição. O programa termina quando o dado lido for zero, então o programa deve
imprimir a lista na tela sem repetição.
33
Programa exemplo (8): O programa abaixo demonstra a construção de uma lista de m
elementos ordenados e SEM REPETIÇÃO diretamente na entrada dos dados.
// --------------------------------------------------------- Fonte: Dados8.java
package dados8;
import javax.swing.*;
public class Dados8 {
final
final
final
final
static
static
static
static
int
int
int
int
SUCESSO = 0;
LISTA_CHEIA = 1;
LISTA_VAZIA = 2;
REPETIDO = 3;
public static void main(String[] args) {
int m = 7;
int[] v = new int[m];
int valor;
int erro = 0;
criaLista(v);
String s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = incluiInic(m, v, valor);
do {
s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = verificaPos(m, v, valor);
switch (erro) {
case REPETIDO:
JOptionPane.showMessageDialog(null, "Erro: Elemento REPETIDO");
break;
case LISTA_CHEIA:
JOptionPane.showMessageDialog(null, "Erro: Lista Cheia");
exibeLista(v);
return;
}
}
} while (valor != 0);
}
exibeLista(v);
}
// -------------------------------------------------- criaLista
static void criaLista(int[] v) {
v[0] = 0;
}
// -------------------------------------------------- incluiFim
static int incluiFim(int m, int[] v, int valor) {
int n = v[0];
if (n < m - 1) {
v[0]++;
34
v[v[0]] = valor;
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiInic
static int incluiInic(int m, int[] v, int valor) {
int n = v[0];
if (n < m - 1) {
v[0]++;
for (int i = n + 1; i >= 2; i--) {
v[i] = v[i - 1];
}
v[1] = valor;
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiPos
static int incluiPos(int m, int[] v, int valor, int pos) {
int n = v[0];
if (n < m - 1) {
v[0]++;
if (pos == n) {
v[v[0]] = v[n];
v[n] = valor;
} else {
for (int i = n + 1; i >= pos; i--) {
v[i] = v[i - 1];
}
v[pos] = valor;
}
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- tamanhoLista
static int tamanhoLista(int[] v) {
return (v[0]);
}
// -------------------------------------------------- verificaPos
static int verificaPos(int m, int[] v, int valor) {
int i = 1;
do {
if (valor == v[i]) {
return (REPETIDO);
}
if (valor < v[i]) {
return (incluiPos(m, v, valor, i));
35
}
i++;
} while (i <= v[0]);
return (incluiFim(m, v, valor));
}
// -------------------------------------------------- exibeLista
static void exibeLista(int[] v) {
String s = "";
int n = v[0];
if (n == 0) {
JOptionPane.showMessageDialog(null, "Erro: Lista Vazia");
} else {
for (int i = 1; i <= n; i++) {
s = s + v[i] + " ";
}
JOptionPane.showMessageDialog(null, "Lista: " + s);
}
}
}
Programa exemplo (8a): O programa abaixo demonstra a construção de uma lista de m
elementos ordenados e SEM REPETIÇÃO diretamente na entrada dos dados. O programa possui
uma classe ListaSemRepeticao.
// --------------------------------------------------------------- Fonte: Dados8a.java
package dados8a;
import javax.swing.*;
public class Dados8a {
final
final
final
final
static
static
static
static
int
int
int
int
SUCESSO = 0;
LISTA_CHEIA = 1;
LISTA_VAZIA = 2;
REPETIDO = 3;
public static void main(String[] args) {
ListaSemRepeticao lista = new ListaSemRepeticao(7);
int valor;
int erro = 0;
String s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = lista.incluiInic(valor);
do {
s = JOptionPane.showInputDialog("Elemento: ");
valor = Integer.parseInt(s);
if (valor != 0) {
erro = lista.verificaPos(valor);
switch (erro) {
case REPETIDO:
JOptionPane.showMessageDialog(null, "Erro: Elemento REPETIDO");
break;
case LISTA_CHEIA:
36
JOptionPane.showMessageDialog(null, "Erro: Lista Cheia");
lista.exibeLista();
return;
}
}
} while (valor != 0);
}
lista.exibeLista();
}
}
// ----------------------------------------------------- Fonte: ListaSemRepeticao.java
package dados8a;
import javax.swing.*;
public class ListaSemRepeticao {
private final int[] v;
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
final static int REPETIDO = 3;
// -------------------------------------------------- construtor
public ListaSemRepeticao(int numElementos) {
v = new int[numElementos];
v[0] = 0;
}
// -------------------------------------------------- incluiFim
public int incluiFim(int valor) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
v[v[0]] = valor;
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- incluiInic
public int incluiInic(int valor) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
for (int i = n + 1; i >= 2; i--) {
v[i] = v[i - 1];
}
v[1] = valor;
return (SUCESSO);
} else {
return (LISTA_CHEIA);
37
}
}
// -------------------------------------------------- incluiPos
public int incluiPos(int valor, int pos) {
int m = v.length;
int n = v[0];
if (n < m - 1) {
v[0]++;
if (pos == n) {
v[v[0]] = v[n];
v[n] = valor;
} else {
for (int i = n + 1; i >= pos; i--) {
v[i] = v[i - 1];
}
v[pos] = valor;
}
return (SUCESSO);
} else {
return (LISTA_CHEIA);
}
}
// -------------------------------------------------- tamanhoLista
public int tamanhoLista() {
return (v[0]);
}
// -------------------------------------------------- verificaPos
public int verificaPos(int valor) {
int i = 1;
do {
if (valor == v[i]) {
return (REPETIDO);
}
if (valor < v[i]) {
return (incluiPos(valor, i));
}
i++;
} while (i <= v[0]);
return (incluiFim(valor));
}
// -------------------------------------------------- exibeLista
public void exibeLista() {
String s = "";
int n = v[0];
if (n == 0) {
JOptionPane.showMessageDialog(null, "Erro: Lista Vazia");
} else {
for (int i = 1; i <= n; i++) {
s = s + v[i] + " ";
}
JOptionPane.showMessageDialog(null, "Lista: " + s);
}
38
}
}
Contiguidade Física
Uma alternativa para representação por contigüidade física é não iniciar no
início do vetor, isto facilita as inserções.
Figura 7: Contigüidade Física
Observação: As operações de inclusão e exclusão de nodos podem optar pela extremidade
da lista que irá diminuir (no caso de exclusão) ou aumentar (no caso de inserção) de
comprimento. “A escolha deverá considerar o caso que produz menor movimentação de
elementos”.
final int m = 7;
int inicio;
int fim;
int []v = new int[m];
ou
final int m = 7;
int []v = new int[m + 2];
// onde v[0] = inic e v[m] = fim
Lista vazia
início = -1
fim = -1
Lista cheia
início = 0
fim = m - 1
Problema: Escreva um programa em Java que permite a inclusão de números inteiros no
início ou no fim da lista linear (máximo 7 elementos), partindo do meio do vetor:
39
metade =(m / 2) + 1
inic
fim
+-------------------------------------+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+-------------------------------------+
| -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -1 |
+-------------------------------------+
|---------------------------- v -------------|
Figura 8: Lista Linear
Programa exemplo (9): O programa abaixo demonstra a inclusão de números inteiros no
início ou no fim de uma lista linear.
// ------------------------------------------------------ Fonte: Dados9.java
package dados9;
import java.util.Scanner;
public class Dados9 {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
final int m = 7;
int[] v = new int[m + 2];
// v[0] = inic e v[m] = fim
int valor;
int erro = SUCESSO;
char ch = 'A';
criaLista(v);
do {
exibeLista(v);
System.out.printf("\nValor: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
System.out.printf("[I]nício ou [F]im ?");
do {
s = entrada.nextLine();
ch = s.charAt(0);
} while (ch != 'I' && ch != 'i' && ch != 'F' && ch != 'f');
}
switch (ch) {
case 'I':
case 'i':
erro = incluiInicio(v, valor);
40
break;
case 'F':
case 'f':
erro = incluiFim(v, valor);
break;
}
if (erro != SUCESSO) {
imprimeErro(erro);
}
} while (valor != 0 && erro != LISTA_CHEIA);
exibeLista(v);
}
// ---------------------------------------------- Cria_Lista
static void criaLista(int[] v) {
int inic = 0;
int fim = v.length - 1;
v[inic] = -1;
v[fim] = -1;
}
// ---------------------------------------------- Inclui_Inicio
static int incluiInicio(int[] v, int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (inic == -1) {
inic = metade;
fim = inic;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return (SUCESSO);
} else {
if (inic == 1) {
return (LISTA_CHEIA);
} else {
inic--;
v[inic] = dado;
v[0] = inic;
return (SUCESSO);
}
}
}
// ---------------------------------------------- Inclui_Fim
static int incluiFim(int[] v, int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (fim == -1) {
inic = metade;
fim = inic;
v[fim] = dado;
41
v[0] = inic;
v[v.length - 1] = fim;
return (SUCESSO);
} else {
if (fim == m) {
return (LISTA_CHEIA);
} else {
fim++;
v[fim] = dado;
v[v.length - 1] = fim;
return (SUCESSO);
}
}
}
// ---------------------------------------------- Imprime_Erro
static void imprimeErro(int erro) {
switch (erro) {
case LISTA_VAZIA:
System.out.println("ERRO: Lista Vazia");
break;
case LISTA_CHEIA:
System.out.println("ERRO: Lista Cheia");
break;
}
}
// ---------------------------------------------- Exibe_Lista
static void exibeLista(int[] v) {
int inic = v[0];
int fim = v[v.length - 1];
System.out.println("inic: " + inic);
System.out.println(" fim: " + fim);
System.out.printf("indices: ");
for (int i = 0; i < v.length; i++) {
System.out.printf("%2d ", i);
}
System.out.println();
System.out.printf(" Lista: ");
for (int i = 0; i < v.length; i++) {
System.out.printf("%2d ", v[i]);
}
}
}
Resultado do Programa:
inic: -1
fim: -1
indices: 0 1 2 3 4 5
Lista: -1 0 0 0 0 0
Valor: 10 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 4
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 0
Valor: 20 <enter>
6
0
7 8
0 -1
6
0
7
0
8
4
42
[I]nício
inic: 4
fim: 5
indices:
Lista:
Valor: 5
[I]nício
inic: 3
fim: 5
indices:
Lista:
Valor: 0
inic: 2
fim: 5
indices:
Lista:
ou [F]im ?f <enter>
0 1 2 3 4 5 6
4 0 0 0 10 20 0
<enter>
ou [F]im ?i <enter>
7
0
8
5
0 1 2
3 0 0
<enter>
0
2
1
0
2
0
3 4 5
5 10 20
6
0
7
0
8
5
3 4 5
5 10 20
6
0
7
0
8
5
Programa exemplo (9a): O programa abaixo demonstra a inclusão de números inteiros no
início ou no fim de uma lista linear. O programa possui uma classe ListaLinear.
// ------------------------------------------------------------------- Fonte: Dados9a.java
package dados9a;
import java.util.Scanner;
public class Dados9a {
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
public static void main(String[] args) {
ListaLinear lista = new ListaLinear(7);
Scanner entrada = new Scanner(System.in);
String s;
int valor;
int erro = SUCESSO;
char ch = 'A';
do {
lista.exibeLista();
System.out.printf("\nValor: ");
s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
System.out.printf("[I]nício ou [F]im ?");
do {
s = entrada.nextLine();
ch = s.charAt(0);
} while (ch != 'I' && ch != 'i' && ch != 'F' && ch != 'f');
}
switch (ch) {
case 'I':
case 'i':
erro = lista.incluiInicio(valor);
break;
case 'F':
43
case 'f':
erro = lista.incluiFim(valor);
break;
}
if (erro != SUCESSO) {
lista.imprimeErro(erro);
}
} while (valor != 0 && erro != LISTA_CHEIA);
lista.exibeLista();
}
}
// ------------------------------------------------------------ Fonte: ListaLinear.java
package dados9a;
public class ListaLinear {
private int[] v;
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
// ---------------------------------------------- construtor
public ListaLinear(int numElementos) {
v = new int[numElementos + 2];
// v[0] = inic e v[m] = fim
int inic = 0;
int fim = v.length - 1;
v[inic] = -1;
v[fim] = -1;
}
// ---------------------------------------------- incluiInicio
public int incluiInicio(int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (inic == -1) {
inic = metade;
fim = inic;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return (SUCESSO);
} else {
if (inic == 1) {
return (LISTA_CHEIA);
} else {
inic--;
v[inic] = dado;
v[0] = inic;
return (SUCESSO);
}
}
}
// ---------------------------------------------- incluiFim
44
public int incluiFim(int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (fim == -1) {
inic = metade;
fim = inic;
v[fim] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return (SUCESSO);
} else {
if (fim == m) {
return (LISTA_CHEIA);
} else {
fim++;
v[fim] = dado;
v[v.length - 1] = fim;
return (SUCESSO);
}
}
}
// ---------------------------------------------- imprimeErro
public void imprimeErro(int erro) {
switch (erro) {
case LISTA_VAZIA:
System.out.println("ERRO: Lista Vazia");
break;
case LISTA_CHEIA:
System.out.println("ERRO: Lista Cheia");
break;
}
}
// ---------------------------------------------- exibeLista
public void exibeLista() {
int inic = v[0];
int fim = v[v.length - 1];
System.out.println("inic: " + inic);
System.out.println(" fim: " + fim);
System.out.printf("indices: ");
for (int i = 0; i < v.length; i++) {
System.out.printf("%2d ", i);
}
System.out.println();
System.out.printf(" Lista: ");
for (int i = 0; i < v.length; i++) {
System.out.printf("%2d ", v[i]);
}
}
}
Resultado do Programa:
inic: -1
45
fim: -1
indices: 0 1 2 3 4 5
Lista: -1 0 0 0 0 0
Valor: 10 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 4
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 0
Valor: 20 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 5
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 20
Valor: 5 <enter>
[I]nício ou [F]im ?i <enter>
inic: 3
fim: 5
indices: 0 1 2 3 4 5
Lista: 3 0 0 5 10 20
Valor: 0 <enter>
inic: 2
fim: 5
indices: 0 1 2 3 4 5
Lista: 2 0 0 5 10 20
6
0
7 8
0 -1
6
0
7
0
8
4
6
0
7
0
8
5
6
0
7
0
8
5
6
0
7
0
8
5
Problema: Escreva um programa em Java que permite a inclusão de números inteiros no
início ou no fim da lista linear (máximo 7 elementos) avisando qual lado está cheio.
Observação: Note que a lista pode estar cheia num lado e não estar cheia no outro lado.
A próxima solução (10) avisa ao usuário qual lado da lista linear está cheia.
Programa exemplo (10): O programa abaixo demonstra a inclusão de números inteiros no
início ou no fim de uma lista linear avisando qual lado está cheio.
// --------------------------------------------------------- Fonte: Dados10.java
package dados10;
import java.util.Scanner;
public class Dados10 {
final static int SUCESSO = 0;
final static int LISTA_CHEIA_DIREITA = 1;
final static int LISTA_CHEIA_ESQUERDA = 2;
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
final int m = 7;
int[] v = new int[m + 2];
// v[0] = inic e v[m] = fim
int valor;
int erro = SUCESSO;
char ch = 'A';
46
criaLista(v);
do {
exibeLista(v);
System.out.printf("\nValor: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
System.out.printf("[I]nício ou [F]im ?");
do {
s = entrada.nextLine();
ch = s.charAt(0);
} while (ch != 'I' && ch != 'i' && ch != 'F' && ch != 'f');
}
switch (ch) {
case 'I':
case 'i':
erro = incluiInicio(v, valor);
break;
case 'F':
case 'f':
erro = incluiFim(v, valor);
break;
}
if (erro != SUCESSO) {
imprimeErro(erro);
}
} while (valor != 0);
exibeLista(v);
}
// ---------------------------------------------- Cria_Lista
static void criaLista(int[] v) {
int inic = 0;
int fim = v.length - 1;
v[inic] = -1;
v[fim] = -1;
}
// ---------------------------------------------- Inclui_Inicio
static int incluiInicio(int[] v, int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (inic == -1) {
inic = metade;
fim = inic;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return (SUCESSO);
} else {
if (inic == 1) {
return (LISTA_CHEIA_ESQUERDA);
} else {
inic--;
v[inic] = dado;
47
v[0] = inic;
return (SUCESSO);
}
}
}
// ---------------------------------------------- Inclui_Fim
static int incluiFim(int[] v, int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (fim == -1) {
inic = metade;
fim = inic;
v[fim] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return (SUCESSO);
} else {
if (fim == m) {
return (LISTA_CHEIA_DIREITA);
} else {
fim++;
v[fim] = dado;
v[v.length - 1] = fim;
return (SUCESSO);
}
}
}
// ---------------------------------------------- Imprime_Erro
static void imprimeErro(int erro) {
switch (erro) {
case LISTA_CHEIA_ESQUERDA:
System.out.println("ERRO: Lista Cheia a Esquerda");
break;
case LISTA_CHEIA_DIREITA:
System.out.println("ERRO: Lista Cheia a Direita");
break;
}
}
// ---------------------------------------------- Exibe_Lista
static void exibeLista(int[] v) {
int inic = v[0];
int fim = v[v.length - 1];
System.out.println("inic: " + inic);
System.out.println(" fim: " + fim);
System.out.printf("indices: ");
for (int i = 0; i < v.length; i++) {
System.out.printf("%2d ", i);
}
System.out.println();
System.out.printf(" Lista: ");
for (int i = 0; i < v.length; i++) {
System.out.printf("%2d ", v[i]);
48
}
}
}
Resultado do Programa:
inic: -1
fim: -1
indices: 0 1 2 3 4 5
Lista: -1 0 0 0 0 0
Valor: 10 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 4
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 0
Valor: 20 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 5
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 20
Valor: 5 <enter>
[I]nício ou [F]im ?i
inic: 3
fim: 5
indices: 0 1 2 3 4 5
Lista: 3 0 0 5 10 20
Valor: 0 <enter>
inic: 2
fim: 5
indices: 0 1 2 3 4 5
Lista: 2 0 0 5 10 20
6
0
7 8
0 -1
6
0
7
0
8
4
6
0
7
0
8
5
6
0
7
0
8
5
6
0
7
0
8
5
Programa exemplo (10a): O programa abaixo demonstra a inclusão de números inteiros no
início ou no fim de uma lista linear avisando qual lado está cheio. O programa possui
uma classe ListaLinear.
// ---------------------------------------------------------------- Fonte: Dados10a.java
package dados10a;
import java.util.Scanner;
public class Dados10a {
final static int SUCESSO = 0;
final static int LISTA_CHEIA_DIREITA = 1;
final static int LISTA_CHEIA_ESQUERDA = 2;
public static void main(String[] args) {
ListaLinear lista = new ListaLinear(7);
Scanner entrada = new Scanner (System.in);
int valor;
int erro = SUCESSO;
char ch = 'A';
49
do {
lista.exibeLista();
System.out.printf("\nValor: ");
s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
System.out.printf("[I]nício ou [F]im ?");
do {
s = entrada.nextLine();
ch = s.charAt(0);
} while (ch != 'I' && ch != 'i' && ch != 'F' && ch != 'f');
}
switch (ch) {
case 'I':
case 'i': erro = lista.incluiInicio(valor);
break;
case 'F':
case 'f': erro = lista.incluiFim(valor);
break;
}
if (erro != SUCESSO) {
lista.imprimeErro(erro);
}
} while (valor != 0);
lista.exibeLista();
}
}
// ---------------------------------------------------------------- Fonte: ListaLinear.java
package dados10a;
public class ListaLinear {
private final int [] v;
final static int SUCESSO = 0;
final static int LISTA_CHEIA_DIREITA = 1;
final static int LISTA_CHEIA_ESQUERDA = 2;
// ---------------------------------------------- construtor
public ListaLinear(int numElementos) {
v = new int[numElementos + 2];
// v[0] = inic e v[m] = fim
int inic = 0;
int fim = v.length - 1;
v[inic] = -1;
v[fim] = -1;
}
// ---------------------------------------------- incluiInicio
public int incluiInicio(int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (inic == -1) {
inic = metade;
50
fim = inic;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (inic == 1) {
return(LISTA_CHEIA_ESQUERDA);
}
else {
inic--;
v[inic] = dado;
v[0] = inic;
return(SUCESSO);
}
}
}
// ---------------------------------------------- incluiFim
public int incluiFim(int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (fim == -1) {
inic = metade;
fim = inic;
v[fim] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (fim == m) {
return(LISTA_CHEIA_DIREITA);
}
else {
fim++;
v[fim] = dado;
v[v.length - 1] = fim;
return(SUCESSO);
}
}
}
// ---------------------------------------------- imprimeErro
public void imprimeErro(int erro) {
switch (erro) {
case LISTA_CHEIA_ESQUERDA: System.out.println("ERRO: Lista Cheia à Esquerda");
break;
case LISTA_CHEIA_DIREITA: System.out.println("ERRO: Lista Cheia à Direita");
break;
}
}
51
// ---------------------------------------------- exibeLista
public void exibeLista() {
int inic = v[0];
int fim = v[v.length - 1];
System.out.println("inic: " + inic);
System.out.println(" fim: " + fim);
System.out.printf("indices: ");
for (int i = 0;i < v.length;i++) {
System.out.printf("%2d ",i);
}
System.out.println();
System.out.printf(" Lista: ");
for (int i = 0;i < v.length;i++) {
System.out.printf("%2d ",v[i]);
}
}
}
Resultado do Programa:
inic: -1
fim: -1
indices: 0 1 2 3 4 5
Lista: -1 0 0 0 0 0
Valor: 10 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 4
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 0
Valor: 20 <enter>
[I]nício ou [F]im ?f <enter>
inic: 4
fim: 5
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 20
Valor: 5 <enter>
[I]nício ou [F]im ?i <enter>
inic: 3
fim: 5
indices: 0 1 2 3 4 5
Lista: 3 0 0 5 10 20
Valor: 0 <enter>
inic: 2
fim: 5
indices: 0 1 2 3 4 5
Lista: 2 0 0 5 10 20
6
0
7 8
0 -1
6
0
7
0
8
4
6
0
7
0
8
5
6
0
7
0
8
5
6
0
7
0
8
5
Problema: Escreva um programa em Java que permite a inclusão de números inteiros em uma
lista linear no início, fim e na posição escolhida pelo usuário
Programa exemplo (11): O programa abaixo demonstra a inclusão de números inteiros no
início, na posição ou no fim de uma lista linear.
// --------------------------------------------------- Fonte: Dados11.java
52
package dados11;
import java.util.Scanner;
public class Dados11 {
final
final
final
final
static
static
static
static
int
int
int
int
SUCESSO = 0;
LISTA_CHEIA = 1;
LISTA_VAZIA = 2;
POSICAO_INVALIDA = 3;
public static void main(String[] args) {
Scanner entrada = new Scanner (System.in);
final int m = 7;
int [] v = new int[m + 2];
// v[0] = inic e v[m] = fim
int valor, pos;
int erro = SUCESSO;
char ch = 'A';
criaLista(v);
do {
exibeLista(v);
System.out.printf("\nValor: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
System.out.printf("[I]nício, [P]osição ou [F]im ?");
do {
s = entrada.nextLine();
ch = s.charAt(0);
} while (ch != 'I' && ch != 'i' &&
ch != 'P' && ch != 'p' && ch != 'F' && ch != 'f');
}
switch (ch) {
case 'I':
case 'i': erro = incluiInicio(v, valor);
break;
case 'F':
case 'f': erro = incluiFim(v, valor);
break;
case 'P':
case 'p': System.out.printf("Posição: ");
s = entrada.nextLine();
pos = Integer.parseInt(s);
erro = incluiPosicao(v, valor, pos);
break;
}
if (erro != SUCESSO) {
imprimeErro(erro);
}
} while (valor != 0);
exibeLista(v);
}
// ---------------------------------------------- criaLista
static void criaLista(int []v) {
int inic = 0;
53
int fim = v.length - 1;
v[inic] = -1;
v[fim] = -1;
}
// ---------------------------------------------- incluiInicio
static int incluiInicio(int [] v, int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (inic == -1) {
inic = metade;
fim = inic;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (inic == 1) {
return(LISTA_CHEIA);
}
else {
inic--;
v[inic] = dado;
v[0] = inic;
return(SUCESSO);
}
}
}
// ---------------------------------------------- incluiFim
static int incluiFim(int [] v, int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (fim == -1) {
inic = metade;
fim = inic;
v[fim] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (fim == m) {
return(LISTA_CHEIA);
}
else {
fim++;
v[fim] = dado;
v[v.length - 1] = fim;
54
return(SUCESSO);
}
}
}
// ---------------------------------------------- incluiPosicao
static int incluiPosicao(int [] v, int dado, int pos) {
int erro;
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
if (pos < inic || pos > fim) {
return(POSICAO_INVALIDA);
}
if (inic == -1) {
inic = pos;
fim = pos;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (inic == 0 && fim == m - 1) {
return(LISTA_CHEIA);
}
else {
if (pos == inic - 1) {
erro = incluiInicio(v, dado);
return(erro);
}
else {
if (pos == fim + 1) {
erro = incluiFim(v, dado);
return(erro);
}
else {
for (int i = fim;i >= pos;i--) {
v[i+1] = v[i];
}
v[pos] = dado;
fim++;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
}
}
}
}
// ---------------------------------------------- imprimeErro
static void imprimeErro(int erro) {
switch (erro) {
case LISTA_CHEIA: System.out.println("ERRO: Lista Cheia");
break;
55
case LISTA_VAZIA: System.out.println("ERRO: Lista Vazia");
break;
case POSICAO_INVALIDA: System.out.println("ERRO: Posição Inválida");
break;
}
}
// ---------------------------------------------- exibeLista
static void exibeLista(int [] v) {
int inic = v[0];
int fim = v[v.length - 1];
System.out.println("inic: " + inic);
System.out.println(" fim: " + fim);
System.out.printf("indices: ");
for (int i = 0;i < v.length;i++) {
System.out.printf("%2d ",i);
}
System.out.println();
System.out.printf(" Lista: ");
for (int i = 0;i < v.length;i++) {
System.out.printf("%2d ",v[i]);
}
}
}
Resultado do Programa:
inic: -1
fim: -1
indices: 0 1 2 3 4 5
Lista: -1 0 0 0 0 0
Valor: 10 <enter>
[I]nício, [P]osicao ou [F]im
inic: 4
fim: 4
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 0
Valor: 20 <enter>
[I]nício, [P]osicao ou [F]im
inic: 4
fim: 5
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 20
Valor: 5 <enter>
[I]nício, [P]osicao ou [F]im
inic: 3
fim: 5
indices: 0 1 2 3 4 5
Lista: 3 0 0 5 10 20
Valor: 0 <enter>
inic: 2
fim: 5
indices: 0 1 2 3 4 5
Lista: 2 0 0 5 10 20
6
0
7 8
0 -1
?f <enter>
6
0
7
0
8
4
?f <enter>
6
0
7
0
8
5
?i <enter>
6
0
7
0
8
5
6
0
7
0
8
5
56
Programa exemplo (11a): O programa abaixo demonstra a inclusão de números inteiros no
início, na posição ou no fim de uma lista linear. O programa possui uma classe
ListaLinear.
// ------------------------------------------------------------------- Fonte: Dados11a.java
package dados11a;
import java.util.Scanner;
public class Dados11a {
final
final
final
final
static
static
static
static
int
int
int
int
SUCESSO = 0;
LISTA_CHEIA = 1;
LISTA_VAZIA = 2;
POSICAO_INVALIDA = 3;
public static void main(String[] args) {
ListaLinear lista = new ListaLinear(7);
Scanner entrada = new Scanner (System.in);
int valor, pos;
int erro = SUCESSO;
char ch = 'A';
do {
lista.exibeLista();
System.out.printf("\nValor: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
System.out.printf("[I]nício, [P]osição ou [F]im ?");
do {
s = entrada.nextLine();
ch = s.charAt(0);
} while (!strChr("IiPpFf", ch));
}
switch (ch) {
case 'I':
case 'i': erro = lista.incluiInicio(valor);
break;
case 'F':
case 'f': erro = lista.incluiFim(valor);
break;
case 'P':
case 'p': System.out.printf("Posição: ");
s = entrada.nextLine();
pos = Integer.parseInt(s);
erro = lista.incluiPosicao(valor, pos);
break;
}
if (erro != SUCESSO) {
lista.imprimeErro(erro);
}
} while (valor != 0);
lista.exibeLista();
}
// ----------------------------------------------- strChr
57
static boolean strChr(String s, char ch) {
int n = s.length();
for (int i = 0;i < n;i++) {
if (s.charAt(i) == ch) {
return(true);
}
}
return(false);
}
}
// ---------------------------------------------------------------- ListaLinear.java
package dados11a;
public class ListaLinear {
private final int [] v;
final static int SUCESSO = 0;
final static int LISTA_CHEIA = 1;
final static int LISTA_VAZIA = 2;
final static int POSICAO_INVALIDA = 3;
// --------------------------------------------- construtor
public ListaLinear(int numElementos) {
v = new int[numElementos + 2];
// v[0] = inic e v[m] = fim
int inic = 0;
int fim = v.length - 1;
v[inic] = -1;
v[fim] = -1;
}
// ---------------------------------------------- incluiInicio
public int incluiInicio(int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (inic == -1) {
inic = metade;
fim = inic;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (inic == 1) {
return(LISTA_CHEIA);
}
else {
inic--;
v[inic] = dado;
v[0] = inic;
return(SUCESSO);
58
}
}
}
// ---------------------------------------------- incluiFim
public int incluiFim(int dado) {
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
int metade = (m / 2) + 1;
if (fim == -1) {
inic = metade;
fim = inic;
v[fim] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (fim == m) {
return(LISTA_CHEIA);
}
else {
fim++;
v[fim] = dado;
v[v.length - 1] = fim;
return(SUCESSO);
}
}
}
// ---------------------------------------------- incluiPosicao
public int incluiPosicao(int dado, int pos) {
int erro;
int inic = v[0];
int fim = v[v.length - 1];
int m = v.length - 2;
if (pos < inic || pos > fim) {
return(POSICAO_INVALIDA);
}
if (inic == -1) {
inic = pos;
fim = pos;
v[inic] = dado;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
else {
if (inic == 0 && fim == m - 1) {
return(LISTA_CHEIA);
}
else {
if (pos == inic - 1) {
erro = incluiInicio(dado);
59
return(erro);
}
else {
if (pos == fim + 1) {
erro = incluiFim(dado);
return(erro);
}
else {
for (int i = fim;i >= pos;i--) {
v[i+1] = v[i];
}
v[pos] = dado;
fim++;
v[0] = inic;
v[v.length - 1] = fim;
return(SUCESSO);
}
}
}
}
}
// ---------------------------------------------- imprimeErro
public void imprimeErro(int erro) {
switch (erro) {
case LISTA_CHEIA: System.out.println("ERRO: Lista Cheia");
break;
case LISTA_VAZIA: System.out.println("ERRO: Lista Vazia");
break;
case POSICAO_INVALIDA: System.out.println("ERRO: Posição Inválida");
break;
}
}
// ---------------------------------------------- exibeLista
public void exibeLista() {
int inic = v[0];
int fim = v[v.length - 1];
System.out.println("inic: " + inic);
System.out.println(" fim: " + fim);
System.out.printf("indices: ");
for (int i = 0;i < v.length;i++) {
System.out.printf("%2d ",i);
}
System.out.println();
System.out.printf(" Lista: ");
for (int i = 0;i < v.length;i++) {
System.out.printf("%2d ",v[i]);
}
}
}
Resultado do Programa:
inic: -1
60
fim: -1
indices: 0 1 2 3 4 5
Lista: -1 0 0 0 0 0
Valor: 10 <enter>
[I]nício, [P]osição ou [F]im
inic: 4
fim: 4
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 0
Valor: 20 <enter>
[I]nício, [P]osição ou [F]im
inic: 4
fim: 5
indices: 0 1 2 3 4 5
Lista: 4 0 0 0 10 20
Valor: 5 <enter>
[I]nício, [P]osição ou [F]im
inic: 3
fim: 5
indices: 0 1 2 3 4 5
Lista: 3 0 0 5 10 20
Valor: 0 <enter>
inic: 2
fim: 5
indices: 0 1 2 3 4 5
Lista: 2 0 0 5 10 20
6
0
7 8
0 -1
?f <enter>
6
0
7
0
8
4
?f <enter>
6
0
7
0
8
5
?i <enter>
6
0
7
0
8
5
6
0
7
0
8
5
Vantagens e Desvantagens da Representação por Contigüidade Física
Vantagens
A consulta pode ser calculada (acesso randômico aos dados);
Facilita a transferência de dados (área de memória contígua);
Adequada para o armazenamento de estruturas simples.
Desvantagens
O tamanho máximo da lista precisa ser conhecido e alocado anteci-padamente, pois
a lista é alocada estaticamente na memória;
Inserções e remoções podem exigir considerável movimentação de dados;
Inadequada para o armazenamento de estruturas complexas;
Mantém um espaço de memória ocioso (não ocupado);
Como a lista é limitada, devem ser testados os limites.
3.2.2 Lista representada por Encadeamento
Permite Alocação Dinâmica de Memória, ou seja, a lista cresce com a execução do
programa enquanto houver memória livre. Operações como inserção e remoção são mais
simples. Este tipo de estrutura se chama Lista Encadeada Simples ou Lista Encadeada.
A seguir será visto duas formas de implementar uma lista encadeada simples:
61
a) Usando uma classe existente no Java: LinkedList;
b) Usando classes definidas pelo programador: Nodo e ListaEncadeada.
Problema: Escrever um programa em Java que permite incluir números inteiros em uma
lista encadeada.
Programa exemplo (12): O programa abaixo demonstra a inclusão de números inteiros em
uma lista encadeada simples usando a classe LinkedList.
// ---------------------------------------------------- Fonte: Dados12.java
package dados12;
import java.util.LinkedList;
public class Dados12 {
public static void main(String[] args) {
LinkedList lista = new LinkedList();
Object primeiro = lista.add(10);
lista.add(20);
lista.add(30);
lista.add("Paulo");
lista.add('A');
lista.add(123.45f);
lista.add(1.23);
lista.add(null);
System.out.println("Lista: " + lista);
primeiro = lista.removeFirst();
while (primeiro != null) {
System.out.println("Nodo: " + primeiro);
primeiro = lista.removeFirst();
}
}
}
Resultado do Programa:
Lista: [10, 20, 30, Paulo, A, 123.45, 1.23, null]
Lista: [10, 20, 30, A, 123.45, 1.23, null]
Nodo: 10
Nodo: 20
Nodo: 30
Nodo: A
Nodo: 123.45
Nodo: 1.23
Programa exemplo (13): O programa abaixo demonstra a inclusão de números inteiros em
uma lista encadeada simples usando a classe LinkedList. Usuário informa os elementos
via teclado.
// --------------------------------------------------- Fonte: Dados13.java
package dados13;
62
import java.util.LinkedList;
import java.util.Scanner;
public class Dados13 {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
LinkedList lista = new LinkedList();
System.out.print("Nodo: ");
String s = entrada.nextLine();
int nodo = Integer.parseInt(s);
Object primeiro = lista.add(nodo);
do {
System.out.print("Nodo: ");
s = entrada.nextLine();
nodo = Integer.parseInt(s);
if (nodo != 0) {
lista.add(nodo);
}
} while (nodo != 0);
System.out.println("Lista: " + lista);
do {
primeiro = lista.removeFirst();
System.out.println("Nodo: " + primeiro);
} while (primeiro != null);
}
}
Resultado do Programa:
Nodo: 10 <enter>
Nodo: 20 <enter>
Nodo: 30 <enter>
Nodo: 40 <enter>
Nodo: 50 <enter>
Nodo: 0 <enter>
Lista: [10, 20, 30, 40, 50, null]
Nodo: 10
Nodo: 20
Nodo: 30
Nodo: 40
Nodo: 50
Nodo: null
Lista: []
63
Figura 9: Lista Encadeada Simples
Problema: Escrever um programa em Java que insere dados em uma lista encadeada,
permitindo obter o conteúdo do último elemento, imprimindo também, toda a lista.
Programa exemplo (14): O programa abaixo demonstra a inclusão de números inteiros em
uma lista encadeada simples usando as classes: Nodo e ListaEncadeada escritas pelo
programador.
// ------------------------------------------------ Fonte: Nodo.java
package dados14;
public class Nodo {
public int dado;
public Nodo elo = null;
}
// --------------------------------------------- Fonte: ListaEncadeada.java
package dados14;
public class ListaEncadeada {
private Nodo prim;
private int n;
private Nodo ult;
// ------------------------------- construtor
public ListaEncadeada() {
prim = null;
n = 0;
ult = null;
}
// ------------------------------- inserirLista
public void inserirLista(int chave)
{
Nodo aux = new Nodo();
aux.dado = chave;
if (prim == null) {
prim = aux;
}
else {
ult.elo = aux;
}
n++;
ult = aux;
}
// ------------------------------- removerLista
public int removerLista() {
64
Nodo aux, tmp;
aux = tmp = prim;
if (aux != null) {
prim = aux.elo;
if (prim == null) {
ult = null;
}
n--;
return(tmp.dado);
}
else
return(0);
}
// ------------------------------- contaElementosLista
public int contaElementosLista() {
return(n);
}
// ------------------------------- imprimirLista
public void imprimirLista() {
Nodo aux = prim;
System.out.print("Lista Encadeada: [ ");
if (aux != null) {
while(aux != null) {
System.out.print(aux.dado + " ");
aux = aux.elo;
}
}
else {
System.out.print("Vazia");
}
System.out.println("]");
}
}
// --------------------------------------------------- Fonte: Dados14.java
package dados14;
import java.util.Scanner;
public class Dados14 {
public static void main(String[] args) {
ListaEncadeada lista = new ListaEncadeada();
Scanner entrada = new Scanner(System.in);
int dado;
do {
System.out.print("Dado: ");
String s = entrada.nextLine();
dado = Integer.parseInt(s);
if (dado != 0) {
lista.inserirLista(dado);
65
}
} while (dado != 0);
lista.imprimirLista();
int n = lista.contaElementosLista();
System.out.println("Total de Elementos: " + n);
dado = lista.removerLista();
while (dado != 0) {
System.out.println("Dado Removido: " + dado);
dado = lista.removerLista();
}
n = lista.contaElementosLista();
System.out.println("Total de Elementos: " + n);
lista.imprimirLista();
}
}
Resultado do Programa:
Dado: 10 <enter>
Dado: 20 <enter>
Dado: 30 <enter>
Dado: 40 <enter>
Dado: 50 <enter>
Dado: 0 <enter>
Lista Encadeada: [ 10 20 30 40 50 ]
Total de Elementos: 5
Dado Removido: 10
Dado Removido: 20
Dado Removido: 30
Dado Removido: 40
Dado Removido: 50
Total de Elementos: 0
Lista Encadeada: [ Vazia]
Figura 10: Lista Encadeada
66
Problema: Escrever um programa em Java que insere dados em uma lista encadeada
simples, permitindo obter o conteúdo do último elemento, imprimindo também, toda a
lista.
Programa exemplo (15): O programa abaixo demonstra a inclusão de números inteiros em
uma lista encadeada simples usando as classes: Nodo e ListaEncadeadaSimples.
// ----------------------------------------------------------- Fonte: Nodo.java
package dados15;
public class Nodo {
public int dado;
public Nodo elo = null;
}
// ----------------------------------------------- Fonte: ListaEncadeadaSimples.java
package dados15;
public class ListaEncadeadaSimples {
private Nodo primeiro = null;
// ------------------------------- inserirLista
public void inserirLista(int valor)
{
Nodo aux = new Nodo();
Nodo tmp;
aux.dado = valor;
if (primeiro == null) {
primeiro = aux;
}
else {
tmp = primeiro;
aux.elo = tmp;
primeiro = aux;
}
}
// ------------------------------- removerLista
public int removerLista() {
Nodo aux;
int dado;
aux = primeiro;
if (aux != null) {
dado = primeiro.dado;
primeiro = primeiro.elo;
return(dado);
}
else
67
return(0);
}
// ------------------------------- imprimirLista
public void imprimirLista() {
Nodo aux;
aux = primeiro;
System.out.print("Lista Encadeada Simples: ");
if (aux != null) {
while(aux != null) {
System.out.print(aux.dado + " ");
aux = aux.elo;
}
}
else {
System.out.print("Vazia");
}
System.out.println();
}
}
// -------------------------------------------- Fonte: Dados15.java
package dados15;
import java.util.Scanner;
public class Dados15 {
public static void main(String[] args) {
ListaEncadeadaSimples lista = new ListaEncadeadaSimples();
Scanner entrada = new Scanner(System.in);
int dado;
do {
System.out.print("Dado: ");
String s = entrada.nextLine();
dado = Integer.parseInt(s);
if (dado != 0) {
lista.inserirLista(dado);
}
} while (dado != 0);
lista.imprimirLista();
dado = lista.removerLista();
while (dado != 0) {
System.out.println("Dado Removido: " + dado);
dado = lista.removerLista();
}
}
}
Resultado do Programa:
68
Dado: 10 <enter>
Dado: 20 <enter>
Dado: 30 <enter>
Dado: 40 <enter>
Dado: 50 <enter>
Dado: 0 <enter>
Lista Encadeada Simples: 50 40 30 20 10
Dado Removido: 50
Dado Removido: 40
Dado Removido: 30
Dado Removido: 20
Dado Removido: 10
Problema: Escrever um programa em Java que permite incluir, excluir e consultar (no
início ou fim) dados inteiros em uma lista encadeada. Em cada operação imprimir a
lista.
Programa exemplo (16): O programa abaixo demonstra a inclusão, exclusão e consulta de
números inteiros em uma lista encadeada simples usando as classes: Nodo e
ListaEncadeadaSimples.
// --------------------------------------------- Fonte: Nodo.java
package dados16;
public class Nodo {
public int dado;
public Nodo elo = null;
}
// -------------------------------------------- Fonte: ListaEncadeadaSimples.java
package dados16;
public class ListaEncadeada {
private Nodo primeiro = null;
// ------------------------------- inserirLista
public void inserirLista(int valor)
{
Nodo aux = new Nodo();
Nodo tmp;
aux.dado = valor;
if (primeiro == null) {
primeiro = aux;
}
else {
tmp = primeiro;
aux.elo = tmp;
primeiro = aux;
}
}
// ------------------------------- removerLista
69
public int removerLista() {
Nodo aux;
int dado;
aux = primeiro;
if (aux != null) {
dado = primeiro.dado;
primeiro = primeiro.elo;
return(dado);
}
else
return(0);
}
// ------------------------------- consultarLista
public int consultarLista() {
Nodo aux;
aux = primeiro;
if (aux != null) {
return(primeiro.dado);
}
else
return(0);
}
// ------------------------------- imprimirLista
public void imprimirLista() {
Nodo aux;
aux = primeiro;
System.out.print("Lista Encadeada Simples: ");
if (aux != null) {
while(aux != null) {
System.out.print(aux.dado + " ");
aux = aux.elo;
}
}
else {
System.out.print("Vazia");
}
System.out.println();
}
}
// ------------------------------------------ Fonte: Dados16.java
package dados16;
import java.util.Scanner;
70
public class Dados16 {
public static void main(String[] args) {
ListaEncadeada lista = new ListaEncadeada();
Scanner entrada = new Scanner(System.in);
char op;
int dado = 0;
do {
System.out.print("[I]ncluir, [C]onsultar, [R]emover ou [F]im: ");
do {
String s = entrada.nextLine();
op = s.charAt(0);
op = Character.toLowerCase(op);
} while (op != 'i' && op != 'c' && op != 'r' && op != 'f');
switch (op) {
case 'i': System.out.print("Dado: ");
String s = entrada.nextLine();
dado = Integer.parseInt(s);
if (dado != 0) {
lista.inserirLista(dado);
}
break;
case 'c': dado = lista.consultarLista();
System.out.println("Dado Consultado: " + dado);
break;
case 'r': dado = lista.removerLista();
System.out.println("Dado Removido: " + dado);
break;
}
lista.imprimirLista();
} while (op != 'f');
}
}
Resultado do Programa:
[I]ncluir, [C]onsultar, [R]emover ou
Dado: 10 <enter>
Lista Encadeada Simples: 10
[I]ncluir, [C]onsultar, [R]emover ou
Dado: 20 <enter>
Lista Encadeada Simples: 20 10
[I]ncluir, [C]onsultar, [R]emover ou
Dado: 30 <enter>
Lista Encadeada Simples: 30 20 10
[I]ncluir, [C]onsultar, [R]emover ou
Dado Consultado: 30 <enter>
Lista Encadeada Simples: 30 20 10
[I]ncluir, [C]onsultar, [R]emover ou
Dado Removido: 30
Lista Encadeada Simples: 20 10
[I]ncluir, [C]onsultar, [R]emover ou
Dado Removido: 20
Lista Encadeada Simples: 10
[I]ncluir, [C]onsultar, [R]emover ou
Dado Removido: 10
Lista Encadeada Simples: Vazia
[I]ncluir, [C]onsultar, [R]emover ou
[F]im: i <enter>
[F]im: i <enter>
[F]im: i <enter>
[F]im: c <enter>
[F]im: r <enter>
[F]im: r <enter>
[F]im: r <enter>
[F]im: f <enter>
71
Lista Encadeada Simples: Vazia
Vantagens das Listas representadas por Encadeamento
Lista cresce indeterminadamente, enquanto houver memória livre (Alocação
Dinâmica de Memória);
As operações de inserção e remoção de elementos não exige a movimentação dos
demais elementos.
Desvantagens das Listas representadas por Encadeamento
Determinar o número de elementos da lista, pois para tanto, deve-se percorrer
toda a lista;
Acessar diretamente um determinado elemento pela sua posição, pois só é
conhecido o primeiro elemento da lista;
Acessar o último elemento da lista, pois para acessá-lo, deve-se “visitar”
todos os intermediários.
3.2.3 Lista Encadeada com Descritor
Como foi visto anteriormente, as dificuldades da lista encadeada, é descobrir o
número de elementos e ainda, acessar o último elemento. Estas dificuldades podem ser
resolvidas utilizando-se um descritor, da seguinte forma:
Figura 11: Lista Encadeada com Descritor
Problema: Escrever o mesmo programa em Java que insere dados em uma lista encadeada com
descritor, permitindo obter o conteúdo do último elemento diretamente, imprimindo
também, toda a lista.
Programa exemplo (17): O programa abaixo demonstra a inclusão e consulta de números
inteiros (à esquerda e à direita) em uma lista encadeada simples com descritor usando
as classes: Nodo e ListaEncadeadaDescritor.
// ----------------------------------------------- Fonte: Nodo.java
package dados17;
72
public class Nodo {
public int dado;
public Nodo elo = null;
}
// ------------------------------------------------ Fonte: ListaEncadeadaDescritor.java
package dados17;
public class ListaEncadeadaDescritor {
private Nodo primeiro;
private int n;
private Nodo ultimo;
// ------------------------------- construtor
public ListaEncadeadaDescritor() {
primeiro = null;
n = 0;
ultimo = null;
}
// ------------------------------- inserirListaEsquerda
public void inserirListaEsquerda(int valor)
{
Nodo aux = new Nodo();
aux.dado = valor;
if (n == 0) {
primeiro = aux;
ultimo = aux;
aux.elo = null;
}
else {
aux.elo = primeiro;
primeiro = aux;
}
n++;
}
// ------------------------------- inserirListaDireita
public void inserirListaDireita(int valor)
{
Nodo aux = new Nodo();
Nodo tmp;
aux.dado = valor;
if (n == 0) {
primeiro = aux;
ultimo = aux;
}
else {
tmp = ultimo;
tmp.elo = aux;
aux.elo = null;
ultimo = aux;
73
}
n++;
}
// ------------------------------- consultarListaEsquerda
public int consultarListaEsquerda() {
Nodo aux;
aux = primeiro;
if (aux != null) {
return(primeiro.dado);
}
else
return(0);
}
// ------------------------------- consultarListaDireita
public int consultarListaDireita() {
Nodo aux;
int dado;
aux = ultimo;
if (aux != null) {
return(ultimo.dado);
}
else
return(0);
}
// ------------------------------- imprimirLista
public void imprimirLista() {
Nodo aux;
aux = primeiro;
System.out.print("Lista Encadeada Simples: ");
if (aux != null) {
while(aux != null) {
System.out.print(aux.dado + " ");
aux = aux.elo;
}
}
else {
System.out.print("Vazia");
}
System.out.println();
}
}
// -------------------------------------------------- Fonte: Dados17.java
package dados17;
74
import java.util.Scanner;
public class Dados17 {
public static void main(String[] args) {
ListaEncadeadaDescritor lista = new ListaEncadeadaDescritor();
Scanner entrada = new Scanner(System.in);
char op, ch = 'e';
int dado = 0;
do {
System.out.print("[I]ncluir, [C]onsultar ou [F]im: ");
do {
String s = entrada.nextLine();
op = s.charAt(0);
op = Character.toLowerCase(op);
} while (op != 'i' && op != 'c' && op != 'f');
if (op == 'i' || op == 'c') {
do {
System.out.print("[E]squerda ou [D]ireita: ");
String s = entrada.nextLine();
ch = s.charAt(0);
ch = Character.toLowerCase(ch);
} while (ch != 'e' && ch != 'd');
}
switch (op) {
case 'i': System.out.print("Dado: ");
String s = entrada.nextLine();
dado = Integer.parseInt(s);
if (dado != 0) {
if (ch == 'e') {
lista.inserirListaEsquerda(dado);
}
else {
lista.inserirListaDireita(dado);
}
}
break;
case 'c': if (ch == 'e') {
dado = lista.consultarListaEsquerda();
}
else {
dado = lista.consultarListaDireita();
}
System.out.println("Dado Consultado: " + dado);
break;
}
lista.imprimirLista();
} while (op != 'f');
}
}
Resultado do Programa:
[I]ncluir, [C]onsultar ou [F]im: i <enter>
[E]squerda ou [D]ireita: e <enter>
Dado: 10 <enter>
75
Lista Encadeada Simples: 10
[I]ncluir, [C]onsultar ou [F]im: i
[E]squerda ou [D]ireita: d <enter>
Dado: 20 <enter>
Lista Encadeada Simples: 10 20
[I]ncluir, [C]onsultar ou [F]im: i
[E]squerda ou [D]ireita: d <enter>
Dado: 30 <enter>
Lista Encadeada Simples: 10 20 30
[I]ncluir, [C]onsultar ou [F]im: c
[E]squerda ou [D]ireita: e <enter>
Dado Consultado: 10
Lista Encadeada Simples: 10 20 30
[I]ncluir, [C]onsultar ou [F]im: c
[E]squerda ou [D]ireita: d <enter>
Dado Consultado: 30
Lista Encadeada Simples: 10 20 30
[I]ncluir, [C]onsultar ou [F]im: f
Lista Encadeada Simples: 10 20 30
<enter>
<enter>
<enter>
<enter>
<enter>
Problema: Escrever um programa em Java que permite incluir, excluir e consultar (no
início ou fim) dados inteiros em uma lista encadeada. Em cada operação imprimir a
lista.
Programa exemplo (18): O programa abaixo demonstra a inclusão, remoção e consulta de
números inteiros (à esquerda e à direita) em uma lista encadeada simples com descritor
usando as classes: Nodo e ListaEncadeadaDescritor.
// ------------------------------------------------------ Fonte: Nodo.java
package dados18;
public class Nodo {
public int dado;
public Nodo elo = null;
}
// ------------------------------------------------------ Fonte: Dados18.java
package dados18;
public class ListaEncadeadaDescritor {
private Nodo primeiro;
private int n;
private Nodo ultimo;
// ------------------------------- construtor
public ListaEncadeadaDescritor() {
primeiro = null;
n = 0;
ultimo = null;
}
// ------------------------------- inserirListaEsquerda
76
public void inserirListaEsquerda(int valor)
{
Nodo aux = new Nodo();
aux.dado = valor;
if (n == 0) {
primeiro = aux;
ultimo = aux;
aux.elo = null;
}
else {
aux.elo = primeiro;
primeiro = aux;
}
n++;
}
// ------------------------------- inserirListaDireita
public void inserirListaDireita(int valor)
{
Nodo aux = new Nodo();
Nodo tmp;
aux.dado = valor;
if (n == 0) {
primeiro = aux;
ultimo = aux;
}
else {
tmp = ultimo;
tmp.elo = aux;
aux.elo = null;
ultimo = aux;
}
n++;
}
// ------------------------------- removerListaEsquerda
public int removerListaEsquerda() {
Nodo aux = primeiro;
int dado;
if (n == 0) {
return(0);
}
else {
dado = aux.dado;
primeiro = aux.elo;
n--;
return(dado);
}
}
// ------------------------------- removerListaDireita
public int removerListaDireita() {
77
Nodo tmp, ant = primeiro, aux = ultimo;
int dado;
if (n == 0) {
return(0);
}
else {
dado = aux.dado;
n--;
tmp = primeiro;
while (tmp.elo != null) {
ant = tmp;
tmp = tmp.elo;
}
ant.elo = null;
ultimo = ant;
return(dado);
}
}
// ------------------------------- consultarListaEsquerda
public int consultarListaEsquerda() {
Nodo aux;
aux = primeiro;
if (aux != null) {
return(primeiro.dado);
}
else
return(0);
}
// ------------------------------- consultarListaDireita
public int consultarListaDireita() {
Nodo aux;
aux = ultimo;
if (aux != null) {
return(ultimo.dado);
}
else
return(0);
}
// ------------------------------- imprimirLista
public void imprimirLista() {
Nodo aux;
aux = primeiro;
System.out.print("Lista Encadeada Simples: ");
if (aux != null) {
78
while(aux != null) {
System.out.print(aux.dado + " ");
aux = aux.elo;
}
}
else {
System.out.print("Vazia");
}
System.out.println();
}
}
// -------------------------------------------------------- Fonte: Dados18.java
package dados18;
import java.util.Scanner;
public class Dados18 {
public static void main(String[] args) {
ListaEncadeadaDescritor lista = new ListaEncadeadaDescritor();
Scanner entrada = new Scanner(System.in);
char op, ch = 'e';
int dado = 0;
do {
System.out.print("[I]ncluir, [C]onsultar, [R]emover ou [F]im: ");
do {
String s = entrada.nextLine();
op = s.charAt(0);
op = Character.toLowerCase(op);
} while (op != 'i' && op != 'c' && op != 'r' && op != 'f');
if (op == 'i' || op == 'r' || op == 'c') {
do {
System.out.print("[E]squerda ou [D]ireita: ");
String s = entrada.nextLine();
ch = s.charAt(0);
ch = Character.toLowerCase(ch);
} while (ch != 'e' && ch != 'd');
}
switch (op) {
case 'i': System.out.print("Dado: ");
String s = entrada.nextLine();
dado = Integer.parseInt(s);
if (dado != 0) {
if (ch == 'e') {
lista.inserirListaEsquerda(dado);
}
else {
lista.inserirListaDireita(dado);
}
}
break;
case 'r': if (ch == 'e') {
dado = lista.removerListaEsquerda();
}
else {
79
dado = lista.removerListaDireita();
}
if (dado != 0) {
System.out.println("Nodo Removido: " + dado);
}
else {
System.out.println("Status: Lista Vazia");
}
break;
case 'c': if (ch == 'e') {
dado = lista.consultarListaEsquerda();
}
else {
dado = lista.consultarListaDireita();
}
System.out.println("Dado Consultado: " + dado);
break;
}
lista.imprimirLista();
} while (op != 'f');
}
}
Resultado do Programa:
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: e <enter>
Dado: 10 <enter>
Lista Encadeada Simples: 10
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: d <enter>
Dado: 20 <enter>
Lista Encadeada Simples: 10 20
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: d <enter>
Dado: 30 <enter>
Lista Encadeada Simples: 10 20 30
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: e <enter>
Dado Consultado: 10
Lista Encadeada Simples: 10 20 30
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: d <enter>
Dado Consultado: 30
Lista Encadeada Simples: 10 20 30
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: e <enter>
Nodo Removido: 10
Lista Encadeada Simples: 20 30
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: d <enter>
Nodo Removido: 30
Lista Encadeada Simples: 20
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: e <enter>
Nodo Removido: 20
Lista Encadeada Simples: Vazia
[I]ncluir, [C]onsultar, [R]emover ou
[E]squerda ou [D]ireita: d <enter>
[F]im: i <enter>
[F]im: i <enter>
[F]im: i <enter>
[F]im: c <enter>
[F]im: c <enter>
[F]im: r <enter>
[F]im: r <enter>
[F]im: r <enter>
[F]im: r <enter>
80
Status: Lista Vazia
Lista Encadeada Simples: Vazia
[I]ncluir, [C]onsultar, [R]emover ou [F]im: f <enter>
Lista Encadeada Simples: Vazia
3.2.4 Lista Duplamente Encadeada
Na lista duplamente encadeada, cada elemento possui um elo para o anterior
(antecessor) e o posterior (sucessor), sendo que a lista pode ter ou não descritor.
Problema: Escrever um programa em Java que insere dados em uma lista duplamente
encadeada com descritor.
Programa exemplo (19): O programa abaixo demonstra a inclusão e exibição de números
inteiros (à esquerda e à direita) em uma lista duplamente encadeada com descritor
usando as classes: Nodo e ListaDuplaEncadeadaDescritor.
Figura 10a: Lista Duplamente Encadeada
// ----------------------------------------------------------- Fonte: Nodo.java
package dados19;
public class Nodo {
public Nodo anterior = null;
public int dado;
public Nodo posterior = null;
}
// ------------------------------------------------ Fonte: ListaDuplaEncadeadaDescritor.java
package dados19;
public class ListaDuplaEncadeadaDescritor {
private Nodo primeiro;
private int n;
private Nodo ultimo;
// ------------------------------- construtor
public ListaDuplaEncadeadaDescritor() {
primeiro = null;
n = 0;
ultimo = null;
}
81
// ------------------------------- inserirListaEsquerda
public void inserirListaEsquerda(int valor)
{
Nodo aux = new Nodo();
aux.dado = valor;
if (n == 0) {
primeiro = aux;
ultimo = aux;
aux.anterior = null;
}
else {
aux.anterior = primeiro;
primeiro = aux;
}
n++;
}
// ------------------------------- inserirListaDireita
public void inserirListaDireita(int valor)
{
Nodo aux = new Nodo();
Nodo tmp;
aux.dado = valor;
if (n == 0) {
primeiro = aux;
ultimo = aux;
}
else {
tmp = ultimo;
tmp.posterior = aux;
aux.anterior = tmp;
aux.posterior = null;
ultimo = aux;
}
n++;
}
// ------------------------------- removerListaEsquerda
public int removerListaEsquerda() {
Nodo aux = primeiro;
int dado;
if (n == 0) {
return(0);
}
else {
dado = aux.dado;
n--;
if (n == 0) {
primeiro = null;
ultimo = null;
}
else {
82
primeiro = aux.posterior;
primeiro.anterior = null;
}
return(dado);
}
}
// ------------------------------- removerListaDireita
public int removerListaDireita() {
Nodo ant, aux = ultimo;
int dado;
if (n == 0) {
return(0);
}
else {
dado = aux.dado;
n--;
if (n == 0) {
primeiro = null;
ultimo = null;
}
else {
ant = aux.anterior;
ultimo = ant;
ant.posterior = null;
}
return(dado);
}
}
// ------------------------------- consultarListaEsquerda
public int consultarListaEsquerda() {
Nodo aux;
int dado;
aux = primeiro;
if (aux != null) {
return(primeiro.dado);
}
else
return(0);
}
// ------------------------------- consultarListaDireita
public int consultarListaDireita() {
Nodo aux;
int dado;
aux = ultimo;
if (aux != null) {
return(ultimo.dado);
83
}
else
return(0);
}
// ------------------------------- imprimirLista
public void imprimirLista() {
Nodo aux = primeiro;
System.out.print("Lista Duplamente Encadeada: ");
if (aux != null) {
while(aux != null) {
System.out.print(aux.dado + " ");
aux = aux.posterior;
}
}
else {
System.out.print("Vazia");
}
System.out.println();
}
}
// --------------------------------------------------------- Fonte: Dados19.java
package dados19;
import java.util.Scanner;
public class Dados19 {
public static void main(String[] args) {
ListaDuplaEncadeadaDescritor lista = new ListaDuplaEncadeadaDescritor();
Scanner entrada = new Scanner(System.in);
char op, ch = 'e';
int dado = 0;
do {
System.out.print("[I]ncluir, [C]onsultar, [R]emover ou [F]im: ");
do {
String s = entrada.nextLine();
op = s.charAt(0);
op = Character.toLowerCase(op);
} while (op != 'i' && op != 'c' && op != 'r' && op != 'f');
if (op == 'i' || op == 'r' || op == 'c') {
do {
System.out.print("[E]squerda ou [D]ireita: ");
String s = entrada.nextLine();
ch = s.charAt(0);
ch = Character.toLowerCase(ch);
} while (ch != 'e' && ch != 'd');
}
switch (op) {
case 'i': System.out.print("Dado: ");
String s = entrada.nextLine();
dado = Integer.parseInt(s);
if (dado != 0) {
84
if (ch == 'e') {
lista.inserirListaEsquerda(dado);
}
else {
lista.inserirListaDireita(dado);
}
}
break;
case 'r': if (ch == 'e') {
dado = lista.removerListaEsquerda();
}
else {
dado = lista.removerListaDireita();
}
if (dado != 0) {
System.out.println("Nodo Removido: " + dado);
}
else {
System.out.println("Status: Lista Vazia");
}
break;
case 'c': if (ch == 'e') {
dado = lista.consultarListaEsquerda();
}
else {
dado = lista.consultarListaDireita();
}
System.out.println("Dado Consultado: " + dado);
break;
}
lista.imprimirLista();
} while (op != 'f');
}
}
Resultado do Programa:
[I]ncluir, [C]onsultar, [R]emover ou [F]im:
[E]squerda ou [D]ireita: e <enter>
Dado: 10 <enter>
Lista Duplamente Encadeada: 10
[I]ncluir, [C]onsultar, [R]emover ou [F]im:
[E]squerda ou [D]ireita: d <enter>
Dado: 20 <enter>
Lista Duplamente Encadeada: 10 20
[I]ncluir, [C]onsultar, [R]emover ou [F]im:
[E]squerda ou [D]ireita: d <enter>
Dado: 30 <enter>
Lista Duplamente Encadeada: 10 20 30
[I]ncluir, [C]onsultar, [R]emover ou [F]im:
[E]squerda ou [D]ireita: e <enter>
Dado Consultado: 10
Lista Duplamente Encadeada: 10 20 30
[I]ncluir, [C]onsultar, [R]emover ou [F]im:
[E]squerda ou [D]ireita: d <enter>
Dado Consultado: 30
Lista Duplamente Encadeada: 10 20 30
[I]ncluir, [C]onsultar, [R]emover ou [F]im:
[E]squerda ou [D]ireita: e <enter>
i <enter>
i <enter>
i <enter>
c <enter>
c <enter>
r <enter>
85
Nodo Removido: 10
Lista Duplamente Encadeada: 20 30
[I]ncluir, [C]onsultar, [R]emover ou [F]im: r <enter>
[E]squerda ou [D]ireita: d <enter>
Nodo Removido: 30
Lista Duplamente Encadeada: 20
[I]ncluir, [C]onsultar, [R]emover ou [F]im: r <enter>
[E]squerda ou [D]ireita: d <enter>
Nodo Removido: 20
Lista Duplamente Encadeada: Vazia
[I]ncluir, [C]onsultar, [R]emover ou [F]im: f <enter>
86
a) Preencha os campos de elo com os valores adequados para que seja representada a
seqüência (A, B, C, D): (sem descritor)
Preencha os campos de elo com os valores adequados para que seja representada a
seqüência (A, B, C, D, E, F): (com descritor)
87
Vantagens e Desvantagens das Listas Duplamente Encadeadas
Vantagens
Inserção e remoção de componentes sem movimentar os demais;
Pode-se ter qualquer quantidade de elementos, limitado pela memória livre, pois
cada elemento é alocado dinamicamente.
Desvantagens
Gerência de memória mais onerosa, alocação / desalocação para cada elemento;
Procedimentos mais complexos;
Processamento serial (Acesso Seqüencial).
3.2.5 Listas Lineares com Disciplina de Acesso
São tipos especiais de Listas Lineares, onde inserção, consulta e exclusão são
feitas somente nos extremos. Estas listas lineares com disciplina de acesso são: Filas,
Pilhas e Deques.
3.2.5.1 Filas
É uma Lista Linear na qual as inserções são feitas no fim e as exclusões e
consultas no início da fila.
Início
Fim
Figura 12: Fila
Critério de Utilização
FIFO - "First In First Out" (primeiro a entrar é o primeiro a sair)
Operações sobre Filas
criaFila();
insereFila(i);
erro = excluiFila ();
dado = consultaFila ();
Cria FILA Vazia
Insere o dado "i" no fim da FILA
Exclui da FILA o primeiro elemento
Copia em "j" primeiro elemento FILA
Erros nas operações sobre Filas: FILA_CHEIA ou FILA_VAZIA
88
Figura 12: Fila Circular
Problema: Escrever um programa em Java que insere, exclui e consulta dados (números
inteiros) em uma fila.
Programa exemplo (20): O programa abaixo demonstra a inclusão, exclusão e consulta de
números inteiros em uma Fila usando as classes: Fila.
3.2.5.1.1 Fila com Vetor
A seguir é visto um programa que implementa uma Fila com “n” elementos
armazenados em um vetor.
// -------------------------------------------------------------- Fonte: Dados20.java
package dados20;
import java.util.Scanner;
public class Dados20 {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
Fila fila = new Fila(7);
int valor;
int erro = 0;
char ch;
do {
System.out.printf("[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? ");
do {
89
String s = entrada.nextLine();
ch = s.charAt(0);
ch = Character.toLowerCase(ch);
} while (ch != 'i' && ch != 'e' && ch != 'c' && ch != 'f');
switch (ch)
{
case 'i': System.out.printf("Valor: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
erro = fila.insereFila(valor);
break;
case 'e': valor = fila.excluiFila();
break;
case 'c': valor = fila.consultaFila();
if (valor != 0) {
System.out.println("Primeiro da Fila: " + valor);
}
else {
System.out.println("ERRO: Fila Vazia");
}
break;
}
fila.exibeFila();
if (erro != 0)
fila.imprimeErro(erro);
} while (ch != 'f');
}
}
// -------------------------------------------------------------- Fonte: Fila.java
package dados20;
public class Fila {
final int SUCESSO = 0;
final int FILA_CHEIA = 1;
final int FILA_VAZIA = 2;
private int primeiro;
private int ultimo;
private int []elem;
// ------------------------------------ Construtor
public Fila(int numElementos) {
elem = new int[numElementos];
primeiro = 0;
ultimo = -1;
}
// ------------------------------------ insereFila
public int insereFila(int dado) {
int m = elem.length;
if (ultimo == m - 1) {
return(FILA_CHEIA);
}
else {
ultimo++;
90
elem[ultimo] = dado;
return(SUCESSO);
}
}
// -------------------------------- excluiFila
public int excluiFila() {
if (ultimo == -1) {
return(FILA_VAZIA);
}
else {
System.out.println("Dado Excluido: " + elem[primeiro]);
primeiro++;
if (primeiro > ultimo) {
primeiro = 0;
ultimo = -1;
}
return(SUCESSO);
}
}
// ------------------------------- consultaFila
public int consultaFila() {
if (ultimo == -1) {
return(0);
}
else {
return(elem[primeiro]);
}
}
// ------------------------------- exibeFila
public void exibeFila() {
System.out.print("Fila: ");
if (ultimo != -1) {
for (int i = primeiro;i <= ultimo; i++) {
System.out.print(elem[i] + " ");
}
System.out.println();
}
}
// ------------------------------------------ imprimeErroCircular
public void imprimeErro(int erro) {
switch (erro) {
case FILA_CHEIA: System.out.println("ERRO: Fila Cheia");
break;
case FILA_VAZIA: System.out.println("ERRO: Fila Vazia");
break;
}
}
}
Resultado do Programa:
91
[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? i <enter>
Valor: 10 <enter>
Fila: 10
[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? i <enter>
Valor: 20 <enter>
Fila: 10 20
[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? i <enter>
Valor: 30 <enter>
Fila: 10 20 30
[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? e <enter>
Dado Excluido: 10
Fila: 20 30
[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? e <enter>
Dado Excluido: 20
Fila: 30
[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? e <enter>
Dado Excluido: 30
Fila: [I]ncluir, [E]xcluir, [C]onsultar ou [F]im? c <enter>
ERRO: Fila Vazia
Fila: [I]ncluir, [E]xcluir, [C]onsultar ou [F]im? f <enter>
92
Exemplo: Fila Vazia
Inclusão de: 3, 5, 4, 7, 8 e 6
Exclusão dos três primeiros elementos: 3, 5 e 4
Problema com Filas:
A reutilização de uma fila depois que alguns elementos foram são inseridos e/ou
extraídos é um problema, pois ela pode estar deslocada toda para a direita, ou seja,
podem haver vagas no início da fila (vetor), mas não há no fim. Existem duas
alternativas viavéis para solucionar este problema: (a) utilizar uma Fila Circular,
onde a posição da inserção, remoção ou consulta é calculada de forma que a fila seja
inserida na posição válida no vetor ou (b) deslocar os elementos do fim da fila para o
início da fila.
3.2.5.1.2 Fila Circular
A seguir é demonstrado a estrutura de uma Fila Circular armazenada em um vetor
(Status: Fila Circular vazia).
Figura 13: Fila Circular em um vetor
93
Problema: Escrever um programa em Java que insere, exclui e consulta dados (números
inteiros) em uma fila circular.
Programa exemplo (21): O programa abaixo demonstra a inclusão, exclusão e consulta de
números inteiros em uma Fila Circular usando a classe: FilaCircular.
// -------------------------------------------------- Fonte: Dados21.java
package dados21;
import javax.swing.*;
public class Dados21 {
public static void main(String[] args) {
FilaCircular fila = new FilaCircular(7);
String s;
int elemento = 0;
char op;
do {
fila.exibeFilaCircular();
do {
s = JOptionPane.showInputDialog("[I]nsere, [R]emove, [C]onsulta ou [F]im: ");
op = s.charAt(0);
} while ("IiRrCcFf".indexOf(op) == -1);
switch (op) { // int ou char
case 'I':
case 'i': s = JOptionPane.showInputDialog("Elemento: ");
elemento = Integer.parseInt(s);
fila.insereFilaCircular(elemento);
break;
case 'R':
case 'r': elemento = fila.removeFilaCircular();
if (elemento != -1) {
System.out.println("Primeiro Elemento da Fila: " + elemento);
}
break;
case 'C':
case 'c': elemento = fila.consultaFilaCircular();
if (elemento != -1) {
System.out.println("Primeiro Elemento da Fila: " + elemento);
}
break;
}
} while (op != 'F' && op != 'f');
}
}
// ------------------------------------------------------- classe: FilaCircular.java
package dados21;
public class FilaCircular {
private int [] v;
private int primeiro;
private int ultimo;
private int n;
94
// ---------------------------- construtor
public FilaCircular(int numElementos) {
v = new int[numElementos];
primeiro = 0;
ultimo = -1;
n = 0;
}
// ---------------------------- insereFilaCircular
public void insereFilaCircular(int elemento) {
int m = v.length;
if (n < m) {
ultimo = (ultimo + 1) % m;
v[ultimo] = elemento;
n++;
} else {
System.out.println("Status: Fila Circular Cheia");
}
}
// ---------------------------- removeFilaCircular
public int removeFilaCircular() {
int m = v.length;
int elemento;
if (n != 0) {
elemento = v[primeiro];
primeiro = (primeiro + 1) % m;
n--;
// Guilherme Tomaschewski Netto
if (n == 0) { // Guilherme Tomaschewski Netto
if (primeiro > ultimo) { // Guilherme Tomaschewski Netto
primeiro = 0;
ultimo = -1;
}
n--;
// Guilherme Tomaschewski Netto
return(elemento);
} else {
System.out.println("Status: Fila Circular Vazia");
return(-1);
}
//
//
}
// ---------------------------- consultaFilaCircular
public int consultaFilaCircular() {
int m = v.length;
int elemento;
if (ultimo != -1) {
int prim = (primeiro + 1) % m;
elemento = v[prim];
return(elemento);
} else {
System.out.println("Status: Fila Circular Vazia");
95
return(-1);
}
}
// ---------------------------- exibeFilaCircular
public void exibeFilaCircular() {
int m = v.length;
int t = primeiro;
System.out.print("Fila Circular: ");
for (int i = 1;i <= n;i++) {
System.out.print(v[t] + "(" + t + ") ");
t = (t + 1) % m;
}
if (ultimo == -1) {
System.out.print("Vazia");
}
System.out.println();
}
}
Resultado do Programa:
Fila Circular: Vazia
[I]nsere, [R]emove, [C]onsulta ou
Elemento: 10 <enter>
Fila Circular: 10(0)
[I]nsere, [R]emove, [C]onsulta ou
Elemento: 20 <enter>
Fila Circular: 10(0) 20(1)
[I]nsere, [R]emove, [C]onsulta ou
Elemento: 30 <enter>
Fila Circular: 10(0) 20(1) 30(2)
[I]nsere, [R]emove, [C]onsulta ou
Primeiro Elemento da Fila: 20
Fila Circular: 10(0) 20(1) 30(2)
[I]nsere, [R]emove, [C]onsulta ou
Primeiro Elemento da Fila: 10
Fila Circular: 20(1) 30(2)
[I]nsere, [R]emove, [C]onsulta ou
Primeiro Elemento da Fila: 20
Fila Circular: 30(2)
[I]nsere, [R]emove, [C]onsulta ou
Primeiro Elemento da Fila: 30
Fila Circular: Vazia
[I]nsere, [R]emove, [C]onsulta ou
[F]im: i <enter>
[F]im: i <enter>
[F]im: i <enter>
[F]im: c <enter>
[F]im: r <enter>
[F]im: r <enter>
[F]im: r <enter>
[F]im: f <enter>
Como calcular a nova posição:
ultimo = (ultimo + 1) % m;
// onde m é número máximo de elementos do vetor
96
Figura 14: Cálculo da nova Posição na Fila Circular
3.2.5.1.3 Deslocamento dos elementos do vetor
Uma segunda solução é deslocar toda a fila que encontra-se a direita do vetor,
inteiramente para o lado esquerdo do vetor (olhe o método deslocaFila).
Programa exemplo (21a): O programa abaixo demonstra a inclusão, exclusão e consulta de
números inteiros em uma Fila através do deslocamento dos elementos da Fila.
// ---------------------------------------------------------------- Fonte: Dados21a.java
package dados21a;
import javax.swing.*;
public class Dados21a {
public static void main(String[] args) {
Fila fila = new Fila(7);
String s;
int elemento = 0;
char op;
do {
fila.exibeFila();
do {
s=JOptionPane.showInputDialog("[I]nsere, [R]emove, [C]onsulta ou [F]im: ");
op = s.charAt(0);
} while ("IiRrCcFf".indexOf(op) == -1);
switch (op) { // int ou char
case 'I':
case 'i': s = JOptionPane.showInputDialog("Elemento: ");
elemento = Integer.parseInt(s);
fila.insereFila(elemento);
break;
case 'R':
case 'r': elemento = fila.removeFila();
if (elemento != -1) {
System.out.println("Primeiro Elemento da Fila: " + elemento);
}
break;
case 'C':
case 'c': elemento = fila.consultaFila();
if (elemento != -1) {
System.out.println("Primeiro Elemento da Fila: " + elemento);
}
97
break;
}
} while (op != 'F' && op != 'f');
}
}
// -------------------------------------------------------------------- Fonte: Fila.java
package dados21a;
public class Fila {
private int [] v;
private int primeiro;
private int ultimo;
private int n;
// ---------------------------- construtor
public Fila(int numElementos) {
v = new int[numElementos];
primeiro = 0;
ultimo = -1;
n = 0;
}
// ---------------------------- insereFila
public void insereFila(int elemento) {
int m = v.length;
if (ultimo < m-1) {
ultimo++;
v[ultimo] = elemento;
n++;
} else {
if (n < m) {
deslocaFila();
// deslocamento dos elementos do vetor
ultimo++;
v[ultimo] = elemento;
n++;
} else {
System.out.println("Status: Fila Cheia");
}
}
}
// ---------------------------- removeFila
public int removeFila() {
int elemento;
if (ultimo != -1) {
elemento = v[primeiro];
primeiro++;
n--;
if (n == 0) {
primeiro = 0;
ultimo = -1;
}
98
return(elemento);
} else {
System.out.println("Status: Fila Vazia");
return(-1);
}
}
// ---------------------------- consultaFila
public int consultaFila() {
int elemento;
if (ultimo != -1) {
elemento = v[primeiro];
return(elemento);
} else {
System.out.println("Status: Fila Vazia");
return(-1);
}
}
// ---------------------------- exibeFila
public void exibeFila() {
System.out.print("Fila: ");
for (int i = primeiro;i <= ultimo;i++) {
System.out.print(v[i] + "(" + i + ") ");
}
if (ultimo == -1) {
System.out.print("Vazia");
}
System.out.println();
}
// ---------------------------- deslocaFila
private
int
int
int
int
void deslocaFila() {
m = v.length;
deslocados = m - n;
mover = m - deslocados;
first = primeiro;
for (int i = 0;i < mover;i++) {
v[i] = v[first];
first++;
}
primeiro = 0;
ultimo = n - 1;
System.out.println("Status: Fila Deslocada");
}
}
Resultado do Programa: (saída no Terminal)
Fila: Vazia
Fila: 10(0)
Fila: 10(0) 20(1)
Fila: 10(0) 20(1) 30(2)
Primeiro Elemento da Fila: 10
99
Fila: 10(0) 20(1)
Primeiro Elemento
Fila: 20(1) 30(2)
Primeiro Elemento
Fila: 30(2)
Primeiro Elemento
Fila: Vazia
30(2)
da Fila: 10
da Fila: 20
da Fila: 30
3.2.5.1.4 Fila com Alocação Dinâmica
A seguir são descritas filas alocadas dinamicamente, ou seja, a fila cresce com
a necessidade do usuário, ou seja, enquanto houver memória livre disponível.
Figura 15: Fila com Alocação Dinâmica
Problema: Escrever um programa em Java que insere, exclui e consulta dados (números
inteiros) em uma fila alocada dinamicamente.
Programa exemplo (22): O programa abaixo demonstra a inclusão, exclusão e consulta de
números inteiros em uma Fila alocada dinamicamente usando as classes: Nodo e
FilaDinamica.
// ----------------------------------------------- Fonte: Nodo.java
package dados22;
public class Nodo {
public int dado;
public Nodo elo;
}
// ----------------------------------------------- Fonte: Dados22.java
package dados22;
public class FilaDinamica {
private Nodo primeiro;
private int tamanho;
private Nodo ultimo;
// ---------------------------------------------- Construtor
public FilaDinamica() {
100
primeiro = null;
tamanho = 0;
ultimo = null;
}
// ---------------------------------------------- inserirFilaDinamica
public void inserirFilaDinamica(int dado) {
Nodo t = new Nodo();
t.dado = dado;
t.elo = null;
tamanho = tamanho + 1;
if (ultimo != null) {
ultimo.elo = t;
}
ultimo = t;
if (primeiro == null) {
primeiro = t;
}
}
// ---------------------------------------------- excluirFilaDinamica
public int excluirFilaDinamica() {
Nodo t;
int dado;
if (primeiro == null) {
return(-1);
}
else {
t = primeiro;
dado = t.dado;
tamanho = tamanho - 1;
primeiro = t.elo;
if (primeiro == null) {
ultimo = null;
return(-1);
}
return(dado);
}
}
// ---------------------------------------------- consultarFilaDinalica
public int consultarFilaDinamica() {
if (primeiro == null) {
return(-1);
}
else {
return(primeiro.dado);
}
}
// ---------------------------------------------- exibirFilaDinalica
public void exibirFilaDinamica() {
Nodo t = primeiro;
101
System.out.print("Fila Dinamica: ");
if (primeiro == null) {
System.out.print("Vazia");
}
else {
while (t != null) {
System.out.print(t.dado + " ");
t = t.elo;
}
}
System.out.println();
}
}
// --------------------------------------------------------- Fonte: Dados22.java
package dados22;
import java.util.Scanner;
public class Dados22 {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
FilaDinamica fila = new FilaDinamica();
int valor, dado;
char tecla;
do {
fila.exibirFilaDinamica();
System.out.print("[I]ncluir, [E]xcluir, [C]onsultar ou [F]im? ");
do {
String s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 'i' && tecla != 'e' && tecla != 'c' && tecla != 'f');
switch (tecla) {
case 'i': System.out.print("Elemento: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
fila.inserirFilaDinamica(valor);
break;
case 'e': dado = fila.excluirFilaDinamica();
if (dado != -1) {
System.out.println("Elemento Excluído: " + dado);
}
break;
case 'c': dado = fila.consultarFilaDinamica();
if (dado != -1) {
System.out.println("Elemento Consultado: " + dado);
}
break;
}
} while (tecla != 'f');
}
}
Resultado do Programa:
102
Fila Dinamica: Vazia
[I]ncluir, [E]xcluir, [C]onsultar
Elemento: 10 <enter>
Fila Dinamica: 10
[I]ncluir, [E]xcluir, [C]onsultar
Elemento: 20 <enter>
Fila Dinamica: 10 20
[I]ncluir, [E]xcluir, [C]onsultar
Elemento: 30
Fila Dinamica: 10 20 30
[I]ncluir, [E]xcluir, [C]onsultar
Elemento Consultado: 10
Fila Dinamica: 10 20 30
[I]ncluir, [E]xcluir, [C]onsultar
Elemento Excluído: 10
Fila Dinamica: 20 30
[I]ncluir, [E]xcluir, [C]onsultar
Elemento Excluído: 20
Fila Dinamica: 30
[I]ncluir, [E]xcluir, [C]onsultar
Fila Dinamica: Vazia
[I]ncluir, [E]xcluir, [C]onsultar
ou [F]im? i <enter>
ou [F]im? i <enter>
ou [F]im? i <enter>
ou [F]im? c <enter>
ou [F]im? e <enter>
ou [F]im? e <enter>
ou [F]im? e <enter>
ou [F]im? f <enter>
3.2.5.2 Pilhas
É uma Lista Linear na qual as inserções, exclusões e consultas são feitas em um
mesmo extremo, chamado Topo.
Figura 16: Pilha
Critério de Utilização
LIFO - "Last In First Out" (último a entrar é o primeiro a sair)
Operações sobre Pilhas
criaPilha();
erro = push(i);
erro = pop();
erro = consultaPilha();
Cria pilha Vazia
Empilha o dado "i" no topo da Pilha
Desempilha o primeiro elemento
Exibe o primeiro elemento
Identificadores da Pilha
B(p)
Base da Pilha
103
T(p)
L(p)
Topo da Pilha
Limite da Pilha
3.2.5.2.1 Pilha com Vetor
A seguir é visto um programa que implementa uma Pilha com “n” elementos
armazenados em um vetor.
Figura 17: Pilha em um Vetor
Problema: Escreva um programa em Java que insere (push), exclui (pop) e consulta dados
(números inteiros) em uma Pilha alocada estaticamente.
Programa exemplo (23): O programa abaixo demonstra a inclusão, exclusão e consulta de
números inteiros em uma Pilha alocada estaticamente usando as classes: PilhaVetor.
// -------------------------------------------------- Fonte: Dados23.java
package dados23;
import java.util.Scanner;
public class Dados23 {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
PilhaVetor pilha = new PilhaVetor(7);
int valor;
int erro = 0;
char ch;
do {
System.out.printf("[P]ush, P[o]p, [C]onsultar ou [F]im? ");
do {
String s = entrada.nextLine();
ch = s.charAt(0);
ch = Character.toLowerCase(ch);
} while (ch != 'p' && ch != 'o' && ch != 'c' && ch != 'f');
switch (ch) {
case 'p':
System.out.printf("Elemento: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
erro = pilha.push(valor);
break;
case 'o':
104
erro = pilha.pop();
break;
case 'c':
erro = pilha.consultaPilha();
break;
}
pilha.exibePilha();
if (erro != 0) {
pilha.imprimeErro(erro);
}
} while (ch != 'f');
}
}
// ------------------------------------------------------- Fonte: Dados23.java
package dados23;
public class PilhaVetor {
final int SUCESSO = 0;
final int PILHA_CHEIA = 1;
final int PILHA_VAZIA = 2;
private int topo;
private final int []elem;
private final int m;
// ------------------------------------ construtor
public PilhaVetor(int numElementos) {
elem = new int[numElementos];
topo = -1;
m = numElementos;
}
// ------------------------------------ push
public int push(int dado) {
if (topo == m - 1) {
return(PILHA_CHEIA);
}
else {
topo = topo + 1;
elem[topo] = dado;
return(SUCESSO);
}
}
// -------------------------------- pop
public int pop() {
if (topo == -1) {
return(PILHA_VAZIA);
}
else {
System.out.println("Pop: " + elem[topo]);
topo = topo - 1;
return(SUCESSO);
}
}
105
// ------------------------------- consultaPilha
public int consultaPilha() {
if (topo == -1) {
return(PILHA_VAZIA);
}
else {
System.out.println("Pop: " + elem[topo]);
return(SUCESSO);
}
}
// ------------------------------- exibePilha
public void exibePilha() {
System.out.print("Pilha: ");
if (topo != -1) {
for (int i = topo;i >= 0; i--) {
System.out.print(elem[i] + " ");
}
System.out.println();
}
}
// ------------------------------------------ imprimeErro
public void imprimeErro(int erro) {
switch (erro) {
case PILHA_CHEIA: System.out.println("ERRO: Pilha Cheia");
break;
case PILHA_VAZIA: System.out.println("ERRO: Pilha Vazia");
break;
}
}
}
Resultado do Programa:
[P]ush, P[o]p, [C]onsultar
Elemento: 10 <enter>
Pilha: 10
[P]ush, P[o]p, [C]onsultar
Elemento: 20 <enter>
Pilha: 20 10
[P]ush, P[o]p, [C]onsultar
Elemento: 30 <enter>
Pilha: 30 20 10
[P]ush, P[o]p, [C]onsultar
Pop: 30
Pilha: 30 20 10
[P]ush, P[o]p, [C]onsultar
Pop: 30
Pilha: 20 10
[P]ush, P[o]p, [C]onsultar
Pop: 20
Pilha: 10
[P]ush, P[o]p, [C]onsultar
Pop: 10
ou [F]im? p <enter>
ou [F]im? p <enter>
ou [F]im? p <enter>
ou [F]im? c <enter>
ou [F]im? o <enter>
ou [F]im? o <enter>
ou [F]im? o <enter>
106
Pilha: [P]ush, P[o]p, [C]onsultar ou [F]im? f <enter>
Pilha:
Programa exemplo (23a): O programa abaixo também demonstra a inclusão, exclusão e
consulta de números inteiros em uma Pilha alocada estaticamente usando as classes:
Pilha.
// ----------------------------------------------------------- Fonte: Dados23a.java
package Dados23a;
public class Dados23a {
public static void main(String[] args) {
Pilha pilha = new Pilha(6);
int valor;
pilha.Push(10);
pilha.Exibe();
pilha.Push(20);
pilha.Exibe();
pilha.Push(30);
pilha.Exibe();
pilha.Push(40);
pilha.Exibe();
pilha.Push(50);
pilha.Exibe();
pilha.Push(60);
pilha.Exibe();
valor = pilha.Pop();
System.out.println("Valor:
pilha.Exibe();
valor = pilha.Pop();
System.out.println("Valor:
pilha.Exibe();
valor = pilha.Pop();
System.out.println("Valor:
pilha.Exibe();
valor = pilha.Pop();
System.out.println("Valor:
pilha.Exibe();
valor = pilha.Pop();
System.out.println("Valor:
pilha.Exibe();
valor = pilha.Pop();
System.out.println("Valor:
pilha.Exibe();
valor = pilha.Pop();
pilha.Exibe();
}
" + valor);
" + valor);
" + valor);
" + valor);
" + valor);
" + valor);
}
// -------------------------------------------------- Pilha.java
package dados23a;
107
public class Pilha {
private final int [] vet;
private int topo;
// --------------------------------- construtor
public Pilha(int numeroElementos) {
vet = new int[numeroElementos];
topo = -1;
}
// --------------------------------- Push
public void Push(int valor) {
int n = vet.length;
if (topo < n-1) {
topo++;
vet[topo] = valor;
}
else {
System.out.println("Status: Pilha Cheia");
System.exit(0);
}
}
// --------------------------------- Pop
public int Pop() {
int valor;
if (topo >= 0) {
valor = vet[topo];
topo--;
return(valor);
}
else {
System.out.println("Status: Pilha Vazia");
return(-1);
}
}
// --------------------------------- exibePilha
public void Exibe() {
System.out.print("Pilha: [");
for (int i = 0;i < topo;i++) {
System.out.print(vet[i] + ",");
}
if (topo >= 0) {
System.out.println(vet[topo] + "]");
}
else {
System.out.println("]");
}
}
}
Resultado do Programa:
108
Pilha: [10]
Pilha: [10,20]
Pilha: [10,20,30]
Pilha: [10,20,30,40]
Pilha: [10,20,30,40,50]
Pilha: [10,20,30,40,50,60]
Valor: 60
Pilha: [10,20,30,40,50]
Valor: 50
Pilha: [10,20,30,40]
Valor: 40
Pilha: [10,20,30]
Valor: 30
Pilha: [10,20]
Valor: 20
Pilha: [10]
Valor: 10
Pilha: []
Status: Pilha Vazia
Pilha: []
3.2.5.2.2 Pilha com Alocação Dinâmica
A seguir é visto uma Pilha alocada dinamicamente na memória.
Figura 18: Pilha em uma Lista Encadeada
Problema: Escreva um programa em Java que inclui, exclui e consulta dados em uma Pilha
Encadeada.
Programa exemplo (24): O programa abaixo demonstra a inclusão, exclusão e consulta em
uma Pilha alocada dinamicamente.
// ---------------------------------------------------------- Fonte: Nodo.java
package dados24;
public class Nodo {
public int dado;
public Nodo elo = null;
}
109
// --------------------------------------------------- PilhaDinamica.java
package dados24;
public class PilhaDinamica {
private Nodo topo;
// ---------------------------------------------- construtor
public PilhaDinamica() {
topo = null;
}
// ---------------------------------------------- push
public void push(int dado) {
Nodo t = new Nodo();
t.dado = dado;
t.elo = topo;
topo = t;
}
// ---------------------------------------------- pop
public int pop() {
Nodo t;
if (topo == null) {
return(-1);
}
else {
t = topo;
topo = t.elo;
return(t.dado);
}
}
// ---------------------------------------------- consultaPilha
public int consultaPilha() {
Nodo t;
if (topo == null) {
return(-1);
}
else {
t = topo;
return(t.dado);
}
}
// ------------------------------------------------- exibePilha
public void exibePilha() {
Nodo t;
System.out.print("Pilha: ");
110
if (topo == null) {
System.out.print("Vazia");
}
else {
t = topo;
while (t != null) {
System.out.print(t.dado + " ");
t = t.elo;
}
}
System.out.println();
}
}
// --------------------------------------------------------------- Fonte: Dados24.java
package dados24;
import java.util.Scanner;
public class Dados24 {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
PilhaDinamica pilha = new PilhaDinamica();
int valor, dado;
char tecla;
do {
pilha.exibePilha();
System.out.print("[P]ush, p[O]p, [C]onsultar ou [F]im? ");
do {
String s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 'p' && tecla != 'o' && tecla != 'c' && tecla != 'f');
switch (tecla) {
case 'p': System.out.print("Elemento a ser Empilhado: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
pilha.push(valor);
break;
case 'o': dado = pilha.pop();
System.out.println("Dado: " + dado);
break;
case 'c': dado = pilha.consultaPilha();
System.out.println("Dado: " + dado);
break;
}
} while (tecla != 'f');
}
}
Resultado do Programa:
Pilha: Vazia
[P]ush, p[O]p, [C]onsultar ou [F]im? p <enter>
Elemento a ser Empilhado: 10 <enter>
Pilha: 10
111
[P]ush, p[O]p, [C]onsultar ou [F]im?
Elemento a ser Empilhado: 20 <enter>
Pilha: 20 10
[P]ush, p[O]p, [C]onsultar ou [F]im?
Elemento a ser Empilhado: 30 <enter>
Pilha: 30 20 10
[P]ush, p[O]p, [C]onsultar ou [F]im?
Dado: 30
Pilha: 30 20 10
[P]ush, p[O]p, [C]onsultar ou [F]im?
Dado: 30
Pilha: 20 10
[P]ush, p[O]p, [C]onsultar ou [F]im?
Dado: 20
Pilha: 10
[P]ush, p[O]p, [C]onsultar ou [F]im?
Dado: 10
Pilha: Vazia
[P]ush, p[O]p, [C]onsultar ou [F]im?
p <enter>
p <enter>
c <enter>
o <enter>
o <enter>
o <enter>
f <enter>
3.2.5.3 Deque (“Double-Ended QUEue”)
É uma fila de duas extremidades. As inserções, consultas e retiradas são
permitidas nas duas extremidades.
Início
Fim
Figura 19: Deque
Deque de Entrada Restrita
A inserção só pode ser efetuada ou no início ou no final da lista.
Deque de Saída Restrita
A retirada só pode ser efetuada ou no início ou no final da lista.
Condição Inicial: Esquerda (Esq) e Direita (Dir) no meio do vetor
Esq = (m DIV 2 + 1
Dir = (m DIV 2) + 1
112
Figura 20: Operações sobre um Deque
Deque Vazio
Esq = -1
Dir = -1
Deque Cheio
Esq = 0
Dir = m-1
Cálculo do número de elementos do Deque
número_de_elementos = Dir - Esq + 1;
Problema: Escreva um programa em Java que inclui, exclui e consulta dados em um Deque.
Programa exemplo (26): O programa abaixo demonstra um Deque usando um vetor.
// ------------------------------------------------------------ Fonte: Dados26.java
package dados26;
import java.util.Scanner;
public class Dados26 {
public static void main(String[] args) {
Deque deque = new Deque(7);
Scanner entrada = new Scanner(System.in);
int valor;
char ch, op;
int erro = 0;
do {
deque.exibeDeque();
System.out.print("[I]nclui, [E]xclui, [C]onsulta ou [F]im: ");
do {
String s = entrada.nextLine();
op = s.charAt(0);
113
op = Character.toLowerCase(op);
} while (op != 'i' && op != 'e' && op != 'c' && op != 'f');
if (op == 'i' || op == 'e' || op == 'c') {
System.out.print("[E]squerda ou [D]ireita: ");
do {
String s = entrada.nextLine();
ch = s.charAt(0);
ch = Character.toLowerCase(ch);
} while (ch != 'e' && ch != 'd');
switch (op) {
case 'i': System.out.print("Elemento: ");
String s = entrada.nextLine();
valor = Integer.parseInt(s);
if (valor != 0) {
switch (ch) {
case 'e': erro = deque.incluiDequeEsquerda(valor);
break;
case 'd': erro = deque.incluiDequeDireita(valor);
break;
}
}
break;
case 'e': switch (ch) {
case 'e': erro = deque.excluiDequeEsquerda();
break;
case 'd': erro = deque.excluiDequeDireita();
break;
}
break;
case 'c': switch (ch) {
case 'e': erro = deque.consultaDequeEsquerda();
break;
case 'd': erro = deque.consultaDequeDireita();
break;
}
break;
}
if (erro != 0) {
deque.imprimeErro(erro);
}
}
} while (op != 'f');
}
}
// -------------------------------------------------------------------- Deque.java
package dados26;
public class Deque {
final int SUCESSO = 0;
final int DEQUE_ESQUERDO_CHEIO = 1;
final int DEQUE_DIREITO_CHEIO = 2;
final int DEQUE_VAZIO = 3;
private int esq;
private int dir;
private int [] v;
private int m;
114
// ------------------------------------ construtor
public Deque(int numElementos) {
v = new int[numElementos];
m = numElementos;
esq = -1;
dir = -1;
}
// ------------------------------------ incluiDequeEsquerda
public int incluiDequeEsquerda(int dado) {
if (esq == 0) {
return(DEQUE_ESQUERDO_CHEIO);
}
else {
if (esq == -1) {
esq = m / 2;
dir = esq;
}
else {
esq = esq - 1;
}
v[esq] = dado;
return(SUCESSO);
}
}
// ------------------------------------ incluiDequeDireita
public int incluiDequeDireita(int dado) {
if (dir == m - 1) {
return(DEQUE_DIREITO_CHEIO);
}
else {
if (dir == -1) {
dir = m / 2;
esq = dir;
}
else {
dir = dir + 1;
}
v[dir] = dado;
return(SUCESSO);
}
}
// ------------------------------------ excluiDequeEsquerda
public int excluiDequeEsquerda() {
if (esq == -1) {
return(DEQUE_VAZIO);
}
else {
System.out.println("Dado Removido a Esquerda: " + v[esq]);
esq = esq + 1;
if (esq > dir) {
esq = -1;
dir = -1;
115
}
return(SUCESSO);
}
}
// ------------------------------------ excluiDequeDireita
public int excluiDequeDireita() {
if (dir == -1) {
return(DEQUE_VAZIO);
}
else {
System.out.println("Dado excluido Direita do Deque:" + v[dir]);
dir = dir - 1;
if (dir < esq) {
esq = -1;
dir = -1;
}
return(SUCESSO);
}
}
// ------------------------------------ consultaDequeEsquerda
public int consultaDequeEsquerda() {
if (esq == -1) {
return(DEQUE_VAZIO);
}
else {
System.out.println("Valor Consultado Esquerda Deque: " + v[esq]);
return(SUCESSO);
}
}
// ------------------------------------ ConsultaDequeDireita
public int consultaDequeDireita() {
if (dir == -1) {
return(DEQUE_VAZIO);
}
else {
System.out.println("Valor Consultado Direita Deque: " + v[dir]);
return(SUCESSO);
}
}
// ------------------------------------ exibeDeque
public void exibeDeque() {
System.out.print("Deque: ");
if (esq == -1) {
System.out.print("Vazio");
}
else {
for (int i = esq;i <= dir;i++) {
System.out.print(v[i] + " ");
}
}
System.out.println();
116
}
// ------------------------------------ Imprime_Erro
public void imprimeErro(int erro) {
switch (erro) {
case DEQUE_ESQUERDO_CHEIO:
System.out.println("ERRO: Deque Cheio à Esquerda");
break;
case DEQUE_DIREITO_CHEIO:
System.out.println("ERRO: Deque Cheio à Direita");
break;
case DEQUE_VAZIO:
System.out.println("ERRO: Deque Vazio");
break;
}
}
}
Resultado do Programa:
Deque: Vazio
[I]nclui, [E]xclui, [C]onsulta ou [F]im:
[E]squerda ou [D]ireita: e <enter>
Elemento: 10 <enter>
Deque: 10
[I]nclui, [E]xclui, [C]onsulta ou [F]im:
[E]squerda ou [D]ireita: d <enter>
Elemento: 20 <enter>
Deque: 10 20
[I]nclui, [E]xclui, [C]onsulta ou [F]im:
[E]squerda ou [D]ireita: d <enter>
Elemento: 30 <enter>
Deque: 10 20 30
[I]nclui, [E]xclui, [C]onsulta ou [F]im:
[E]squerda ou [D]ireita: e <enter>
Valor Consultado Esquerda Deque: 10
Deque: 10 20 30
[I]nclui, [E]xclui, [C]onsulta ou [F]im:
[E]squerda ou [D]ireita: d <enter>
Valor Consultado Direita Deque: 30
Deque: 10 20 30
[I]nclui, [E]xclui, [C]onsulta ou [F]im:
i <enter>
i <enter>
i <enter>
c <enter>
c <enter>
f <enter>
117
4. Pesquisa de Dados
Uma operação complexa e trabalhosa é a consulta em tabelas. Normalmente uma
aplicação envolve grande quantidade de dados que são armazenadas em Tabelas.
As tabelas são compostas de registros (normalmente possui uma chave), e os
registros de campos.
Figura 21: Exemplo de uma Tabela
4.1 Pesquisa Seqüencial
Método mais simples de pesquisa em tabela, consiste em uma varredura seqüencial,
sendo que cada campo é comparado com o valor que está sendo procurado. Esta pesquisa
termina quando for achado o valor desejado ou quando chegar o final da tabela.
Figura 22: Número Médio de Comparações
Problema: Escreva um programa em Java que faz uma Busca Seqüencial em uma estrutura que
possui os campos: chave, nome, altura e peso.
Programa exemplo (27): O programa demonstra uma busca sequencial em uma tabela.
118
// ------------------------------------------------------------ Fonte: Dados27.java
package dados27;
import java.util.Scanner;
public class Dados27 {
public static void main(String[] args) {
Tabela tabela = new Tabela(10);
Scanner entrada = new Scanner(System.in);
int key, chave;
tabela.entradaTabela();
do {
System.out.print("Chave para consulta [0 - Sair]: ");
String s = entrada.nextLine();
key = Integer.parseInt(s);
if (key != 0) {
chave = tabela.pesquisaSequencial(key);
tabela.exibeTabela(chave);
}
} while (key != 0);
}
}
// --------------------------------------------------------------- Fonte: Tabela.java
package dados27;
import java.util.Scanner;
public class Tabela {
private int [] chave;
private String [] nome;
private float [] peso;
private float [] altura;
private int n = -1;
private int max;
// ---------------------------------------------- construtor
public Tabela(int numElementos) {
chave = new int[numElementos];
nome = new String[numElementos];
peso = new float[numElementos];
altura = new float[numElementos];
n = -1;
max = numElementos;
}
// ---------------------------------------------- pesquisaSequencial
public int pesquisaSequencial(int ch) {
int key = -1;
for (int i = 0;i <= n;i++) {
119
if (chave[i] == ch) {
key = i;
break;
}
}
return(key);
}
// ---------------------------------------------- exibeTabela
public void exibeTabela(int key) {
if (key != -1) {
System.out.println("Chave: " + chave[key]);
System.out.println("Nome: " + nome[key]);
System.out.println("Peso: " + peso[key]);
System.out.println("Altura: " + altura[key]);
}
else {
System.out.println("Erro: Chave Inexistente");
}
}
// ---------------------------------------------- entradaTabela
public void entradaTabela() {
Scanner entrada = new Scanner(System.in);
String s;
char tecla;
do {
n++;
System.out.printf("Chave: ");
s = entrada.nextLine();
chave[n] = Integer.parseInt(s);
if (chave[n] == 0) {
System.exit(0);
}
System.out.printf("Nome: ");
nome[n] = entrada.nextLine();
System.out.printf("Peso: ");
s = entrada.nextLine();
peso[n] = Integer.parseInt(s);
System.out.printf("Altura: ");
s = entrada.nextLine();
altura[n] = Float.parseFloat(s);
System.out.printf("Continua [S/N] ?");
do {
s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 's' && tecla != 'n');
} while (tecla == 's' && n < max);
}
}
Resultado do Programa:
Chave: 10 <enter>
Nome: Paulo <enter>
120
Peso: 94 <enter>
Altura: 1.67 <enter>
Continua [S/N] ?s <enter>
Chave: 20 <enter>
Nome: Renato <enter>
Peso: 78 <enter>
Altura: 1.80 <enter>
Continua [S/N] ?n <enter>
Chave para consulta [0 - Sair]:
Chave: 10
Nome: Paulo
Peso: 94.0
Altura: 1.67
Chave para consulta [0 - Sair]:
Chave: 20
Nome: Renato
Peso: 78.0
Altura: 1.8
Chave para consulta [0 - Sair]:
Erro: Chave Inexistente
Chave para consulta [0 - Sair]:
10 <enter>
20 <enter>
30 <enter>
0 <enter>
Observação: A Pesquisa Sequencial apresenta desempenho melhor se a tabela estiver
ordenada pela chave de acesso:
Problema: Escreva um programa em Java que faz uma Busca Seqüencial, em uma estrutura
ordenada por chave, que possui os campos: chave, nome, altura e peso.
Programa exemplo (28): O programa demonstra uma busca sequencial em uma tabela
ordenada por chave.
// --------------------------------------------------- Fonte: Dados28.java
package dados28;
import java.util.Scanner;
public class Dados28 {
public static void main(String[] args) {
Tabela tabela = new Tabela(10);
Scanner entrada = new Scanner(System.in);
int key, chave;
tabela.entradaTabela();
tabela.ordenaTabela();
do {
System.out.print("Chave para consulta [0 - Sair]: ");
String s = entrada.nextLine();
key = Integer.parseInt(s);
if (key != 0) {
chave = tabela.pesquisaSequencial(key);
tabela.exibeTabela(chave);
}
} while (key != 0);
}
121
}
// ---------------------------------------------------- Fonte: Tabela.java
package dados28;
import java.util.Scanner;
public class Tabela {
private final int max;
private int [] chave;
private String [] nome;
private float [] peso;
private float [] altura;
private int n;
// ---------------------------------------------- construtor
public Tabela(int numElementos) {
max = numElementos;
chave = new int[max];
nome = new String[max];
peso = new float[max];
altura = new float[max];
n = -1;
}
// ---------------------------------------------- pesquisaSequencial
public int pesquisaSequencial(int ch) {
int key = -1;
for (int i = 0;i <= n;i++) {
if (chave[i] == ch) {
key = i;
break;
}
}
return(key);
}
// ---------------------------------------------- ordenaTabela
public void ordenaTabela() {
for (int i = 0;i < n-1;i++) {
for (int j = i+1;j < n;j++) {
if (chave[i] > chave[j]) {
int temp = chave[i];
chave[i] = chave[j];
chave[j] = temp;
String s = nome[i];
nome[i] = nome[j];
nome[j] = s;
float f = peso[i];
peso[i] = peso[j];
peso[j] = f;
f = altura[i];
altura[i] = altura[j];
altura[j] = f;
122
}
}
}
}
// ---------------------------------------------- exibeTabela
public void exibeTabela(int key) {
if (key != -1) {
System.out.println("Chave: " + chave[key]);
System.out.println("Nome: " + nome[key]);
System.out.println("Peso: " + peso[key]);
System.out.println("Altura: " + altura[key]);
}
else {
System.out.println("Erro: Chave Inexistente");
}
}
// ---------------------------------------------- entradaTabela
public void entradaTabela() {
Scanner entrada = new Scanner(System.in);
String s;
char tecla;
do {
n++;
System.out.printf("Chave: ");
s = entrada.nextLine();
chave[n] = Integer.parseInt(s);
if (chave[n] == 0) {
System.exit(0);
}
System.out.printf("Nome: ");
nome[n] = entrada.nextLine();
System.out.printf("Peso: ");
s = entrada.nextLine();
peso[n] = Integer.parseInt(s);
System.out.printf("Altura: ");
s = entrada.nextLine();
altura[n] = Float.parseFloat(s);
System.out.printf("Continua [S/N] ?");
do {
s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 's' && tecla != 'n');
} while (tecla == 's' && n < max);
}
}
Resultado do Programa:
Chave: 10 <enter>
Nome: Paulo <enter>
Peso: 94 <enter>
Altura: 1.67 <enter>
Continua [S/N] ?s <enter>
123
Chave: 20 <enter>
Nome: Renato <enter>
Peso: 78 <enter>
Altura: 1.80 <enter>
Continua [S/N] ?n <enter>
Chave para consulta [0 - Sair]: 10 <enter>
Chave: 10
Nome: Paulo
Peso: 94.0
Altura: 1.67
Chave para consulta [0 - Sair]: 20 <enter>
Chave: 20
Nome: Renato
Peso: 78.0
Altura: 1.8
Chave para consulta [0 - Sair]: 0 <enter>
4.2 Pesquisa Binária
Método de Pesquisa que só pode ser aplicada em tabelas ordenadas.
Figura 23: Pesquisa Binária
O método consiste na comparação do "valor" com a chave localizada na metade da
tabela, pode ocorrer:
valor = chave....... chave localizada
valor < chave....... chave está na primeira metade (esquerda)
valor > chave....... chave está na segunda metade (direita)
A cada comparação, a área de pesquisa é reduzida a metade do número de
elementos.
O número máximo de comparações será:
124
nc = log n + 1
2
Problema: Escreva um programa em Java que faz uma Pesquisa Binária em uma tabela de
números inteiros.
Programa exemplo (29): O programa demonstra uma busca binária em uma tabela ordenada
por chave.
// -------------------------------------------------------------- Fonte: Dados29.java
package dados29;
import java.util.Scanner;
public class Dados29 {
public static void main(String[] args) {
Tabela tabela = new Tabela(10);
Scanner entrada = new Scanner(System.in);
int key, chave;
tabela.entradaTabela();
tabela.ordenaTabela();
do {
System.out.print("Chave para consulta [0 - Sair]: ");
String s = entrada.nextLine();
key = Integer.parseInt(s);
if (key != 0) {
chave = tabela.pesquisaBinaria(key);
tabela.exibeTabela(chave);
}
} while (key != 0);
}
}
// ---------------------------------------- Fonte: Tabela.java
package dados29;
import java.util.Scanner;
public class Tabela {
private final int max;
private int [] chave;
private String [] nome;
private float [] peso;
private float [] altura;
private int n;
// ---------------------------------------------- construtor
public Tabela(int numElementos) {
max = numElementos;
chave = new int[max];
nome = new String[max];
125
peso = new float[max];
altura = new float[max];
n = -1;
}
// ---------------------------------------------- pesquisaBinaria
public int pesquisaBinaria(int valor) {
int indice = -1;
int inic, fim, metade;
inic = 0;
fim = (n - 1) + 1;
metade = n / 2;
do {
if (valor == chave[metade]) {
indice = metade;
break;
}
else {
if (valor < chave[metade]) {
fim = metade - 1;
metade = (fim + inic) / 2;
}
else {
inic = metade + 1;
metade = (fim + inic) / 2;
}
}
} while (indice == -1 && inic <= fim);
return(indice);
}
// ---------------------------------------------- ordenaTabela
public void ordenaTabela() {
for (int i = 0;i < n;i++) {
for (int j = i+1;j <= n;j++) {
if (chave[i] > chave[j]) {
int temp = chave[i];
chave[i] = chave[j];
chave[j] = temp;
String s = nome[i];
nome[i] = nome[j];
nome[j] = s;
float f = peso[i];
peso[i] = peso[j];
peso[j] = f;
f = altura[i];
altura[i] = altura[j];
altura[j] = f;
}
}
}
}
// ---------------------------------------------- exibeTabela
public void exibeTabela(int key) {
126
if (key != -1) {
System.out.println("Chave: " + chave[key]);
System.out.println("Nome: " + nome[key]);
System.out.println("Peso: " + peso[key]);
System.out.println("Altura: " + altura[key]);
}
else {
System.out.println("Erro: Chave Inexistente");
}
}
// ---------------------------------------------- entradaTabela
public void entradaTabela() {
Scanner entrada = new Scanner(System.in);
String s;
char tecla;
do {
n++;
System.out.printf("Chave: ");
s = entrada.nextLine();
chave[n] = Integer.parseInt(s);
if (chave[n] == 0) {
System.exit(0);
}
System.out.printf("Nome: ");
nome[n] = entrada.nextLine();
System.out.printf("Peso: ");
s = entrada.nextLine();
peso[n] = Integer.parseInt(s);
System.out.printf("Altura: ");
s = entrada.nextLine();
altura[n] = Float.parseFloat(s);
System.out.printf("Continua [S/N] ?");
do {
s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 's' && tecla != 'n');
} while (tecla == 's' && n < max);
}
}
Resultado do Programa:
Chave: 20 <enter>
Nome: Beatriz <enter>
Peso: 56 <enter>
Altura: 1.45 <enter>
Continua [S/N] ?s <enter>
Chave: 30 <enter>
Nome: Ana <enter>
Peso: 67 <enter>
Altura: 1.56 <enter>
Continua [S/N] ?s <enter>
Chave: 10 <enter>
Nome: Carla <enter>
Peso: 78 <enter>
127
Altura: 1.58 <enter>
Continua [S/N] ?n <enter>
Chave para consulta [0 - Sair]:
Chave: 10
Nome: Carla
Peso: 78.0
Altura: 1.58
Chave para consulta [0 - Sair]:
Chave: 20
Nome: Beatriz
Peso: 56.0
Altura: 1.45
Chave para consulta [0 - Sair]:
Chave: 30
Nome: Ana
Peso: 67.0
Altura: 1.56
Chave para consulta [0 - Sair]:
10 <enter>
20 <enter>
30 <enter>
0 <enter>
4.3 Cálculo de Endereço (Hashing)
Além de um método de pesquisa, este método é também um método de organização
física de tabelas (Classificação). Onde cada dado de entrada é armazenado em um
endereço previamente calculado (através de uma função), desta forma, o processo de
busca é igual ao processo de entrada, ou seja, eficiente.
Um dos problemas é definir bem o tipo de função a ser usada, pois normalmente as
funções geram endereços repetidos. A eficiência deste método depende do tipo de função.
Numa tabela com n elementos com valores na faixa de [0..max] pode ser utilizada
a seguinte a função:
Onde: n é o número de elementos.
Exemplo:
n = 53
entrada: [0..1000]
Note que no cálculo dos endereços houve repetições, tais como: 2, 33, 23, 10 e
50, por causa disto, é necessário verificar se o endereço está ocupado ou não.
Finalmente os endereços calculados são:
128
Problema: Escreva um programa em Java que faz um Cálculo de Endereço (Hashing) em uma
tabela de números inteiros.
Programa exemplo (30): O programa demonstra operações em uma Tabela Hashing.
// --------------------------------------------------------------- Fonte: Dados30.java
package dados30;
import java.util.Scanner;
public class Dados30 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
Tabela tabela = new Tabela(15);
int n = 0, entrada, endereco;
// 15 elementos
int max = tabela.consultaLimite();
do {
tabela.exibeTabela();
n++;
System.out.print("Número [0 para Sair]: ");
String s = input.nextLine();
entrada = Integer.parseInt(s);
if (entrada != 0) {
tabela.insereTabela(entrada);
}
} while (entrada != 0 && n <= max);
tabela.exibeTabela();
do {
System.out.print("Valor a ser CONSULTADO: ");
String s = input.nextLine();
entrada = Integer.parseInt(s);
if (entrada != 0) {
endereco = tabela.hashing(entrada);
if (endereco == -1) {
System.out.println("Status: Valor Inválido");
}
else {
System.out.println("Endereco: " + endereco);
}
}
} while (entrada != 0);
}
}
// --------------------------------------------------------------- Fonte: Tabela.java
129
package dados30;
public class Tabela {
private final int max;
private boolean [] situacao;
private int [] valor;
// ---------------------------------------------- Tabela
public Tabela(int numElementos) {
max = numElementos;
situacao = new boolean[max];
valor = new int[max];
for (int i = 0;i < situacao.length;i++) {
situacao[i] = false;
valor[i] = 0;
}
}
// ---------------------------------------------- consultaLimite
public int consultaLimite() {
return(max);
}
// ---------------------------------------------- testaTabela
public boolean testaTabela() {
for (int i = 0;i < situacao.length; i++) {
if (situacao[i] == false) {
return(false);
}
}
return(true);
}
// ---------------------------------------------- insereTabela
public void insereTabela(int entrada) {
int endereco, n = -1;
boolean lotado = testaTabela();
if (!lotado) {
endereco = entrada % max;
while (situacao[endereco] == true) {
endereco++;
n++;
}
if (n < max) {
valor[endereco] = entrada;
situacao[endereco] = true;
}
}
else {
System.out.println("Status: TABELA CHEIA ...");
}
}
130
// ---------------------------------------------- hashing
public int hashing(int entrada) {
int endereco;
endereco = entrada % max;
while (valor[endereco] != entrada && endereco != max) {
endereco++;
if (endereco == max) {
return(-1);
}
}
if (endereco != max) {
return(endereco);
}
else {
return(-1);
}
}
// ---------------------------------------------- exibeTabela
public void exibeTabela() {
for (int i = 0;i < max;i++) {
System.out.printf("%3d ",i);
}
System.out.println();
for (int i = 0;i < max;i++) {
System.out.printf("%03d ",valor[i]);
}
System.out.println();
}
}
Resultado do Programa:
0
1
2
3
4
5
6
7
8
000 000 000 000 000 000 000 000 000
Número [0 para Sair]: 383 <enter>
0
1
2
3
4
5
6
7
8
000 000 000 000 000 000 000 000 383
Número [0 para Sair]: 487 <enter>
0
1
2
3
4
5
6
7
8
000 000 000 000 000 000 000 487 383
Número [0 para Sair]: 235 <enter>
0
1
2
3
4
5
6
7
8
000 000 000 000 000 000 000 487 383
Número [0 para Sair]: 527 <enter>
0
1
2
3
4
5
6
7
8
000 000 527 000 000 000 000 487 383
Número [0 para Sair]: 510 <enter>
0
1
2
3
4
5
6
7
8
510 000 527 000 000 000 000 487 383
Número [0 para Sair]: 320 <enter>
0
1
2
3
4
5
6
7
8
510 000 527 000 000 320 000 487 383
Número [0 para Sair]: 203 <enter>
0
1
2
3
4
5
6
7
8
510 000 527 000 000 320 000 487 383
9 10 11 12 13 14
000 000 000 000 000 000
9 10 11 12 13 14
000 000 000 000 000 000
9 10 11 12 13 14
000 000 000 000 000 000
9 10 11 12 13 14
000 235 000 000 000 000
9 10 11 12 13 14
000 235 000 000 000 000
9 10 11 12 13 14
000 235 000 000 000 000
9 10 11 12 13 14
000 235 000 000 000 000
9 10 11 12 13 14
203 235 000 000 000 000
131
Número [0 para Sair]: 108 <enter>
0
1
2
3
4
5
6
7
8
510 000 527 108 000 320 000 487 383
Número [0 para Sair]: 563 <enter>
0
1
2
3
4
5
6
7
8
510 000 527 108 000 320 000 487 383
Número [0 para Sair]: 500 <enter>
0
1
2
3
4
5
6
7
8
510 000 527 108 000 320 500 487 383
Número [0 para Sair]: 646 <enter>
0
1
2
3
4
5
6
7
8
510 646 527 108 000 320 500 487 383
Número [0 para Sair]: 103 <enter>
0
1
2
3
4
5
6
7
8
510 646 527 108 000 320 500 487 383
Número [0 para Sair]: 0 <enter>
0
1
2
3
4
5
6
7
8
510 646 527 108 000 320 500 487 383
Valor a ser CONSULTADO: 487 <enter>
Endereco: 7
Valor a ser CONSULTADO: 646 <enter>
Endereco: 1
Valor a ser CONSULTADO: 0 <enter>
9 10 11 12 13 14
203 235 000 000 000 000
9 10 11 12 13 14
203 235 563 000 000 000
9 10 11 12 13 14
203 235 563 000 000 000
9 10 11 12 13 14
203 235 563 000 000 000
9 10 11 12 13 14
203 235 563 000 103 000
9 10 11 12 13 14
203 235 563 000 103 000
132
5. Classificação de Dados (Ordenação)
É o processo pelo qual é determinada a ordem em que devem ser apresentados os
elementos de uma tabela de modo a obedecer à seqüência de um ou mais campos (chaves de
classificação).
Classificação Interna...................... Memória Principal
Classificação Externa...................... Memória Secundária
5.1 Classificação por Força Bruta
Figura 24: Exemplo de Tabela de Nomes
Logo, os elementos são fisicamente reorganizados.
Problema: Escreva um programa em Java que ordena (classifica em ordem crescente) um
vetor de números inteiros.
Programa exemplo (31): O programa demonstra um programa de classificação por força
bruta.
// ---------------------------------------------------------- Fonte: Dados31.java
package dados31;
import java.util.Scanner;
public class Dados31 {
public static void main(String[] args) {
final int QUANT = 10;
int [] v = new int[QUANT];
Scanner entrada = new Scanner(System.in);
int n = -1;
do {
133
n++;
System.out.print("Valor: ");
String s = entrada.nextLine();
v[n] = Integer.parseInt(s);
} while (v[n] != 0 && n < QUANT);
if (v[n] == 0) {
n--;
}
sortForcaBruta(v, n);
exibeLista(v, n);
}
// ------------------------------------------------------- sortForcaBruta
static void sortForcaBruta(int [] v, int n) {
for (int i = 0;i < n;i++) {
for (int j = i+1;j <= n;j++) {
if (v[i] > v[j]) {
int temp = v[i];
v[i] = v[j];
v[j] = temp;
}
}
}
}
// ------------------------------------------------------- exibe
static void exibeLista(int [] v, int n) {
System.out.print("Lista: ");
if (n == -1) {
System.out.print("Vazia");
}
else {
for (int i = 0;i <= n;i++) {
System.out.printf("%2d ", v[i]);
}
}
System.out.println();
}
}
Resultado do Programa:
Valor:
Valor:
Valor:
Valor:
Valor:
Valor:
Lista:
30 <enter>
50 <enter>
40 <enter>
20 <enter>
10 <enter>
0 <enter>
10 20 30 40 50
5.2 Vetor Indireto de Ordenação (Tabela de Índices)
Os elementos não são reorganizados fisicamente, apenas é criado um outro vetor
(tabela de índices) que controla a ordem do primeiro.
134
Exemplo:
Figura 25: Exemplo de Tabela de Nomes
Problema: Escreva um programa em Java que ordena (classifica em ordem crescente) um
vetor de números inteiros utilizando um Vetor Indireto de Ordenação (VIO).
Programa exemplo (32): O programa demonstra a utilização de um vetor indireto de
ordenação.
// ------------------------------------------------------------- Fonte: Dados32.java
package dados32;
import java.util.Scanner;
public class Dados32 {
public static void main(String[] args) {
final int QUANT = 10;
String [] v = new String[QUANT];
int [] vio = new int[QUANT];
Scanner entrada = new Scanner(System.in);
int u = -1;
char tecla;
do {
u++;
System.out.print("Nome: ");
v[u] = entrada.nextLine();
System.out.print("Continua [S/N] ?");
vio[u] = 0;
do {
String s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 's' && tecla != 'n');
} while (tecla != 'n' && u <= QUANT);
for (int i = 0;i <= u;i++) {
vio[i] = i;
}
for (int i = 0;i < u;i++) {
for (int j = i+1;j <= u;j++) {
if (v[vio[i]].compareTo(v[vio[j]]) > 0) {
int temp = vio[i];
vio[i] = vio[j];
135
vio[j] = temp;
}
}
}
System.out.println("Lista de Nomes Ordenados");
for (int i = 0;i <= u;i++) {
System.out.printf("Nome: %s\n",v[vio[i]]);
}
}
}
Resultado do Programa:
Nome: Carla <enter>
Continua [S/N] ?s <enter>
Nome: Beatriz <enter>
Continua [S/N] ?s <enter>
Nome: Ana <enter>
Continua [S/N] ?n <enter>
Lista de Nomes Ordenados
Nome: Ana
Nome: Beatriz
Nome: Carla
5.3 Classificação por Encadeamento
Os elementos permanecem em seus lugares. É criado então uma lista encadeada
ordenada. Esta lista possui um Header (Cabeça) o qual indica o primeiro elemento da
lista.
Exemplo:
Figura 26: Classificação por Encadeamento
Problema: Escreva um programa em Java que ordena (classifica em ordem crescente) um
vetor de números inteiros utilizando encadeamento.
Programa exemplo (33): O programa demonstra a ordenação uti-lizando encadeamento.
136
// ------------------------------------------------------------ Fonte: Tabela.java
package dados33;
public class Tabela {
public String nome;
public int prox = -1;
}
// ----------------------------------------------------------------- Fonte: Dados33.java
package dados33;
import java.util.Scanner;
public class Dados33 {
public static void main(String[] args) {
final int QUANT = 10;
Tabela [] t = new Tabela[QUANT];
Tabela [] ta = new Tabela[QUANT];
Scanner entrada = new Scanner(System.in);
int j = 0, k, m, u = -1;
int anterior, primeiro, sai;
char tecla;
do {
u++;
System.out.print("Nome: ");
String s = entrada.nextLine();
t[u] = new Tabela();
t[u].nome = s;
t[u].prox = -1;
System.out.print("Continua [S/N]? ");
do {
s = entrada.nextLine();
tecla = s.charAt(0);
tecla = Character.toLowerCase(tecla);
} while (tecla != 's' && tecla != 'n');
} while (tecla != 'n' && u < QUANT);
primeiro = 0;
for (int i = 1;i <= u;i++) {
if (t[i].nome.compareTo(t[primeiro].nome) < 0) {
primeiro = i;
}
}
t[primeiro].prox = 0;
anterior = primeiro;
do {
m = copia(t, ta, u);
if (m != 0) {
if (m >= 1) {
int i = 1;
j = 0;
do {
if (ta[i].nome.compareTo(ta[j].nome) < 0) {
j = i;
}
i++;
137
} while (i <= m);
}
}
else {
j = 0;
}
k = verifica(t, ta, j);
t[anterior].prox = k;
t[k].prox = 0;
anterior = k;
} while (m != 0);
j = primeiro;
System.out.println("Lista de Nomes Ordenados por Encadeamento");
for (int i = 0;i <= u;i++) {
System.out.printf("%s\n",t[j].nome);
j = t[j].prox;
}
}
// --------------------------------------------------- verifica
static int verifica(Tabela [] t, Tabela [] ta, int j) {
boolean sai;
int i = 0;
do {
sai = false;
if (t[i].nome.compareTo(ta[j].nome) == 0) {
j = i;
sai = true;
}
i++;
} while (!sai);
return(j);
}
// ---------------------------------------------- Copia
static int copia(Tabela [] t, Tabela [] ta, int n) {
int m = -1;
for (int i = 0;i <= n;i++) {
ta[i] = new Tabela();
if (t[i].prox == -1) {
m++;
ta[m].nome = t[i].nome;
ta[m].prox = -1;
}
}
return(m);
}
}
Resultado do Programa:
Nome: Beatriz <enter>
Continua [S/N]? s <enter>
Nome: Debora <enter>
138
Continua [S/N]? s <enter>
Nome: Ana <enter>
Continua [S/N]? s <enter>
Nome: Carla <enter>
Continua [S/N]? n <enter>
Lista de Nomes Ordenados por Encadeamento
Ana
Beatriz
Carla
Debora
5.4 Métodos de Classificação Interna
Os métodos de Classificação Interna podem ser:
Por Inserção
Por Troca
Por Seleção
Observação: Para os seguintes métodos considere que as entradas são feitas no vetor v,
logo após é criado o vetor c (chaves) e o vetor e (endereços). A ordenação é feita no
vetor c e o vetor e é o vetor indireto de ordenação, ou seja, será mantido o vetor de
entrada intacto.
Figura 27: Métodos de Classificação Interna (Tabela de números inteiros)
5.4.1 Método por Inserção Direta
Neste método ocorre a inserção de cada elemento em outro vetor ordenado.
139
Figura 28: Vetor original, chaves e vetor indireto de ordenação
Utilização: Pequena quantidade de dados, pois é pouco eficiente.
O vetor é dividido em dois segmentos. Inicialmente:
c[0]
e
c[1], c[2], ... c[n]
A classificação acontece por meio de interações, cada elemento do segundo
segmento é inserido ordenadamente no primeiro até que o segundo segmento acabe. Por
exemplo:
Figura 29: Método por Inserção Direta
Problema: Escreva um programa em Java que ordena (classifica em ordem crescente) um
vetor de números inteiros utilizando Método por Inserção Direta.
Programa exemplo (34): O programa demonstra a ordenação utilizando o método de inserção
direta.
140
// --------------------------------------------------------------- Fonte: Dados34.java
package dados34;
import java.util.Scanner;
public class Dados34 {
public static void main(String[] args) {
final int QUANT = 10;
int [] v = new int[QUANT];
int [] c = new int[QUANT];
int [] e = new int[QUANT];
int j, k, u = -1, temp;
int chave, endereco;
Scanner entrada = new Scanner(System.in);
do {
u++;
System.out.print("Número: ");
String s = entrada.nextLine();
temp = Integer.parseInt(s);
if (temp != 0) {
v[u] = temp;
}
else {
u--;
}
} while (temp != 0 && u < QUANT);
for (int i = 0;i <= u;i++) {
c[i] = v[i];
e[i] = i;
}
for (int i = 1;i <= u;i++) {
k = 0;
j = i - 1;
chave = c[i];
endereco = e[i];
while (j >= 0 && k == 0) {
if (chave < c[j]) {
c[j+1] = c[j];
e[j+1] = e[j];
j--;
}
else {
k = j + 1;
}
}
c[k] = chave;
e[k] = endereco;
}
System.out.printf(" Valores: ");
for (int i = 0;i <= u;i++) {
System.out.printf("%2d ", c[i]);
}
System.out.println();
System.out.print("Endereços: ");
141
for (int i = 0;i <= u;i++) {
System.out.printf("%2d ", e[i]);
}
System.out.println();
}
}
Resultado do Programa:
Número: 20 <enter>
Número: 40 <enter>
Número: 50 <enter>
Número: 30 <enter>
Número: 10 <enter>
Número: 0 <enter>
Valores: 10 20 30 40 50
Endereços: 4 0 3 1 2
5.4.2 Método por Troca
Neste método, compara-se pares de elementos, trocando-os de posição caso estejam
desordenados.
5.4.2.1 Método da Bolha (Bubble Sort)
Cada elemento do vetor é testado com o seguinte, se estiverem fora de ordem
ocorre a troca, isto é repetido até não ocorrer mais trocas. Por exemplo:
Figura 30: Método da Bolha (Bubble Sort)
Observação: Na primeira passagem completa o último elemento esta ordenado, logo na
segunda passagem não é necessário ir até o fim.
Problema: Escreva um programa em Java que ordena (classifica em ordem crescente) um
vetor de números inteiros utilizando o Método da Bolha.
142
Programa exemplo (35): Programa abaixo demonstra a ordenação utilizando o Bubble Sort.
// ---------------------------------------------------------------- Fonte: Dados35.java
package dados35;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
final int QUANT = 10;
int [] v = new int[QUANT];
int [] c = new int[QUANT];
int [] e = new int[QUANT];
int j = 0, n = -1, m, temp;
int chave, endereco;
boolean troca;
Scanner entrada = new Scanner(System.in);
do {
n++;
System.out.print("Número: ");
temp = entrada.nextInt();
if (temp != 0) {
v[n] = temp;
}
else {
n--;
}
} while (temp != 0 && n < QUANT);
for (int i = 0;i <= n;i++) {
c[i] = v[i];
e[i] = i;
}
m = n - 1;
do {
troca = true;
for (int i = 0;i <= m;i++) {
if (c[i] > c[i+1]) {
chave = c[i];
c[i] = c[i+1];
c[i+1] = chave;
endereco = e[i];
e[i] = e[i+1];
e[i+1] = endereco;
j = i;
troca = false;
}
}
m = j;
} while (!troca);
System.out.print("Lista Ordenada: ");
for (int i = 0;i <= n;i++) {
System.out.print(c[i] + " ");
}
System.out.println();
143
}
}
Resultado do Programa:
Número: 20 <enter>
Número: 40 <enter>
Número: 50 <enter>
Número: 30 <enter>
Número: 10 <enter>
Número: 0 <enter>
Lista Ordenada: 10 20 30 40 50
5.4.3 Método por Seleção
Seleção sucessiva do menor valor da tabela. A cada passo o menor
elemento é colocado em sua posição definitiva.
5.4.3.1 Método por Seleção Direta
A cada passo do método é feita uma varredura do segmento que corresponde os
elementos, ainda não selecionados, e determinado o menor elemento o qual é colocado na
primeira posição do elemento por troca. Por exemplo:
Figura 31: Método por Seleção Direta
Problema: Escreva um programa em Java que ordena (classifica em ordem crescente) um
vetor de números inteiros utilizando o Método por Seleção Direta.
Programa exemplo (36): Programa abaixo demonstra a ordenação utilizando o método da
seleção direta.
// ------------------------------------------------------------ Fonte: Dados36.java
package dados36;
144
import java.util.Scanner;
public class Dados36 {
public static void main(String[] args) {
final int QUANT = 10;
int [] v = new int[QUANT];
int [] c = new int [QUANT];
int [] e = new int [QUANT];
Scanner entrada = new Scanner(System.in);
int j, n = -1, min, temp;
int chave, endereco;
do {
n++;
System.out.print("Número: ");
temp = entrada.nextInt();
if (temp != 0) {
v[n] = temp;
}
else {
n--;
}
} while (temp != 0 && n < QUANT);
for (int i = 0;i <= n;i++) {
c[i] = v[i];
e[i] = i;
}
for (int i = 0;i <= n-1;i++) {
min = i;
for (j = i+1;j <= n;j++) {
if (c[j] < c[min]) {
min = j;
}
}
chave = c[i];
c[i] = c[min];
c[min] = chave;
endereco = e[i];
e[i] = e[min];
e[min] = endereco;
}
System.out.print("Lista Ordenada: ");
for (int i = 0;i <= n;i++) {
System.out.printf("%d ", c[i]);
}
System.out.println();
}
}
Resultado do Programa:
Número:
Número:
Número:
Número:
Número:
Número:
20 <enter>
40 <enter>
50 <enter>
30 <enter>
10 <enter>
0 <enter>
145
Lista Ordenada: 10 20 30 40 50
146
6. Árvores
São estruturas de dados não-lineares que caracterizam uma relação entre os
dados, à relação existente entre os dados é uma relação de hierarquia ou de composição
(um conjunto é subordinado a outro).
6.1 Conceitos Básicos
Definição
É um conjunto finito de dados T de um ou mais nós, tais que:
a) Existe um nó principal chamado raiz (root);
b) Os demais nós formam n >= 0 conjuntos disjuntos T1, T2, ... Tn, onde cada um destes
subconjuntos é uma árvore. As árvores Ti (i >= 1 e i <= n) recebem a denominação de
sub-árvores.
Figura 32: Uma árvore genérica
Terminologia
Grau
Indica o número de sub-árvores de um nó.
Figura 33: Grau de uma árvore
Observação: Se um nodo não possuir nenhuma sub-árvore é chamado de nó terminal ou
folha.
147
Nível
É o comprimento da árvore, ou seja, o número de linhas do caminho da raiz até o
nó.
Figura 34: Nível em uma árvore
Observação: Raiz é nível zero (0)
Exemplo:
Figura 35: Representação Hierárquica uma árvore
Altura
É o nível mais alto da árvore. Na árvore acima, a altura é igual a 2.
Floresta
É um conjunto de zero ou mais árvores disjuntas, ou seja, se for eliminado o nó
raiz da árvore, as sub-árvores que restarem chamam-se de florestas.
148
Figura 36: Conceito de Floresta em uma Árvore
Formas de Representação de Árvores
 Representação Hierárquica
Figura 37: Representação Hierárquica de uma Árvore
 Representação por Conjunto (Diagrama de Inclusão ou Composição)
Figura 38: Representação por Conjunto de uma Árvore
 Representação por Expressão Parentetizada (Parênteses Aninhados)
( A ( B ( ) C ( D ( G ( ) H ( ) ) E ( ) F ( I ( ) ) ) ) )
Figura 39: Representação por Expressão Parentetizada de uma Árvore
 Representação por Expressão não Parentetizada
A 2 B 0 C 3 D 2 G 0 H 0 E 0 F 1 I 0
149
Figura 40: Representação por Expressão não Parentetizada de uma Árvore

Representação por Indentação (Digrama de Barras)
Figura 41: Representação por Endentação de uma Árvore
6.2 Árvores Binárias
Uma árvore binária (T) é um conjunto finito de nós que pode ser vazio ou pode
ser dividida em três sub-conjuntos disjuntos: raiz, sub-árvore esquerda (Te) e subárvore direita (Td). São estruturas onde o grau de cada nó é menor ou igual a dois, ou
seja, no máximo grau 2. O número máximo de nós no nível i é 2i.
São árvores onde cada nó tem no máximo dois filhos (grau máximo 2), desta forma,
obtém-se uma estrutura apropriada para busca binária, pois sabe-se que existe, para
cada nodo, duas sub-árvores (Te e Td).
Para cada nó da árvore associa-se uma chave (dado, valor ou informação) que
permite a realização de uma classificação. A construção da árvore deve ser de forma que
na sub-árvore à esquerda (Te) da raiz só existam nós com chaves menores que a chave da
raiz. E a sub-árvore à direita (Td) só pode conter nós com valores maiores que a raiz.
Com esta reestruturação da árvore, a busca de um determinado nó torna-se trivial. O
acesso aos dados pode ser feito então através de funções recursivas.
150
Figura 42: Uma Árvore Binária
Propriedades
1) O número máximo de nodos no k-ésimo nível de uma árvore binária é 2k;
2) O número máximo de nodos em uma árvore binária com altura k é 2k+1-1, para k >= 0;
3) Árvore completa: árvore de altura k com 2k+1-1 nodos.
Exemplo de uma aplicação de Árvore Binária
(Analisador de Expressão):
Expressão: (3 + 6) * (4 – 1) + 5
Figura 43: Expressão representação por uma Árvore Binária
Conversão de Árvore Genérica em Árvore Binária
Ligar os nós irmãos;
Remover a ligação entre o nó pai e seus filhos, exceto as do primeiro filho.
151
Figura 44: Conversão de Árvore Genérica em Árvore Binária
Nota: O nó da sub-árvore à esquerda é filho e o nó da sub-árvore à direita é irmão
6.3 Representações
6.3.1 Representação por Contigüidade Física (Adjacência)
Os nodos são representados seqüencialmente na memória. Devem ser tomados os
seguintes cuidados:
Ser alocado espaço suficiente para armazenar a estrutura completa;
Os nodos devem ser armazenados em uma lista, onde cada nodo i da árvore ocupa o
i-ésimo nodo da lista.
152
Exemplo:
Figura 45: Representação por Adjacência de uma Árvore Binária
Sendo i a posição de um nodo e n o número máximo de nodos da árvore.
Observações (considere a árvore da página anterior):
1) O pai de i está em i / 2 sendo i <= n. Se i = 1, i é a raiz e não possui pai.
2) O filho à esquerda de i está em 2i se 2i <= n. Se 2i > n, então tem filho à
esquerda.
3) O filho à direita de i está em 2i+1. Se 2i+1 <= n. Se 2i+1 > n, então tem filho à
direita.
Observação: Representação por Contigüidade Física não é um modo conveniente para
representar árvores, na maioria dos casos.
Vantagens
Adequado para árvores binárias completas.
Útil para o armazenamento em disco ou fita (seqüencial).
Desvantagens
A estrutura pode ter muitos espaços sem uso.
153

Estrutura possui limite finito no número de nodos.
6.3.2 Representação por Encadeamento
esq
info
dir
esq: endereço do nodo filho à esquerda
info: contém a informação do nodo
dir: endereço do nodo filho à direita
Figura 46: Representação por Encadeamento de uma Árvore Binária
public class Tree {
public Tree esq;
public char info;
public Tree dir;
}
6.4 Caminhamento em Árvores
Consiste em processar de forma sistemática e ordenada cada nó da árvore apenas
uma vez, obtendo assim uma seqüência linear de nós. Abaixo são mostrados os três tipos
de caminhamentos:
6.4.1 Caminhamento Pré-Fixado (Pré-Ordem)
1) Visitar a raiz;
2) Caminhar na sub-árvore da esquerda;
3) Caminhar na sub-árvore a direita.
Ordem do Caminhamento: [RED]
154
Observação: “Visitar” significa qualquer operação relacionada à informação (info) do
nodo.
155
Exemplo:
Caminhamento: ABDECFG
Figura 47: Caminhamento Pré-Fixado (Pré-Ordem)
6.4.2 Caminhamento In-Fixado (Central)
1) Caminhar na sub-árvore da esquerda;
2) Visitar a raiz;
3) Caminhar na sub-árvore da direita.
Ordem do Caminhamento: [ERD]
Exemplo: Conforme exemplo acima, o caminhamento In-Fixado é:
Caminhamento: DBEACGF
Figura 48: Caminhamento In-Fixado (Central)
6.4.3 Caminhamento Pós-Fixado
1) Caminhar na subárvore da esquerda;
2) Caminhar na subárvore da direita;
3) Visitar a raiz.
Ordem do Caminhamento: [EDR]
Exemplo: Conforme exemplo acima, o caminhamento Pós-Fixado é:
156
Caminhamento: DEBGFCA
Figura 49: Caminhamento Pós-Fixado
6.4.4 Algoritmos recursivos para percorrer Árvores Binárias
Algoritmos de busca de dados em estruturas hierárquicas, caminhamentos em
árvores, por exemplo, utilizam, normalmente, recursividade.
Recursividade é uma técnica utilizada em programação quando se deseja que uma
função faça uma chamada a si própria. Este mecanismo utiliza uma estrutura de pilha
para fazer o controle do retorno de todas as chamadas realizadas.
Como vantagens das funções recursivas tem-se:
a) clareza na interpretação do código (funções pequenas);
b) “simplicidade” e elegância na implementação.
Como desvantagens tem-se:
a) dificuldade para encontrar erros (debug);
b) dificuldade de encontrar o critério de parada da função;
c) em alguns casos podem ser ineficientes devido a quantidade de chamadas recursivas.
A chamada de uma função recursiva requer espaço para os parâmetros, variáveis
locais e endereço de retorno. Todas estas informações são armazenadas em uma pilha e
depois desalocadas, ou seja, a quantidade de informações é proporcional ao número de
chamadas. Todas as operações envolvidas na recursividade contribuem para um gasto maior
de tempo, pois a alocação e liberação de memória consomem tempo.
6.4.4.1 Caminhamento Pré-Fixado (Pré-Ordem)
static void caminhamentoPreOrdem(Tree a) {
if (!treeVazia(a)) {
System.out.printf("%c ", a.info);
caminhamentoPreOrdem(a.esq);
157
// mostra raiz
// mostra sub_esq
caminhamentoPreOrdem(a.dir);
// mostra sub_dir
}
}
6.4.4.2 Caminhamento In-Fixado (Central)
static void caminhamentoInFixado(Tree a) {
if (!treeVazia(a)) {
caminhamentoInFixado(a.esq);
// mostra sub_esq
System.out.printf("%c ", a.info); // mostra raiz
caminhamentoInFixado(a.dir);
// mostra sub_dir
}
}
6.4.4.3 Caminhamento Pós-Fixado
static void caminhamentoPosFixado(Tree a) {
if (!treeVazia(a)) {
caminhamentoPosFixado(a.esq);
caminhamentoPosFixado(a.dir);
System.out.printf("%c ", a.info);
}
}
// mostra sub_esq
// mostra sub_dir
// mostra raiz
Problema: Escreva um programa em Java que cria a árvore da página 137. O programa deve
exibir na tela os três tipos de caminhamentos.
Programa exemplo (37): O programa a seguir demonstra os detalhes da implementação de
uma árvore.
// ------------------------------------------------------------- Fonte: Tree.java
package dados37;
public class Tree {
public Tree esq;
public char info;
public Tree dir;
// --------------------------------------------- criaTree
public Tree(Tree esquerda, char informacao, Tree direita) {
esq = esquerda;
info = informacao;
dir = direita;
}
}
// ---------------------------------------------------- Fonte: Dados37.java
package dados37;
158
public class Dados37 {
public static void main(String[] args) {
Tree a1 = new Tree(null,'d',null);
Tree a2 = new Tree(null,'e',null);
Tree a3 = new Tree(a1,'b',a2);
Tree a4 = new Tree(null,'g',null);
Tree a5 = new Tree(a4,'f',null);
Tree a6 = new Tree(null,'c',a5);
Tree a = new Tree(a3,'a',a6);
System.out.printf("Caminhamentos em Árvore\n Pré-Ordem: ");
caminhamentoPreOrdem(a);
System.out.printf("\n In-Fixado: ");
caminhamentoInFixado(a);
System.out.printf("\nPós-Fixado: ");
caminhamentoPosFixado(a);
System.out.println();
}
// --------------------------------------------- treeVazia
static boolean treeVazia(Tree a) {
if (a == null) {
return(true);
}
else {
return(false);
}
}
// --------------------------------------------- caminhamentoPreOrdem
static void caminhamentoPreOrdem(Tree a) {
if (!treeVazia(a)) {
System.out.printf("%c ", a.info); // mostra raiz
caminhamentoPreOrdem(a.esq);
// mostra sub_esq
caminhamentoPreOrdem(a.dir);
// mostra sub_dir
}
}
// --------------------------------------------- caminhamentoInFixado
static void caminhamentoInFixado(Tree a) {
if (!treeVazia(a)) {
caminhamentoInFixado(a.esq);
// mostra sub_esq
System.out.printf("%c ", a.info); // mostra raiz
caminhamentoInFixado(a.dir);
// mostra sub_dir
}
}
// --------------------------------------------- caminhamentoPosFixado
static void caminhamentoPosFixado(Tree a) {
if (!treeVazia(a)) {
caminhamentoPosFixado(a.esq);
// mostra sub_esq
caminhamentoPosFixado(a.dir);
// mostra sub_dir
System.out.printf("%c ", a.info); // mostra raiz
159
}
}
}
Figura 50: Árvore Exemplo
Resultado do Programa:
Caminhamentos na Árvore
Pré-Ordem: a b d e c f g
In-Fixado: d b e a c g f
Pós-Fixado: d e b g f c a
6.5 Árvore de Busca Binária
Uma árvore de busca binária (BST - Binary Search Tree) é uma árvore binária
cujas chaves (informações ou dados) aparecem em ordem crescente quando a árvore é
percorrida em ordem in-Fixado (esquerda -> raiz -> direita, ou seja, caminhamento
ERD). Onde a chave de cada nó da árvore deve ser:
maior ou igual que qualquer chave na sua sub-árvore esquerda;
menor ou igual que qualquer chave na sua sub-árvore direita.
Em outras palavras, a ordem esquerda-raiz-direita das chaves deve ser crescente.
Problema: Escreva um programa em Java que cria a árvore binária ordenada (a, b, c, d,
e, f, g). O programa deve permitir ao usuário buscar o endereço de uma determinada
informação, ou seja, uma letra de ‘a’ até ‘z’.
Programa exemplo (38): O programa a seguir demonstra os detalhes da implementação de
uma árvore.
// ---------------------------------------------------------- Fonte: Tree.java
package dados38;
public class Tree {
public Tree esq;
public char info;
160
public Tree dir;
// --------------------------------------------- criaTree (construtor)
public Tree(Tree esquerda, char informacao, Tree direita) {
esq = esquerda;
info = informacao;
dir = direita;
}
}
// --------------------------------------------------------- Fonte: Dados38.java
package dados38;
import java.util.Scanner;
public class Dados38 {
public static void main(String[] args) {
Tree a1 = new Tree(null,'d',null);
Tree a2 = new Tree(null,'e',null);
Tree a3 = new Tree(a1,'b',a2);
Tree a4 = new Tree(null,'g',null);
Tree a5 = new Tree(a4,'f',null);
Tree a6 = new Tree(null,'c',a5);
Tree a = new Tree(a3,'a',a6);
Scanner entrada = new Scanner(System.in);
Tree tree = new Tree(null, 'x', null);
char info;
System.out.println("In-Fixado: ");
caminhamentoInFixado(a);
System.out.println();
do {
System.out.print("Info [x - abandona]: ");
do {
String s = entrada.nextLine();
info = s.charAt(0);
} while (!(info >= 'a' && info <= 'z') && info != 'x');
if (info != 'x') {
tree = buscaTree(a, info);
if (tree == null) {
System.out.println("Status: Nodo Inválido");
}
else {
System.out.println("Status: Ok, Nodo Válido");
}
}
} while (info != 'x');
}
// --------------------------------------------- treeVazia
static boolean treeVazia(Tree a) {
if (a == null) {
return(true);
}
else {
161
return(false);
}
}
// --------------------------------------------- caminhamentoPreOrdem
static void caminhamentoPreOrdem(Tree a) {
if (!treeVazia(a)) {
System.out.printf("%c ", a.info); // mostra raiz
caminhamentoPreOrdem(a.esq);
// mostra sub_esq
caminhamentoPreOrdem(a.dir);
// mostra sub_dir
}
}
// --------------------------------------------- caminhamentoInFixado
static void caminhamentoInFixado(Tree a) {
if (!treeVazia(a)) {
caminhamentoInFixado(a.esq);
// mostra sub_esq
System.out.printf("%c ", a.info); // mostra raiz
caminhamentoInFixado(a.dir);
// mostra sub_dir
}
}
// --------------------------------------------- caminhamentoPosFixado
static void caminhamentoPosFixado(Tree a) {
if (!treeVazia(a)) {
caminhamentoPosFixado(a.esq);
// mostra sub_esq
caminhamentoPosFixado(a.dir);
// mostra sub_dir
System.out.printf("%c ", a.info); // mostra raiz
}
}
// --------------------------------------------- BuscaTree
static Tree buscaTree(Tree raiz, char chave) {
Tree a1;
if (raiz == null) {
return(null);
}
else {
if (raiz.info == chave) {
// busca na raiz
return(raiz);
}
else {
a1 = buscaTree(raiz.esq, chave);
// busca na sub-árvore esquerda
if (a1 == null) {
a1 = buscaTree(raiz.dir, chave); // busca na sub-árvore direita
}
}
return(a1);
}
}
}
Resultado do Programa:
162
In-Fixado:
d b e a c g f
Info [x - abandona]: b <enter>
Status: Ok, Nodo Valido
Info [x - abandona]: y <enter>
Status: Nodo Invalido
Info [x - abandona]: x <enter>
6.6 Árvore AVL
O objetivo principal na utilização de árvores AVL é diminuir o custo de acesso
as informações desejadas, ou seja, organizar a árvore de forma a otimizar a busca em
uma árvore binária.
Os algoritmos de árvore AVL são muito parecidos com os algoritmos de uma árvore
binária, a diferença está no esforço necessário para se manter uma árvore AVL
balanceada.
Para manter uma árvore balanceada, precisa-se constante-mente refazer a
estrutura da árvore nas operações de inserção ou exclusão de elementos. Árvores AVL, B
e B++ são árvores balanceadas.
Balanceamento em Árvores
Diz-se que uma árvore está balanceada (equilibrada), se todos os nós folhas
estão à mesma distância da raiz, ou seja, uma árvore é dita balanceada quando as suas
sub-árvores à esquerda e à direita possuem a mesma altura. Quando uma árvore não está
balanceada, chama-se degenerada.
Figura 51: Árvore Balanceada
O balanceamento de uma árvore binária pode ser: estático ou dinânico (AVL). O
balanceamento estático de uma árvore binária consiste em construir uma nova versão da
árvore, reorganizando-a, enquanto que no balanceamento dinâmico (AVL) a cada nova
operação realizada na árvore binária, ela sobre rotações deixando-a balanceada.
O termo AVL foi colocado em homenagem aos matemáticos russos Adelson-Velskii e
Landis.
Adelson-Velskii e Landis em 1962 apresentaram uma árvore de busca binária que é
balanceada levando-se em consideração a altura das suas sub-árvores, ou seja, uma
árvore AVL é uma árvore binária de pesquisa onde a diferença em altura entre as subárvores esquerda e direita é no máximo 1 (positivo ou negativo).
163
Está diferença é chamado de fator de balanceamento (fb). Este fator deve ser
calculado para todos os nós da árvore binária. O fator de balanceamento de um nó folha
é sempre zero, ou seja, fb = 0.
O fator de balanceamento (fb) é um número inteiro igual a:
fb (nodo) = altura (subárvore direita) – altura (subárvore esquerda);
Definição: Uma árvore binária vazia é sempre balanceada por altura. Se T não é vazia e
Te e Td são sub-árvores da esquerda e direita, respectivamente, então T é balanceada
por altura se: a) Te e Td são balanceadas por altura; b) altura Te – altura Td for
igual a 0, 1 ou -1.
6.6.1 Inserção em uma árvore AVL
Quando um novo elemento é inserido em uma árvore binária, é necessário verificar
se esta inserção quebrou a propriedade de balanceamento da árvore, ou seja, é
necessário calcular o fator de balanceamento dos nodos da árvore. Se o Fb de algum nodo
for diferente de 0, 1 ou -1, é necessário reestruturar a árvore para que volte a ser
balanceada.
Na inserção de um nodo em uma árvore AVL, pode-se ter quatro situações
distintas, cuja a forma de tratamento é diferente:
164
a) Inserção dos nós: 10, 20 e 30
b) Inserção dos nós: 30, 20 e 10
c) Inserção dos nós: 10, 30 e 20
d) Inserção dos nós: 30, 10 e 20
Note que nas quatro situações acima (a, b, c e d), o fator de balanceamento de
algum nodo ficou fora da faixa [-1..1], ou seja, algum nodo teve o Fator de
Balanceamento (Fb) 2 ou -2.
165
Para cada caso acima, aplica-se um tipo de rotação a árvore:
166
a) Rotação simples à esquerda
b) Rotação simples à direita
c) Rotação dupla à esquerda
(rotação simples à direita + rotação simples à esquerda)
167
d) Rotação dupla à direita
(rotação simples à esquerda + rotação simples à direita)
Dicas:
a) Para identificar quando uma rotação é simples ou dupla deve-se observar os sinais do
Fb:
• Sinal for igual, a rotação é simples
• Sinal for diferente a rotação é dupla
b) Se Fb for positivo (+) a rotação para à esquerda
c) Se Fb for negativa (-) a rotação para à direita
Problema: Escreva um programa em Java que cria uma árvore binária balanceada utilizando
as características de uma árvore AVL (10, 20, 30, 40, ...). O programa deve permitir a
entrada de números inteiros até que o usuário digite zero (0). Ao final a árvore é
exibida.
Programa exemplo (39): O programa a seguir demonstra os detalhes de uma árvore binária
balanceada.
// ----------------------------------------------------------- Fonte: AvlNode.java
package Dados39;
class AvlNode {
AvlNode esq;
int info;
AvlNode dir;
int altura;
// ----------------------------------------- Construtor
AvlNode(int info) {
this(null, info, null);
}
// ----------------------------------------- Construtor
168
AvlNode(AvlNode esquerda, int info, AvlNode direita) {
this.esq = esquerda;
this.info = info;
this.dir = direita;
this.altura = 0;
}
}
// ---------------------------------------------------------- Fonte: AvlTree.java
package Dados39;
public class AvlTree {
// -------------------------------------------- maxAVL
private static int maxAVL(int a, int b) {
if (a > b) {
return(a);
}
else {
return(b);
}
}
// -------------------------------------------- alturaAVL
private static int alturaAVL(AvlNode t) {
if (t == null) {
return(-1);
}
else {
return(t.altura);
}
}
// -------------------------------------------- rotacaoEsquerdaAVL
private static AvlNode rotacaoEsquerdaAVL( AvlNode nodoOut) {
AvlNode nodoIn = nodoOut.esq;
int a, b;
nodoOut.esq = nodoIn.dir;
nodoIn.dir = nodoOut;
a = AvlTree.alturaAVL(nodoOut.esq);
b = AvlTree.alturaAVL(nodoOut.dir);
nodoOut.altura = AvlTree.maxAVL(a, b) + 1;
a = AvlTree.alturaAVL(nodoIn.esq);
b = nodoOut.altura;
nodoIn.altura = AvlTree.maxAVL(a, b) + 1;
return(nodoIn);
}
// -------------------------------------------- rotacalDireitaAVL
private static AvlNode rotacaoDireitaAVL( AvlNode nodoOut) {
AvlNode nodoIn = nodoOut.dir;
int a, b;
169
nodoOut.dir = nodoIn.esq;
nodoIn.esq = nodoOut;
a = AvlTree.alturaAVL(nodoOut.esq);
b = AvlTree.alturaAVL(nodoOut.dir);
nodoOut.altura = AvlTree.maxAVL(a, b) + 1;
a = AvlTree.alturaAVL(nodoIn.dir);
b = nodoOut.altura;
nodoIn.altura = AvlTree.maxAVL(a, b) + 1;
return(nodoIn);
}
// -------------------------------------------- rotacaoDuplaEsquerdaAVL
private static AvlNode rotacaoDuplaEsquerdaAVL(AvlNode nodo) {
nodo.esq = AvlTree.rotacaoDireitaAVL(nodo.esq);
return(AvlTree.rotacaoEsquerdaAVL(nodo));
}
// -------------------------------------------- rotacaoDuplaDireitaAVL
private static AvlNode rotacaoDuplaDireitaAVL(AvlNode nodo) {
nodo.dir = AvlTree.rotacaoEsquerdaAVL(nodo.dir);
return(AvlTree.rotacaoDireitaAVL(nodo));
}
private AvlNode raiz;
// -------------------------------------------- Construtor
public AvlTree() {
this.raiz = null;
}
// -------------------------------------------- inserteAVL
public void insertAVL(int info) {
this.raiz = insertAVL(info, this.raiz);
}
// -------------------------------------------- inserteAVL (sobreCarga)
private AvlNode insertAVL( int x, AvlNode avl) {
int a, b;
if (avl == null) {
avl = new AvlNode(null, x, null);
}
else {
if (x > avl.info) {
avl.dir = insertAVL(x, avl.dir);
a = AvlTree.alturaAVL(avl.dir);
b = AvlTree.alturaAVL(avl.esq);
if (a - b == 2) {
if (x > avl.dir.info) {
avl = AvlTree.rotacaoDireitaAVL(avl);
}
else {
avl = AvlTree.rotacaoDuplaDireitaAVL(avl);
170
}
}
}
else {
if (x < avl.info) {
avl.esq = insertAVL(x, avl.esq);
a = AvlTree.alturaAVL(avl.esq);
b = AvlTree.alturaAVL(avl.dir);
if (a - b == 2) {
if (x < avl.esq.info) {
avl = AvlTree.rotacaoEsquerdaAVL(avl);
}
else {
avl = AvlTree.rotacaoDuplaEsquerdaAVL(avl);
}
}
}
}
}
a = AvlTree.alturaAVL(avl.esq);
b = AvlTree.alturaAVL(avl.dir);
avl.altura = AvlTree.maxAVL(a, b) + 1;
return(avl);
}
// -------------------------------------------- vaziaAVL
public boolean vaziaAVL() {
return this.raiz == null;
}
// -------------------------------------------- exibeAVL
public void exibeAVL() {
if (vaziaAVL()) {
System.out.println("Status: AVL Vazia");
} else {
exibeAVL(this.raiz, 1);
}
}
// -------------------------------------------- exibeAVL (SobreCarga)
private void exibeAVL(AvlNode avl, int t) {
if (avl != null) {
exibeAVL(avl.dir, t + 1);
for (int i = 0;i < t;i++) {
System.out.printf(" ");
}
System.out.printf("%d \n",avl.info);
exibeAVL(avl.esq, t + 1);
}
}
}
// -------------------------------------------------------- Fonte: Dados39.java
package Dados39;
171
import java.util.Scanner;
public class AVL {
public static void main(String [] args) {
Scanner entrada = new Scanner(System.in);
AvlTree avl = new AvlTree();
int x;
do {
System.out.print("Info: ");
x = entrada.nextInt();
if (x != 0) {
avl.insertAVL(x);
}
} while (x != 0);
avl.exibeAVL();
}
}
Resultado do Programa:
Info:
Info:
Info:
Info:
Info:
Info:
20 <enter>
30 <enter>
10 <enter>
40 <enter>
50 <enter>
0 <enter>
50
40
30
20
10
Programa online que demonstra inserções e remoções em uma árvore AVL:
http://www.site.uottawa.ca/~stan/csi2514/applets/avl/BT.html
6.6.2 Remoção em uma árvore AVL
Quando um elemento é removido de uma árvore balanceada AVL, é necessário
verificar se esta operação quebrou a propriedade de balanceamento da árvore, ou seja, é
necessário calcular o Fator de Balanceamento dos nodos da árvore. Se o Fb de algum nodo
for diferente de 0, 1 ou -1, é necessário reestruturar a árvore para que volte a ser
balanceada.
Na remoção de um nodo em uma árvore AVL, pode-se ter quatro situações distintas,
cuja a forma de tratamento é diferente:
a) Remoção do nó: 10
172
Resultado: Com a remoção do nodo 10 a árvore ficará desbalanceada, pois o nodo raiz
ficará com Fb = 2. A solução será fazer uma rotação simples à esquerda.
b) Remoção do nó: 40
Resultado: Com a remoção do nodo 40 a árvore ficará desbalanceada, pois o nodo raiz
ficará com Fb = -2. A solução será fazer uma rotação simples à direita.
c) Remoção do nó: 10
Resultado: Com a remoção do nodo 10 a árvore ficará desbalanceada, pois o nodo raiz
ficará com Fb = 2. A solução será fazer uma rotação dupla à esquerda (rotação simples à
direita + rotação simples à esquerda).
173
d) Remoção do nó: 40
Resultado: Com a remoção do nodo 40 a árvore ficará desbalanceada, pois o nodo raiz
ficará com Fb = 2. A solução será fazer uma rotação dupla à direita (rotação simples à
esquerda + rotação simples à direita).
174
7. Grafos
7.1 Conceitos
Um grafo G é definido como G (V, A) onde V é um conjunto finito e não vazio de
vértices e A é um conjunto finito de arestas, ou seja, linhas, curvas ou setas que
interligam dois vértices.
“Grafo é um par ordenado de conjuntos disjuntos (V, A), onde V é um conjunto
arbitrário que se designa por conjunto dos vértices e A um subconjunto de pares não
ordenados de elementos (distintos) de V que se designa por conjunto das arestas.”
Um vértice é representado por um ponto ou círculo representando um nó, nodo ou
informação. Uma aresta pode ser uma reta, seta ou arco representando uma relação entre
dois nodos.
Figura 52: Um Grafo
Quando uma aresta possui indicação de sentido (uma seta), ela é chamada de arco,
caso contrário é chamada de linha (veja grafo acima).
Orientação é a direção para a qual uma seta aponta, um grafo deste tipo é
chamado grafo dirigido ou orientado.
G(4,7) – 4 vértices e 7 arestas
175
Figura 53: Grafo com 4 vértices e 7 arestas
Cardinalidade (ordem) de um conjunto de vértices é igual a quantidade de seus
elementos. Grafo denso possui alta cardinalidade de vértices, enquanto que grafo pouco
povoado possui baixa cardinalidade.
A ordem (V) de um grafo G é o número de vértices do grafo enquanto que a
dimensão (A) é o número de arestas do grafo. No exemplo acima, a ordem do grafo é 4
enquanto que a dimensão é 7.
Figura 54: Grafo
O conjunto de arcos do grafo acima é:
1
{<A,A>, <A,B>, <A,C>, <A,D>, <C,D>, <F,C>, <F,G>, <D,F>}
2
3
4
5
6
7
8
Um vértice que não possui nenhuma aresta incidente é chamado de isolado (figura
abaixo). Um grafo com nenhum vértice é chamado de vazio.
Figura 55: Vértice Isolado
Passeio é uma seqüência de vértices e arestas onde o caminho é um passeio sem
vértices repetidos (seqüência de vértices em que cada dois vértices consecutivos são
ligados por um arco). Trajeto é um passeio sem arestas repetidas.
176
Passeio é uma seqüência <v0, a1, v1, a2, ..., vk-1, ak, vk> onde v0, v1,....,vk
são vértices, a1, a2,...., ak são arcos e, para cada (i, ai) é um arco de vi-1 a vi. O
vértice v0 é o início do passeio e o vértice vk é o seu término.
Um caminho é um passeio sem vértices repetidos. A dimensão de um caminho ou
trajeto é chamado de comprimento.
Ciclo é um caminho de comprimento não nulo fechado, ou seja, tem os vértices
extremos iguais (é um passeio onde v0 = vk.). Circuito é um trajeto de comprimento não
nulo fechado (é um ciclo sem vértices, com exceção feita a v0 e vk).
Laço é uma aresta que retorna ao mesmo vértice. Se a aresta não tiver seta ela é
dita sem orientação. Diz-se que uma aresta é incidente com os vértices que ela liga,
não importando a orientação. Dois vértices são adjacentes se estão ligados por uma
aresta. Um vértice é dito isolado se não existe aresta incidente sobre ele. Duas
arestas incidentes nos mesmos vértices, não importando a orientação, a1 = (v,w) e a2 =
(v,w), então as arestas são paralelas.
Diz-se que o grafo é conexo se para cada par de vértices existe pelo menos um
passeio que os une.
Chama-se grafo não-orientado ou não-dirigido se as arestas representam
relacionamento nas duas direções, ou seja, as arestas não possuem uma seta indicando
sentido.
Figura 56: Grafo não-orientado e não-dirigido
177
Grafo não-orientado ou não-dirigido
V = { Paulo, Adriane, Paola, Roberta }
A = { (Paulo, Adriane) , (Paulo, Paola) , (Adriane, Paola) , (Adriane, Roberta) }
Explicação do grafo acima: O exemplo representa uma relação de amizade, ou seja, se
Paulo é amigo de Adriane o inverso é verdade, isto se chama: relação simétrica.
Quando um grafo possui arcos (seta indicando uma direção) ele é denominado grafo
dirigido ou dígrafo (veja Figura 57).
Figura 57: Grafo dirigido ou Dígrafo
Grafo dirigido ou dígrafo
Explicação do grafo acima: O exemplo representa uma relação de subordinação, ou
seja, se “Paulo” é chefe de “Adriane” o inverso não é verdade, isto se chama:
relação não-simétrica.
Grau de um vértice, em um grafo não-dirigido, é o número de arestas incidentes
ao vértice. Em um grafo dirigido, pode-se dividir o grau em dois: grau de emissão
(número de arestas que saem do vértice) e grau de recepção (número de arestas que
chegam no vértice).
Toda árvore é um grafo, mas nem todo grafo é uma árvore. Um grafo onde existe um
número associado a cada arco (peso) é chamado de rede ou grafo ponderado. Um exemplo
deste tipo é um grafo representando cidades e distâncias entre as cidades (veja figura
abaixo).
178
Figura 58: Grafo Ponderado
Grau de um Vértice: É igual ao número de arestas que são incidentes ao vértice. Um laço
é contado duas vezes.
Figura 59: Láco em um Grafo
No exemplo acima, o vértice A tem grau 3 enquanto que o vértice B tem grau 1. Em
um grafo dirigido o grau de um vértice é a soma do número de arestas que saem e chegam
no vértice.
Tipos de Grafos
a) Simples: É um grafo que não possui laços nem arestas paralelas.
Figura 60: Grafo Simples
b) Dirigido (dígrafo ou direcionado): Consiste de dois conjuntos finitos:
a) vértices e b) arestas dirigidas, onde cada aresta é associada a um par ordenado de
vértices chamados de nós terminais.
179
Figura 61: Grafo Dirigido
c) Completo: Um grafo completo de n vértices, denominado Kn, é um grafo simples com n
vértices v1, v2, . . . , vn, cujo conjunto de arestas contém exatamente uma aresta para
cada par de vértices distintos.
Figura 62: Grafo Completo
d) Ciclo: Um grafo ciclo de n vértices, denominado C n, onde n é maior ou igual a 3, é
um grafo simples com n vértices v 1, v2, . . . , vn, e arestas v1v2, v2v3, . . ., vn−1vn,
vnv1.
Figura 63: Ciclo em um Grafo
e) Multigrafo: É um grafo que não possui laços, mas pode ter arestas paralelas.
180
Figura 64: Multigrafo
f) Valorado: É um grafo em que cada aresta tem um valor associado (peso), ou seja,
possui um conjunto de valores (pesos) associados a cada aresta.
Figura 65: Grafo Valorado
g) Planar: É um grafo onde não há cruzamento de arestas.
Figura 66: Grafo Planar
h) Imersível: Um grafo é imersível em uma superfície S se puder ser representado
geograficamente em S de tal forma que arestas se cruzem nas extremidades (vértices). Um
grafo planar é um grafo que é imersível no plano. Um exemplo de grafo imersível é a
representação das conexões de uma placa de circuito impresso, onde as arestas não podem
se cruzar, ou seja, os cruzamentos são permitidos apenas nas extremidades.
i) Regular: Um grafo é regular quando todos os seus vértices têm o mesmo grau. Grafos
completos com 2, 3, 4, e 5 vértices são grafos regulares.
181
Figura 67: Grafo Regular
Grafos podem ser representados de duas formas: Matriz de Adjacências (forma
apropriada para representar grafos densos) ou Lista de Adjacências (forma apropriada
para representar grafos esparsos).
182
7.2 Representação por Lista e Matriz de Adjacências
7.2.1 Lista de Adjacências
...
Um grafo pode ser representado por uma lista Adjacente[vi] = [va, vb] onde va, vb,
representam os vértices que se relacionam com o vértice vi.
Lista de Adjacências para um grafo dirigido:
Figura 68: Lista de Adjacências (Grafo Dirigido)
Lista de Adjacências para um grafo não-dirigido:
Figura 69: Lista de Adjacências (Grafo não-Dirigido)
7.2.2 Matriz de Adjacências
Um grafo pode ser representado por uma matriz A = (aij), onde aij representa o
número de arestas de vi para vj.
Matriz de Adjacências para um grafo dirigido:
183
Figura 70: Matriz de Adjacências (Grafo Dirigido)
Matriz de Adjacências para um grafo não-dirigido:
Figura 71: Matriz de Adjacências (Grafo não-Dirigido)
7.3 Percurso em Amplitude e Percurso em Profundidade
Existem dois critérios para percorrer grafos: Percurso em Amplitude e Percurso
em Profundidade.
Em ambos os percursos parte-se de um nodo qualquer escolhido arbitrariamente e
visita-se este nodo. A seguir, considera-se cada um dos nodos adjacentes ao nodo
escolhido.
Percurso em amplitude ou caminhamento em amplitude:
a) Seleciona-se um vértice para iniciar o caminhamento.
b) Visitam-se os vértices adjacentes, marcando-os como visitados.
c) Coloca-se cada vértice adjacente numa fila.
184
d) Após visitar os vértices adjacentes, o primeiro da fila torna-se o novo vértice
inicial. Reinicia-se o processo.
e) O caminhamento termina quanto todos os vértices tiverem sido visitados ou o
vértice procurado for encontrado.
Percurso em profundidade ou caminhamento em profundidade:
a) Seleciona-se um vértice para iniciar o caminhamento.
b) Visita-se um primeiro vértice adjacente, marcando-o como visitado.
c) Coloca-se o vértice adjacente visitado numa pilha.
d) O vértice visitado torna-se o novo vértice inicial.
e) Repete-se o processo até que o vértice procurado seja encontrado ou não haja mais
vértices adjacentes. Se verdadeiro, desempilha-se o topo e procura-se o próximo
adjacente, repetindo o algoritmo.
f) O processo termina quando o vértice procurado for encontrado ou quando a pilha
estiver vazia e todos os vértices tiverem sido visitados.
7.4 Determinação do Caminho Mínimo
O caminho de um vértice a outro vértice é mínimo se não existe outro
caminho entre eles que tenha menos arcos.
O problema de encontrar o caminho mais curto entre dois nós de um grafo
ou uma rede é um dos problemas clássicos da Ciência da Computação. Este problema
consiste, genericamente, em encontrar o caminho de menor custo entre dois nós da
rede, considerando a soma dos custos associados aos arcos percorridos.
O mais famoso algoritmo para resolver o problema de caminho mínimo em
grafos é o algoritmo de Dijkstra (1959). Este algoritmo apenas funciona se os
custos associados aos arcos não forem negativos, mas isso não é muito importante
na maioria dos problemas práticos pois, em geral, os custos associados aos arcos
são em geral grandezas fisicamente mensuráveis.
7.4.1 Algoritmo de Dijkstra
Dado um grafo, G=(V,E) , dirigido ou não, com valores não negativos em cada arco
ou ramo, utiliza-se o algoritmo de Dijkstra para encontrar a distância mínima entre um
vértice inicial (s) e um vértice final (v). Ele determina a distância mínima entre s e
os outros vértices na ordem dessas distâncias mínimas, ou seja, os vértices que se
encontram mais próximos de s em primeiro lugar.
O algoritmo vai usar dist(v), uma estrutura que armazena e referencia a
distância de s ao nó v. De início, dist(s)=0 , pois a menor distância de s a si mesmo
será sempre zero.
O símbolo LIMITE representa um valor maior que o comprimento de qualquer caminho
sem ciclos em G. Por outro lado, se dist(v) = LIMITE, indica que ainda não foi
185
encontrado nenhum caminho com distância mínima entre s e v. De início,
LIMITE. Será utilizado um conjunto S que contém os vértices cuja distância a
e conhecida naquele momento da execução do algoritmo. Esta distância será
para cada um deles. Este conjunto será de início constituído somente pelo
dist(s) = 0.
186
dist(v) =
s é mínima
definitiva
nó s, com
Descrição do Algoritmo
Começa-se considerando a distância ao próprio s como zero. Faze-se então
dist(s)= 0. Para todos os outros vértices, considera-se a sua distância a s como
valendo LIMITE. Fazer então dist(v) = LIMITE.
O processo de introdução de um nó Vn não pertencente a S, assumindo portanto que
V(S) é diferente do conjunto vazio, consiste no seguinte:
1. Qualquer um que seja Vm não pertencente a S tal que v foi o último nó a 'entrar' em
S e (V, Vm) pertencente ao conjunto V, se dist(Vm) > dist(V) + distância associada a
(V,Vm) então dist(Vm) = dist(V) + distância associada a (V, Vm);
2. Determinar qualquer que seja Vm não pertencente a S o menor de entre os valores de
dist(vm). Seja dist(vj) esse valor;
3. Fazer Vn = Vj , dist(Vn) = dist(Vj) e Vn passa a ser o novo elemento de S;
Se o vértice vn coincidir com o vértice final então dist(Vn) é a menor distância entre
s e Vn , e parar a execução. Se não coincidir, voltam-se a repetir os passos 1 , 2 e 3.
Se não for possível aplicar aqueles passos, ou porque V(S) igual ao conjunto
vazio ou qualquer que seja Vm não pertencente a S então (V, Vm) não pertence ao
conjunto V, então não é possível determinar a distância mínima de s ao vértice final.
Problema: Escreva um programa em Java que cria um grafo representando a ligação entre
seis cidades com suas respectivas distâncias (São Paulo, Rio de Janeiro, Vitória,
Recife, Salvador e Natal). O programa deve permitir a entrada da cidade origem (0..5) e
da cidade destino (0..5) e exibir o caminho mínimo entre estas duas cidades através da
utilização do Algoritmo de Dijkstra.
187
Figura 72: Grafo Valorado
Programa exemplo (40): O programa a seguir exibe o caminho mínimo entre duas cidades
qualquer (se existir) através da utilização do algoritmo de Dijkstra.
// -------------------------------------------------------------- Fonte: Grafo.java
package dados40;
public class Grafo {
final int maxVertices = 6;
final int limite = 32767;
int [][] valor = new int[maxVertices][maxVertices];
char [][] adj = new char[maxVertices][maxVertices];
String [] rotulos = {"Spa", "Rio", "Vit", "Rec", "Sal", "Nat"};
// ------------------------------------ inicializaGrafo
public void inicializaGrafo() {
for (int l = 0; l < maxVertices; l++) {
for (int c = 0; c < maxVertices; c++) {
valor[l][c] = limite;
adj[l][c] = 'N';
}
}
}
// ------------------------------------ criaAresta
public void criaAresta(int
adj[origem][destino] =
valor[origem][destino]
adj[destino][origem] =
valor[destino][origem]
}
origem, int destino, int info) {
'S';
= info;
'S';
= info;
// ------------------------------------ imprimeGrafo
public void imprimeGrafo () {
for (int l = 0; l < maxVertices; l++) {
System.out.printf(" %d", l);
}
newline();
for (int l = 0; l < maxVertices; l++) {
System.out.printf(" %s", rotulos[l]);
}
newline();
}
// ------------------------------------ imprimeMatriz
public void imprimeMatriz() {
System.out.printf("Matriz de Adjacencias\n");
for (int l = 0; l < maxVertices; l++) {
for (int c = 0; c < maxVertices; c++) {
System.out.printf("%5d ",valor[l][c]);
}
newline();
188
}
newline();
}
// ---------------------------------------------- dijkstra
public void dijkstra(int origem, int destino, int [] precede) {
int k, result;
int aux1, aux2;
int [] distancia = new int[maxVertices];
boolean [] menorCaminho = new boolean[maxVertices];
int atual, dc, menordist, novadist;
char parar = 'N';
for (int i = 0; i < maxVertices; i++) {
distancia[i] = limite;
menorCaminho [i] = false;
precede[i] = -1;
}
menorCaminho [origem] = true;
distancia[origem] = 0;
atual = origem;
k = atual;
while (atual != destino && parar == 'N') {
menordist = limite;
dc = distancia[atual];
for (int i = 0; i < maxVertices; i++) {
if (menorCaminho [i] == false) {
if (adj[atual][i] =='S') {
novadist = dc + valor[atual][i];
}
else {
novadist = valor[atual][i];
}
if (novadist < distancia[i]) {
distancia[i] = novadist;
precede[i] = atual;
}
if (distancia[i] < menordist) {
menordist = distancia[i];
k = i;
}
}
}
if (atual == k) {
parar = 'S';
}
else {
atual = k;
menorCaminho[atual] = false;
}
}
result = distancia[destino];
if (result == limite || result == 0) {
System.out.printf("\nNão há trajeto entre %s e %s",
rotulos[origem], rotulos[destino]);
}
else {
System.out.printf("\nMenor caminho entre %s e %s = %d",
189
rotulos[origem], rotulos[destino], result);
System.out.printf("\nCaminho INVERSO Percorrido: ");
aux1 = precede[destino];
aux2 = destino;
while (aux1 != origem) {
System.out.printf("\n %s -> %s (%d)",
rotulos[aux2],
aux2 = aux1;
aux1 = precede[aux1];
System.out.printf("\n %s -> %s (%d)",
rotulos[aux2],
rotulos[aux1],
valor[aux1][aux2]);
rotulos[aux1],
valor[aux1][aux2]);
}
}
}
// ------------------------------------ imprimeCidades
public void imprimeCidades() {
String [] cidades = {"[0] - (Spa) - Sao Paulo",
"[1] - (Rio) - Rio de janeiro",
"[2] - (Vit) - Vitoria",
"[3] - (Rec) - Recife",
"[4] - (Sal) - Salvador",
"[5] - (Nat) - Natal"};
for (int i = 0;i < maxVertices;i++) {
System.out.printf("%s\n",cidades[i]);
}
newline();
}
// ------------------------------------ newline
public void newline() {
System.out.println();
}
}
// ------------------------------------------------------ Fonte: Dados40.java
package dados40;
import java.util.Scanner;
public class Dados40 {
public static void main(String[] args) {
final int maxVertices = 6;
final int limite = 32767;
Grafo grafo = new Grafo();
int [] precede = new int [maxVertices];
char tecla;
int origem, destino;
Scanner entrada = new Scanner(System.in);
String s;
grafo.inicializaGrafo();
190
grafo.criaAresta(0, 1, 300);
grafo.criaAresta(0, 3, 400);
grafo.criaAresta(0, 4, 100);
grafo.criaAresta(1, 2, 100);
grafo.criaAresta(1, 5, 70);
grafo.criaAresta(2, 3, 50);
grafo.criaAresta(4, 5, 50);
grafo.criaAresta(3, 5, 150);
do {
grafo.imprimeMatriz();
grafo.imprimeCidades();
grafo.imprimeGrafo();
int tam = maxVertices - 1;
System.out.printf("\n Origem [0..%d]: ", tam);
do {
s = entrada.nextLine();
origem = Integer.parseInt(s);
} while (origem < 0 || origem > tam);
System.out.printf("Destino [0..%d]: ", tam);
do {
s = entrada.nextLine();
destino = Integer.parseInt(s);
} while (destino < 0 || destino > tam);
grafo.dijkstra(origem, destino, precede);
System.out.println();
System.out.printf("\nRepetir [S/N]? ");
do {
s = entrada.nextLine();
tecla = s.charAt(0);
} while (!strChr("SsNn", tecla));
} while (strChr("Ss",tecla));
System.exit(0);
}
// ----------------------------------------------------- strChr
static boolean strChr(String s, char ch) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ch) {
return(true);
}
}
return(false);
}
}
Resultado do Programa:
Matriz de Adjacencias
32767 300 32767 400 100 32767
300 32767 100 32767 32767 70
32767 100 32767 50 32767 32767
400 32767 50 32767 32767 150
100 32767 32767 32767 32767 50
32767 70 32767 150 50 32767
[0] - (Spa) - Sao Paulo
191
[1]
[2]
[3]
[4]
[5]
-
(Rio)
(Vit)
(Rec)
(Sal)
(Nat)
-
Rio de janeiro
Vitoria
Recife
Salvador
Natal
0
1
2
3
4
5
Spa Rio Vit Rec Sal Nat
Origem [0..%d]: 0 <enter>
Destino [0..%d]: 5 <enter>
Menor caminho entre Spa e Nat = 150
Caminho INVERSO Percorrido:
Sal -> Nat(50)
Spa -> Sal(100)
Repetir [S/N]? n
192
8. Programas exemplos
A seguir serão vistos alguns exemplos da utilização das estruturas de dados
vistas neste livro.
8.1 Torre de Hanoi (Pilha - Stack)
A seguir é visto a implementação de uma Torre de Hanoi em Java usando a classe
Stack (Pilha).
Regras do Jogo:
a)
b)
Não se pode colocar um disco grande sobre um disco pequeno
Ganha quando trocar todos os três discos de uma torre para outra
// -------------------------------------------------- Fonte: Torre.java
package torre;
import java.util.Stack;
import java.util.Scanner;
public class Torre {
public static void main(String[] args) {
193
Scanner entrada = new Scanner(System.in);
String s;
int in, out;
Stack p1 = new Stack();
Stack p2 = new Stack();
Stack p3 = new Stack();
boolean ganhou = false, moveu = false;
p1.push(3);
p1.push(2);
p1.push(1);
exibePilhas(p1, p2, p3);
do {
do {
System.out.print("Move: ");
s = entrada.nextLine();
in = Integer.parseInt(s);
if (in == 0) {
System.exit(0);
}
} while (in < 1 || in > 3);
do {
System.out.print("Para: ");
s = entrada.nextLine();
out = Integer.parseInt(s);
if (in == 0) {
System.exit(0);
}
} while (out < 1 || out > 3);
if (testaMovimento(p1, p2, p3, in)) {
if (testaMaior(p1, p2, p3, in, out)) {
moveu = movePilha(p1, p2, p3, in, out);
}
}
exibePilhas(p1, p2, p3);
if (moveu) {
ganhou = testaVitoria(p1);
if (ganhou) {
System.out.println("Status: VENCEDOR (p1)");
System.exit(0);
}
ganhou = testaVitoria(p2);
if (ganhou) {
System.out.println("Status: VENCEDOR (p2)");
System.exit(0);
}
ganhou = testaVitoria(p3);
if (ganhou) {
System.out.println("Status: VENCEDOR (p3)");
System.exit(0);
}
}
} while (true);
}
// -------------------------------------------- testaVitoria
static boolean testaVitoria(Stack p1) {
int a, b, c;
194
a = p1.search(1);
b = p1.search(2);
c = p1.search(3);
if (a != -1 && b != -1 && c != -1) {
return(true);
}
else {
return(false);
}
}
// -------------------------------------------- testaMaior
static boolean testaMaior(Stack p1, Stack p2, Stack p3, int in, int out) {
Object nodo;
int a = 0, b = 0;
switch (in) {
case 1: nodo = p1.peek();
a = nodo.hashCode();
break;
case 2: nodo = p2.peek();
a = nodo.hashCode();
break;
case 3: nodo = p3.peek();
a = nodo.hashCode();
break;
}
switch (out) {
case 1: if (p1.empty()) {
return(true);
}
else {
nodo = p1.peek();
b = nodo.hashCode();
}
break;
case 2: if (p2.empty()) {
return(true);
}
else {
nodo = p2.peek();
b = nodo.hashCode();
}
break;
case 3: if (p3.empty()) {
return(true);
}
else {
nodo = p3.peek();
b = nodo.hashCode();
}
break;
}
if (a < b)
return(true);
else {
return(false);
195
}
}
// -------------------------------------------- testaMovimento
static boolean testaMovimento(Stack p1, Stack p2, Stack p3, int in) {
boolean pode = false;
switch (in) {
case 1: if (p1.empty()) {
System.out.println("Status: Impossivel mover (p1)");
}
else {
pode = true;
}
break;
case 2: if (p2.empty()) {
System.out.println("Status: Impossivel mover (p2)");
}
else {
pode = true;
}
break;
case 3: if (p3.empty()) {
System.out.println("Status: Impossivel mover (p3)");
}
else {
pode = true;
}
break;
}
return(pode);
}
// -------------------------------------------- movePilha
static boolean movePilha(Stack p1, Stack p2, Stack p3, int a, int b) {
Object nodo;
int in = 0;
boolean moveu = false;
switch (a) {
case 1: if (!p1.empty()) {
nodo = p1.pop();
in = nodo.hashCode();
}
else {
in = 0;
}
break;
case 2: if (!p2.empty()) {
nodo = p2.pop();
in = nodo.hashCode();
}
else {
in = 0;
}
break;
case 3: if (!p3.empty()) {
196
nodo = p3.pop();
in = nodo.hashCode();
}
else {
in = 0;
}
break;
}
if (in != 0) {
switch (b) {
case 1: p1.push(in);
moveu = true;
break;
case 2: p2.push(in);
moveu = true;
break;
case 3: p3.push(in);
moveu = true;
break;
}
}
return(moveu);
}
// -------------------------------------------- exibePilhas
static void exibePilhas(Stack
System.out.println("p1: "
System.out.println("p2: "
System.out.println("p3: "
}
p1, Stack p2, Stack p3) {
+ p1);
+ p2);
+ p3);
Observação: Substitua o método exibePilhas pelo método abaixo.
// -------------------------------------------- exibePilhas
static void exibePilhas(Stack p1,
char a1 = '|', a2 = '|', a3 =
char b1 = '|', b2 = '|', b3 =
char c1 = '|', c2 = '|', c3 =
Object nodo;
Stack p2, Stack p3) {
'|';
'|';
'|';
nodo = p1.search(1);
a1 = nodo.toString().charAt(0);
if (a1 != '-') {
a1 = '1';
}
nodo = p1.search(2);
a2 = nodo.toString().charAt(0);
if (a2 != '-') {
a2 = '2';
}
nodo = p1.search(3);
a3 = nodo.toString().charAt(0);
if (a3 != '-') {
a3 = '3';
}
197
nodo = p2.search(1);
b1 = nodo.toString().charAt(0);
if (b1 != '-') {
b1 = '1';
}
nodo = p2.search(2);
b2 = nodo.toString().charAt(0);
if (b2 != '-') {
b2 = '2';
}
nodo = p2.search(3);
b3 = nodo.toString().charAt(0);
if (b3 != '-') {
b3 = '3';
}
nodo = p3.search(1);
c1 = nodo.toString().charAt(0);
if (c1 != '-') {
c1 = '1';
}
nodo = p3.search(2);
c2 = nodo.toString().charAt(0);
if (c2 != '-') {
c2 = '2';
}
nodo = p3.search(3);
c3 = nodo.toString().charAt(0);
if (c3 != '-') {
c3 = '3';
}
if (c3 == '-' && c2 == '-' && c1
c3 = c1;
c1 = '-';
}
if (c3 == '-' && c2 != '-' && c1
c3 = c2;
c2 = '-';
}
if (c3 == '-' && c2 != '-' && c1
c3 = c2;
c2 = c1;
c1 = '-';
}
if (b3 == '-' && b2 == '-' && b1
b3 = b1;
b1 = '-';
}
if (b3 == '-' && b2 != '-' && b1
b3 = b2;
b2 = '-';
}
if (b3 == '-' && b2 != '-' && b1
b3 = b2;
b2 = b1;
b1 = '-';
}
if (a3 == '-' && a2 == '-' && a1
a3 = a1;
!= '-') {
== '-') {
!= '-') {
!= '-') {
== '-') {
!= '-') {
!= '-') {
198
a1 = '-';
}
if (a3 == '-' && a2 != '-' && a1 == '-') {
a3 = a2;
a2 = '-';
}
if (a3 == '-' && a2 != '-' && a1 != '-') {
a3 = a2;
a2 = a1;
a1 = '-';
}
System.out.printf("
%c
%c
%c
\n", a1, b1, c1);
System.out.printf("
%c
%c
%c
\n", a2, b2, c2);
System.out.printf("
%c
%c
%c
\n", a3, b3, c3);
System.out.printf("--------- --------- ---------\n");
System.out.printf(" p1
p2
p3\n\n");
}
}
8.2 Analisador de Expressões (classes: PilhaInt e PilhaChar)
Problema: Implementar em Java um Analisador de Expressões utilizando Pilhas.
Exemplo: (3 * (4 + 5))
Dicas:
1.
2.
3.
4.
5.
6.
Crie duas PILHAS (números e operandos);
"(" não faça nada;
Número (Push pilha 2) empilhe na pilha de números;
Operando (Push pilha 1) empilhe na pilha de operandos;
")" (Pop pilha 2, Pop pilha 2 e Pop pilha 1) execute a operação;
Até que i = e[0]
199
Valores Válidos:
Números: 0 1 2 3 4 5 6 7 8 9 (Números Inteiros Positivos)
Operandos: + - * /
// -------------------------------------------------------- Fonte: Dados25.java
package dados25;
public class PilhaInt {
private final int m = 50;
private final int SUCESSO = 0;
private final int PILHA_CHEIA = 1;
private final int PILHA_VAZIA = 2;
private int topo;
private int [] elem = new int[m];
// ---------------------------------------------- criaPilha
public void criaPilha() {
topo = -1;
}
// ---------------------------------------------- push
public int push(int dado) {
if (topo == m - 1) {
return(PILHA_CHEIA);
}
else {
topo++;
elem[topo] = dado;
return(SUCESSO);
}
}
// ---------------------------------------------- pop
200
public int pop() {
if (topo != -1) {
topo--;
return(elem[topo + 1]);
}
return(0);
}
// ---------------------------------------------- exibePilha
public void exibePilha() {
if (topo != -1) {
System.out.print("PilhaInt: ");
for (int i = topo;i >= 0;i--) {
System.out.print(elem[i] + " ");
}
System.out.println();
}
}
}
// ----------------------------------------------------- Fonte: Dados25.java
package dados25;
public class PilhaChar {
private final int m = 50;
private final int SUCESSO = 0;
private final int PILHA_CHEIA = 1;
private final int PILHA_VAZIA = 2;
private int topo;
private char [] elem = new char[m];
// ---------------------------------------------- criaPilha
public void criaPilha() {
topo = -1;
}
// ---------------------------------------------- push
public int push(char dado) {
if (topo == m - 1) {
return(PILHA_CHEIA);
}
else {
topo++;
elem[topo] = dado;
return(SUCESSO);
}
}
// ---------------------------------------------- pop
public char pop() {
if (topo != -1) {
topo--;
return(elem[topo + 1]);
201
}
return('0');
}
// ---------------------------------------------- exibePilha
public void exibePilha() {
if (topo != -1) {
System.out.print("PilhaChar: ");
for (int i = topo;i >= 0;i--) {
System.out.print(elem[i] + " ");
}
System.out.println();
}
}
}
// ------------------------------------------------------ Fonte: Dados25.java
package dados25;
import java.util.Scanner;
public class Dados25 {
public static void main(String[] args) {
PilhaInt p1 = new PilhaInt();
PilhaChar p2 = new PilhaChar();
final int m = 50;
Scanner entrada = new Scanner(System.in);
String str;
int tipo, erro = 0;
int [] valor = {0};
char [] operador = {'0'};
int v1, v2, resposta;
System.out.println("Analisador de Expressões");
System.out.print("Expressão: ");
str = entrada.nextLine();
int n = str.length();
char [] s = new char[n];
for (int i = 0;i < n;i++) {
s[i] = str.charAt(i);
}
if (n > m) {
System.out.println("ERRO: Expressão muito Longa");
}
else {
if (testaExpressao(str) == true) {
p1.criaPilha();
p2.criaPilha();
for (int i = 0;i < n;i++) {
tipo = codifica(s[i], valor, operador);
switch (tipo) {
case 1: erro = p1.push(valor[0]);
p1.exibePilha();
break;
case 2: erro = p2.push(operador[0]);
p2.exibePilha();
202
break;
case 3: v2 = p1.pop();
v1 = p1.pop();
operador[0] = p2.pop();
resposta = calcula(v1, v2, operador[0]);
erro = p1.push(resposta);
break;
}
}
if (erro == 0) {
resposta = p1.pop();
System.out.println("Resposta: " + resposta);
}
}
else {
System.out.println("Erro: Expressão Inválida");
}
}
}
// ---------------------------------------------- codifica
static int codifica(char ch, int [] valor, char [] op) {
int codifica = 4;
if (ch >= '0' && ch <= '9') {
codifica = 1;
valor[0] = ch - 48;
}
if (ch == '+' || ch == '-' || ch == '*' || ch == '/') {
codifica = 2;
op[0] = ch;
}
if (ch == ')') {
codifica = 3;
}
return(codifica);
}
// -------------------------------------------- testaExpressao
static boolean testaExpressao(String s) {
int abre = 0,fecha = 0;
int n = s.length();
for (int i = 0;i < n;i++) {
if (s.charAt(i) == '(') {
abre++;
}
else {
if (s.charAt(i) == ')') {
fecha++;
}
}
}
if (abre == fecha) {
return(true);
203
}
return(false);
}
// ------------------------------------------ Calcula
static int calcula(int v1, int v2, char op) {
switch (op) {
case '+': return(v1 + v2);
case '-': return(v1 - v2);
case '*': return(v1 * v2);
case '/': return(v1 / v2);
}
return(0);
}
}
Resultado do Programa:
Analisador de Expressões
Expressão: (3+(4*5)) <enter>
PilhaInt: 3
PilhaChar: +
PilhaInt: 4 3
PilhaChar: * +
PilhaInt: 5 4 3
Resposta: 23
8.3 Analisador de Expressões usando Stack
Programa abaixo implementa um Analisador de Expressões utilizando a classe Java
Stack. O programa resolve expressões do tipo: (4*(5+(4*3)/(3-1))) ou (3*(4+5))
Exemplo de entrada de dados:
Expressao: (4*(5+(4*3)/(3-1))) <enter>
// ----------------------------------------------- Fonte: AnalisadorExpressao.java
import java.util.Stack;
import java.util.Scanner;
public class AnalisadorExpressao {
public static void main(String[] args) {
Stack numeros = new Stack();
Stack operadores = new Stack();
Scanner entrada = new Scanner(System.in);
String s;
float resp = 0;
System.out.print("Expressao: ");
s = entrada.nextLine();
204
int n = s.length();
if (testaExpressao(s)) {
for (int i = 0;i < n;i++) {
if (s.charAt(i) == '(') {
continue;
}
if ("0123456789".indexOf(s.charAt(i)) != -1) {
char ch = s.charAt(i);
float t = (float) ch - 48;
numeros.push(t);
exibePilha(numeros);
exibePilha(operadores);
System.out.println();
}
else {
if ("+-*/".indexOf(s.charAt(i)) != -1) {
char op = s.charAt(i);
operadores.push(op);
}
}
if (s.charAt(i) == ')') {
Object nodo = numeros.pop();
String st = nodo.toString();
float y = Float.parseFloat(st);
nodo = numeros.pop();
st = nodo.toString();
float x = Float.parseFloat(st);
nodo = operadores.pop();
String temp = nodo.toString();
char op = temp.charAt(0);
resp = calculaOperacao(x, y, op);
numeros.push(resp);
exibePilha(numeros);
exibePilha(operadores);
}
}
System.out.println();
if (operadores.empty()) {
Object nodo = numeros.pop();
String st = nodo.toString();
resp = Float.parseFloat(st);
}
else {
resp = 0;
while (!operadores.empty()) {
Object nodo = numeros.pop();
String st = nodo.toString();
float y = Float.parseFloat(st);
nodo = numeros.pop();
st = nodo.toString();
float x = Float.parseFloat(st);
nodo = operadores.pop();
String temp = nodo.toString();
char op = temp.charAt(0);
resp = calculaOperacao(x, y, op);
numeros.push(resp);
exibePilha(numeros);
exibePilha(operadores);
}
205
}
System.out.println("Resposta: " + resp);
}
else {
System.out.println("Erro: Expressao Invalida");
}
}
// ---------------------------------------- calculaOperacao
static float calculaOperacao(float x, float y, char op) {
float resp = 0;
switch (op) {
case '+': resp = x + y;
break;
case '-': resp = x - y;
break;
case '*': resp = x * y;
break;
case '/': if (y != 0) {
resp = x / y;
}
else {
System.out.println("Erro Fatal: Divisão por Zero");
System.exit(0);
}
break;
}
return(resp);
}
// ---------------------------------------- testaExpressao
static boolean testaExpressao(String exp) {
int abre = 0, fecha = 0;
for (int i = 0;i < exp.length();i++) {
if (exp.charAt(i) == '(') {
abre++;
}
if (exp.charAt(i) == ')') {
fecha++;
}
}
if (abre == fecha) {
return(true);
}
else
return(false);
}
// ---------------------------------------- exibePilha
static void exibePilha(Stack pilha) {
Object [] nodo = pilha.toArray();
System.out.print("Pilha: ");
for (int i = 0;i < nodo.length;i++) {
206
System.out.print(nodo[i] + " ");
}
System.out.println();
}
}
Resultado do Programa:
Expressao: (4*(5+(4*3)/(3-1))) <enter>
Pilha: 4
Pilha:
Pilha: 5 4
Pilha: *
Pilha: 4 5 4
Pilha: + *
Pilha: 3 4 5 4
Pilha: * + *
Pilha:
Pilha:
Pilha:
Pilha:
12 5 4
+ *
3 12 5 4
/ + *
Pilha: 1 3 12 5 4
Pilha: - / + *
Pilha:
Pilha:
Pilha:
Pilha:
Pilha:
Pilha:
2 12 5 4
/ + *
6 5 4
+ *
11 4
*
Pilha: 44
Pilha:
Resposta: 44
8.4 Calculadora Polonesa Reversa
A seguir um programa simples que implementa uma calculadora Polonesa Reversa, ou
seja, o usuário digita primeiro dois valores e depois o operador.
Exemplo de entrada de dados:
Polonesa Reversa: <enter> abandona
3
2
/
1.5
2
*
207
3
<enter>
by Polonesa Reversa
// -------------------------------------------------- Fonte: Polonesa.java
package polonesa;
public class Polonesa {
public static void main(String[] args) {
PolonesaReversa polonesa = new PolonesaReversa();
polonesa.calculaPolonesaReversa();
}
}
// -------------------------------------------------- Fonte: PolonesaReversa.java
package polonesa;
import java.util.Scanner;
public class PolonesaReversa {
// ............................................. lista de atributos da classe
private double x, y, resp = 0;
private char op;
private int erro;
// ............................................. métodos públicos da classe
public PolonesaReversa () {
erro = 0;
}
// construtor
public void calculaPolonesaReversa() {
Scanner entrada = new Scanner(System.in);
String s;
System.out.println("Polonesa Reversa: <enter> abandonar");
do {
if (resp == 0) {
s = entrada.nextLine();
if (s.equals("")) {
System.out.println("by Polonesa Reversa");
System.exit(0);
}
x = Double.parseDouble(s);
}
else {
x = resp;
}
s = entrada.nextLine();
if (s.equals("")) {
System.out.println("by Polonesa Reversa");
System.exit(0);
208
}
y = Double.parseDouble(s);
do {
s = entrada.nextLine();
if (s.equals("")) {
System.out.println("by Polonesa Reversa");
System.exit(0);
}
op = s.charAt(0);
} while (!strChr("+-*/Pp", op));
operaCalculadora();
exibeCalculadora();
} while (!s.equals(""));
}
// ---------------------------- operaCalculadora
private void operaCalculadora() {
switch (op)
{
case '+': resp = soma(x, y);
break;
case '-': resp = subtracao(x, y);
break;
case '*': resp = multiplicacao(x, y);
break;
case '/': if (y == 0)
erro = 1; // divisão por zero
else
resp = divisao(x, y);
break;
case 'P':
case 'p': resp = power(x, y);
// potência
break;
}
}
// ---------------------------- exibeCalculadora
private void exibeCalculadora() {
switch (erro) {
case 1: System.out.println("Erro: Divisão por Zero");
break;
case 2: System.out.println("Erro: Raiz Complexa");
break;
case 3: System.out.println("Erro: Tangente Inválida");
break;
default: System.out.println(resp);
}
}
// ................................................ métodos privados da classe
// ---------------------------- strChr
private boolean strChr(String s, char ch) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ch) {
209
return(true);
}
}
return(false);
}
// ---------------------------- soma
private double soma(double x, double y) {
return(x + y);
}
// ---------------------------- subtração
private double subtracao(double x, double y) {
return(x - y);
}
// ---------------------------- multiplicação
private double multiplicacao(double x, double y) {
return(x * y);
}
// ---------------------------- divisão
private double divisao(double x, double y) {
if (y == 0) {
erro = 1;
return(-1);
}
return(x / y);
}
// ---------------------------- power
private double power(double x, double y) {
return(Math.pow(x, y));
}
}
8.5 Torre de Hanoi (classe Pilha)
A seguir é visto a implementação de uma Torre de Hanoi em Java usando a classe
Pilha (Pilha alocada em um vetor).
// -------------------------------------------------- Fonte: Tower.java
package tower;
import java.util.Scanner;
public class Tower {
public static void
Pilha p1 = new
Pilha p2 = new
Pilha p3 = new
main(String[] args) {
Pilha(3);
Pilha(3);
Pilha(3);
210
Scanner input = new Scanner(System.in);
String s;
int t1, t2;
int valor1 = 0, valor2;
boolean erro = false;
p1.Push(30);
p1.Push(20);
p1.Push(10);
do {
p1.Exibe("p1: ");
p2.Exibe("p2: ");
p3.Exibe("p3: ");
System.out.print("De: ");
s = input.nextLine();
t1 = Integer.parseInt(s);
if (t1 != 0) {
switch (t1) {
case 1: valor1 = p1.Pop();
break;
case 2: valor1 = p2.Pop();
break;
case 3: valor1 = p3.Pop();
break;
}
if (valor1 == -1) {
System.out.println("Status: Movimento Inválido");
}
else {
erro = false;
System.out.print("Para: ");
s = input.nextLine();
t2 = Integer.parseInt(s);
switch (t2) {
case 1: if (!p1.Empty()) {
valor2 = p1.Consulta();
if (valor1 > valor2) {
System.out.println("Status: Quebra da Regra");
erro = true;
}
else {
p1.Push(valor1);
}
}
else {
p1.Push(valor1);
}
break;
case 2: if (!p2.Empty()) {
valor2 = p2.Consulta();
if (valor1 > valor2) {
System.out.println("Status: Quebra da Regra");
erro = true;
}
else {
p2.Push(valor1);
}
}
else {
211
p2.Push(valor1);
}
break;
case 3: if (!p3.Empty()) {
valor2 = p3.Consulta();
if (valor1 > valor2) {
System.out.println("Status: Quebra da Regra");
erro = true;
}
else {
p3.Push(valor1);
}
}
else {
p3.Push(valor1);
}
break;
}
}
if (erro) {
switch (t1) {
case 1: p1.Push(valor1);
break;
case 2: p2.Push(valor1);
break;
case 3: p3.Push(valor1);
break;
}
}
}
if (p2.Full() || p3.Full()) {
System.out.println("Status: Winner");
System.exit(0);
}
} while (t1 != 0);
}
}
// ------------------------------------------------------- Fonte: Pilha.java
package tower;
public class Pilha {
private int [] vet;
private int topo;
private int max;
// ------------------------------------ construtor
public Pilha(int numeroElementos) {
vet = new int[numeroElementos];
topo = -1;
max = numeroElementos;
}
// ------------------------------------ Push
public void Push(int valor) {
if (topo < max-1) {
212
topo++;
vet[topo] = valor;
}
else {
System.out.println("Status: Pilha Cheia");
System.exit(0);
}
}
// ------------------------------------ Pop
public int Pop() {
int valor;
if (topo >= 0) {
valor = vet[topo];
topo--;
}
else {
//System.out.println("Status: Pilha Vazia");
return(-1);
}
return(valor);
}
// ------------------------------------ Consulta
public int Consulta() {
int valor;
if (topo >= 0) {
valor = vet[topo];
}
else {
//System.out.println("Status: Pilha Vazia");
return(-1);
}
return(valor);
}
// ------------------------------------ Empty
public boolean Empty() {
if (topo == -1) {
return(true);
}
return(false);
}
// ------------------------------------ Full
public boolean Full() {
if (topo == max-1) {
return(true);
}
return(false);
}
// ------------------------------------ Exibe
213
public void Exibe(String s) {
System.out.print(s + "[");
for (int i = 0;i < topo;i++) {
System.out.print(vet[i] + ",");
}
if (topo >= 0) {
System.out.println(vet[topo] + "]");
}
else {
System.out.println("]");
}
}
}
214
8.6 Jogo Quebra-Cabeças
A seguir é visto a implementação de um jogo chamado Quebra-Cabeças,
cujo objetivo é colocar os números de 1 à 8 em ordem crescente, conforme
exemplo abaixo:
Começo Jogo
+-----------+
| 6 | 2 | 4 |
+-----------+
| 8 | 7 | 5 |
+-----------+
| 3 | 1 |
|
+-----------+
Final Jogo
+-----------+
| 1 | 2 | 3 |
+-----------+
| 4 | 5 | 6 |
+-----------+
| 7 | 8 |
|
+-----------+
// ---------------------------------------------------------------- Fonte: Cabeca.java
package cabeca;
public class Cabeca {
public static void main(String[] args) {
Tabuleiro tabuleiro = new Tabuleiro();
tabuleiro.sorteiaNumeros();
tabuleiro.exibeTabuleiro();
tabuleiro.jogadasJogador();
}
}
// ------------------------------------------------------ Fonte: Tabuleiro.java
package cabeca;
import java.util.Scanner;
public class Tabuleiro {
private int [][] matriz = new
private int [][] certa = {{1,
{4,
{7,
private int jogadas = 0;
int [3][3];
2, 3},
5, 6},
8, 0}};
// --------------------------------- verificaVitoria
private boolean verificaVitoria() {
for (int l = 0;l < 3;l++) {
for (int c = 0;c < 3;c++) {
if (matriz[l][c] != certa[l][c]) {
return(false);
}
}
}
215
return(true);
}
// --------------------------------- verificaDeslocamento
private void verificaDeslocamento(int num) {
int lin = 0, col = 0;
int ll = 0, cc = 0;
for (int l = 0;l < 3;l++) {
for (int c = 0;c < 3;c++) {
if (matriz[l][c] == num) {
lin = l;
col = c;
}
}
}
for (int l = 0;l < 3;l++) {
for (int c = 0;c < 3;c++) {
if (matriz[l][c] == 0) {
ll = l;
cc = c;
}
}
}
if ((lin == ll || col == cc) &&
((ll-lin == 1 || lin-ll == 1) || (cc-col == 1 || col-cc == 1))){
matriz[ll][cc] = num;
matriz[lin][col] = 0;
exibeTabuleiro();
}
else {
System.out.println("Status: Movimento Inválido");
}
if (verificaVitoria()) {
System.out.println("Vitória");
System.exit(0);
}
}
// --------------------------------- jogadasJogador
public void jogadasJogador() {
Scanner input = new Scanner(System.in);
char tecla;
do {
System.out.print("Jogada (" + jogadas + "): ");
String s = input.nextLine();
tecla = s.charAt(0);
if (strChr("12345678", tecla)) {
verificaDeslocamento(tecla-48);
jogadas++;
if (jogadas == 99) {
System.out.println("Game Over");
System.exit(0);
}
}
} while (tecla != '0');
216
}
// --------------------------------- exibeTabuleiro
public void exibeTabuleiro() {
for (int l = 0;l < 3;l++) {
for (int c = 0;c < 3;c++) {
if (matriz[l][c] != 0) {
System.out.printf("%2d ", matriz[l][c]);
}
else {
System.out.printf("
");
}
}
System.out.println();
}
}
// --------------------------------- sorteiaNumeros
public void sorteiaNumeros() {
for (int i = 1;i <= 8;i++) {
boolean ok = false;
do {
int l = (int) (Math.random() * 3);
int c = (int) (Math.random() * 3);
if (matriz[l][c] == 0) {
matriz[l][c] = i;
ok = true;
}
} while (!ok);
}
}
// --------------------------------- strChr
private boolean strChr(String s, char tecla) {
int n = s.length();
for (int i = 0;i < n;i++) {
if (s.charAt(i) == tecla) {
return(true);
}
}
return(false);
}
}
217
Download