Enunciados das aulas práticas de Algoritmos e Modelação Matemática Paulo Mateus André Souto 2013
ii À guardiã
Precaução dirigida aos alunos Os temas apresentados neste trabalho são uma versão muito preliminar da sebenta da cadeira de Algoritmos e Modelação Matemática dos cursos de Engenharia Biomédica e de Matemática Aplicada à Computação do Instituto Superior Técnico da Universidade de Lisboa. Notem que pode haver gralhas, exemplos incompletos, definições e teoremas que podem estar apresentados de forma não uniforme. Na verdade podem existir tópicos que necessitarão de ser reescritos ou escritos de raiz. Parte dos exercícios são retirados das referências bibliográficas dadas. Futuramente, serão substituídos por outros que possam servir os nossos propósitos enquanto docentes da cadeira e de acordo com os objetivos estabelecidos para os conhecimentos a adquirir pelos alunos. No que diz respeito a esta notas o leitor deve estar preparado para se deparar com problemas de compreensão das matérias abordadas, dado que serão para já muito incompletas, e portanto sugerimos a leitura de livros considerados importantes nas áreas que serão abordadas de modo a complementarem a informação apresentada. Sugerimos por exemplo a leitura de [?], [?] e outras referências que faremos ao longo deste trabalho. iii
Prefácio Este trabalho tenciona compilar num livro os conteúdos programáticos de um curso introdutório à Algoritmia e à Modelação Matemática. Os temas abordados neste trabalho são naturalmente parte integrante dos conteúdos programáticos planeados para a cadeira de Algoritmos e Modelação Matemática a lecionar nos cursos de Engenharia Biomédica e de Matemática Aplicada à Computação do Instituto Superior Técnico da Universidade de Lisboa. A primeira compilação data do ano de 2013. A ideia deste trabalho é providenciar ao alunos (e não só) uma referência de estudo, ainda que incompleta, sobre algoritmia com uma forte componente matemática de análise e correção sendo por isso dado um especial enfase a estas problemática sob o ponto de vista de matemático e do ponto de vista das ciências da computação. A juntar a este objetivo pretende-se que este compêndio possa futuramente ser também uma ferramenta útil para outros cursos que abordem temáticas semelhantes. Pelo apoio financeiro, o autor André Souto está profundamente grato à Fundação para a Ciência e Tecnologia pela bolsa SFRH/BPD/76231/2011. Estamos também gratos a todos os membros do SQIG pelo excelente ambiente de trabalho pelo encorajamento dado. Ficamos também gratos aos alunos por qualquer comentário que ajudem a melhorar este trabalho. 2012. Departamento de Matemática Instituto Superior Técnico, Universidade de Lisboa Security and Quantum Information Group v
Instituto de Telecomunicações Conteúdo Precaução dirigida aos alunos Prefácio iii v Conteúdo 1 1 Introdução ao Eclipse 3 1.1 Exercícios propostos para a aula................................. 3 1.1.1 Criação de um projeto no Eclipse............................. 4 1.1.2 Compilação, Debugging e correção dos programas.................. 4 2 Implementação de dados abstratos 11 2.1 Exercícios propostos para a aula................................. 11 2.2 Exercícios propostos adicionais.................................. 13 3 Notação assimptótica 25 3.1 Exercícios propostos para a aula................................. 25 4 Pesquisa binária e árvores de pesquisa 31 4.1 Exercícios propostos para a aula................................. 31 5 Grafos com matrizes de adjacência 35 5.1 Exercício propostos para a aula.................................. 35 5.2 Exercícios propostos........................................ 36 6 Pesquisa em profundidade em grafos 39 6.1 Exercícios propostos para a aula................................. 39 1
Prática 1 Introdução ao Eclipse Exercícios propostos para a aula SECÇÃO 1.1 A primeira aula de laboratório tem como objetivo a introdução à escrita, compilação e debugging de programas escritos em Java, utilizando o ambiente de desenvolvimento integrado Eclipse. Pretende-se nesta aula implementar um programa que realiza um conjunto de operações sobre números naturais. Ao longo da aula serão realizadas as seguintes tarefas: 1. criação e configuração de um novo projeto no Eclipse; 2. compilação, debugging e correção do programa; 3. implementação recursiva de algumas operações. 3
1.1.1 Criação de um projeto no Eclipse 1. Comece por entrar na sua área de trabalho, com o login e password do Fenix. Inicie o programa Eclipse Juno. 2. Crie um novo projecto File > New Java Project. Coloque o título Aula1. 3. Crie uma nova classe File > New Class. Coloque no nome Utils e verifique as opções. 4. Está pronto para desenvolver funções de pacotes de utilitários. 1.1.2 Compilação, Debugging e correção dos programas 1. Crie a função fatorial. Teste a função para alguns valores fazendo output destes valores; 2. Depure o programa: Crie breakpoints e entre na vista de Debug. 3. Implemente recursivamente a função fatorial e depure-a. 4. Escreva um algoritmo de ordenação à sua escolha. Depure o programa criado. 5. Escreva uma função que calcula o traço de uma matriz. 6. Escreva um função que testa se um dado elemento ocorre num vetor. Melhore a função anterior supondo que o vetor recebido está ordenado. 4
Algumas propostas de resolução Apresenta-se algum do código da resolução de alguns exercícios da aula. O código para a implementação do cálculo da função fatorial quando é dado um número n: 1 public class Utils { 2 3 public static void main ( String [] args ) { 4 int n =4; 5 boolean x; 6 x= teste (n); 7 if(x == true ){ 8 System. out. println ("O valor de " + n+"! e :" + factorial (n)); 9 } else { 10 System. out. println ("O valor de " + n+" esta incorrecto."); 11 } 12 } 13 14 private static boolean teste ( int n) { 15 if(n >0) { 16 return true ;} 17 else { 18 return false ; 19 } 20 } 21 5
22 private static int factorial ( int n) { 23 int i=1, r =1; 24 while (i< n){ 25 i ++; 26 r*=i; 27 } 28 return r; 29 } 30 } A implementação de forma recursiva pode ser feita através do seguinte código: 1 public class Utils2 { 2 3 public static void main ( String [] args ) { 4 int n =6; 5 boolean x; 6 x= teste (n); 7 if(x == true ){ 8 System. out. println ("O valor de " + n+"! e :" + fatorial (n)); 9 } else { 10 System. out. println ("O valor de " + n+" esta incorreto."); 11 } 12 } 13 14 private static boolean teste ( int n) { 15 if(n >0) { 16 return true ;} 17 else { 18 return false ; 19 } 20 } 6
21 22 private static int factorial ( int n) { 23 if(n ==1) { 24 return 1; 25 } 26 else { 27 return n* factorial (n -1) ; 28 } 29 } 30 } Uma possível implementação da ordenação de um vetor pode ser idealizado através de: 1 public class Utils3 { 2 3 public static void main ( String [] args ) { 4 int vec []; 5 vec = new int [4]; 6 vec [0]=1; 7 vec [1]=5; 8 vec [2]=3; 9 vec [3]=2; 10 int i; 11 i =0; 12 while (i< vec. length ){ 13 int j=i,min = vec [i], pos =i; 14 int aux ; 15 while (j< vec. length ){ 16 if(vec [j]< min ){ 17 pos =j; 18 } 19 aux = vec [i]; 20 vec [i]= vec [ pos ]; 21 vec [ pos ]= aux ; 7
22 j ++; 23 } 24 i ++; 25 } 26 System. out. println ( vec [0] + ";" + vec [1] + ";" + vec [2] + ";" + vec [3]) ; 27 } 28 } Uma possível implementação do cálculo do traço de uma matriz é: 1 public class Utils5 { 2 3 public static void main ( String [] args ) { 4 double mat [][]; 5 mat = new double [2][2]; 6 mat [0][0]=1.5; 7 mat [0][1]=5.5; 8 mat [1][0]=3.3; 9 mat [1][1]=2.2; 10 int i =0; 11 double soma =0; 12 while (i <= mat. length -1) { 13 soma += mat [i][i]; 14 i ++; 15 } 16 System. out. println ( soma ); 17 } 18 // } A implementação do teste de ocorrência de um número num vetor: 8
1 public class Utils6 { 2 3 public static void main ( String [] args ) { 4 int vec []; 5 vec = new int [4]; 6 vec [0]=1; 7 vec [1]=5; 8 vec [2]=3; 9 vec [3]=2; 10 int n= 6; 11 boolean r; 12 r= ocorrencia (vec,n); 13 if(r == true ){ 14 System. out. println ("O valor ocorre "); 15 } else { 16 System. out. println ("O valor nao ocorre "); 17 } 18 } 19 20 21 private static boolean ocorrencia ( int [] vec, int n) { 22 int i =0; 23 while (i <= vec. length -1) { 24 if(vec [i ]== n){ 25 return true ;} 26 i ++; 27 } 28 return false ;} 29 } 9
Prática 2 Implementação de dados abstratos Exercícios propostos para a aula SECÇÃO 2.1 Considere o tipo de dados lista ordenada implementado em Java da seguinte forma: 1 class Node { 2 int val ; 3 Node next ; 4 } 5 6 public class Lista { 7 int comp ; 8 Node prim ; 9... 10 } 11
Implemente a classe lista com a seguinte interface 1. ins: recebe um inteiro acrescenta à lista o inteiro de forma a que esta se mantenha ordenada (por ordem crescente). 2. vazq: testa se a lista é vazia. 3. pert: recebe um inteiro e verifica se o inteiro pertence à lista. 4. ret: recebe um inteiro e apaga uma ocorrência do inteiro na lista. 5. apaga: recebe uma lista e apaga todos os elementos da lista. 12
SECÇÃO 2.2 Exercícios propostos adicionais 1. Implemente a classe da página anterior com um nó bidirecional. 2. Suponha que cerca de 70% inserções correspondem a inserir um elemento maior que todos os elementos que se encontram na lista. Faça alterações à implementação do tipo de dados lista para que a implementação da função ins tenha o custo médio mais baixo possível. Indique qual o número médio de comparações necessárias para inserir um elemento supondo que nos restantes 30% dos casos o elemento a colocar poderá ser colocado em qualquer posição (exceto a última) com igual probabilidade. 3. Usando a classe de nó do Exercício 1, implemente uma lista circular (não ordenada) onde o primeiro e último elemento estão ligados. Considere as seguintes funções: a) O construtor retorna a lista vazia. b) ins: recebe um inteiro e acrescenta o inteiro no fim da lista. c) vazq: testa se a lista é vazia. d) pert: recebe um inteiro e verifica se o inteiro pertence à lista. e) ret: recebe um inteiro e apaga uma ocorrência do inteiro da lista. f) apaga: recebe uma lista e apaga todos os elementos da lista. 13
Algumas propostas de resolução O código para a implementação de uma lista com o respetivo interface: 1 public interface Lista { 2 void ins ( int i); 3 boolean vazq (); 4 boolean pert ( int i); 5 void ret ( int i); 6 void apaga (); 7 } 1 public class Node { 2 int val ; 3 Node next ; 4 5 Node ( int v){ 6 val =v; 7 next = null ; 8 } 9 } 1 public class ImpLista implements Lista { 2 15
3 int comp ; 4 private Node prim ; 5 6 public void ins ( int i) { 7 Node n= new Node (i); 8 // Node aux = prim ; 9 if ( comp ==0) { 10 prim =n; 11 comp =1; 12 } 13 if( prim. val >= i){ 14 n. next = prim ; 15 prim = n; 16 } 17 Node aux = prim ; 18 int j =1; 19 while ( aux. next.val < i && j< comp -1) { 20 aux = aux. next ; 21 j ++; 22 } 23 if(j== comp -1) { 24 j=j -1; 25 aux. next =n; 26 n. next = null ; 27 } else { 28 Node aux2 = aux. next ; 29 aux. next =n; 30 n. next = aux2 ; 31 } 32 comp = comp +1; 33 } 34 35 public boolean vazq () { 36 return comp ==0; 37 } 38 16
39 public boolean pert ( int i) { 40 int j =1; 41 Node aux = prim ; 42 while (j< comp ){ 43 if(aux. val == i) return true ; 44 j ++; 45 } 46 return false ; 47 } 48 49 public void ret ( int i) { 50 if( pert (i)== true ){ 51 if( comp ==1 && prim. val ==i){ 52 comp =0; 53 prim = null ; 54 } else { if( prim. val ==i){ 55 prim = prim. next ; 56 comp =comp -1; 57 } else { 58 Node aux1 = prim ; 59 Node aux2 = aux1. next ; 60 while ( aux2. val!=i){ 61 aux2 = aux2. next ; 62 aux1 = aux1. next ; 63 64 aux1. next = aux2. next ; 65 comp =comp -1; 66 } 67 } 68 } 69 } 70 71 public void apaga () { 72 comp =0; 73 prim. val = -1; 74 prim. next = null ; } 17
75 } 76 } O código para a implementação de uma lista bidirecional com o respetivo interface: 1 public interface Listabi { 2 3 void ins ( int i); 4 boolean vazq (); 5 boolean pert ( int i); 6 void ret ( int i); 7 void apaga (); 8 } 1 public class Nobi { 2 int val ; 3 Nobi next ; 4 Nobi previous ; 5 6 Nobi ( int v){ 7 val =v; 8 next = null ; 9 previous = null ; 10 } 11 } 1 public class Implistabi implements Listabi { 2 3 int comp ; 4 private Nobi prim ; 18
5 6 public void ins ( int i) { 7 Nobi n= new Nobi (i); 8 // Node aux = prim ; 9 if ( comp ==0) { 10 prim =n; 11 comp =1;} 12 if( prim. val >= i){ 13 n. next = prim ; 14 n. next. previous =n; 15 prim =n; 16 } 17 Nobi aux = prim ; 18 int j =1; 19 while ( aux. next.val < i && j< comp -1) { 20 aux = aux. next ; 21 j ++; 22 } 23 if(j== comp -1) { 24 n. previous = aux ; 25 n. next = null ; 26 } else { 27 n. next = aux. next ; 28 n. previous = aux. previous ; 29 } 30 comp = comp +1; 31 } 32 33 public boolean vazq () { 34 return comp ==0; 35 } 36 37 public boolean pert ( int i) { 38 int j =1; 39 Nobi aux = prim ; 40 while (j< comp ){ 19
41 if(aux. val == i) return true ; 42 j ++; 43 } 44 return false ; 45 } 46 47 public void ret ( int i) { 48 if( pert (i)== true ){ 49 if( prim. val ==i){ 50 prim = prim. next ; 51 prim. previous = null ; 52 comp =comp -1; 53 } else { 54 Nobi aux = prim ; 55 while ( aux. val!=i){ 56 aux = aux. next ; 57 } 58 aux. next. previous = aux. previous ; 59 comp =comp -1; 60 } 61 } 62 } 63 64 public void apaga () { 65 comp =0; 66 prim. val = -1; 67 prim. next = null ; 68 prim. previous = null ; 69 } 70 71 } O código para a implementação de uma lista circular com o respetivo interface: 20
1 public interface Listacircular { 2 void nova (); 3 void ins ( int i); 4 boolean vazq (); 5 boolean pert ( int i); 6 void ret ( int i); 7 void apaga (); 8 } 1 public class Implistacircular implements Listacircular { 2 3 int comp ; 4 protected Node prim ; 5 6 public void nova () { 7 prim = null ; 8 comp =0; 9 } 10 11 public void ins ( int i) { 12 Node n = new Node (i); 13 if( comp ==0) { 14 prim =n; 15 n. next =n; 16 comp = comp +1; 17 } else { 18 int j =1; 19 Node aux = prim ; 20 while (j< comp ){ 21 aux = aux. next ; 22 j ++; 23 } 24 n. next = prim ; 25 aux. next =n; 21
26 } 27 } 28 29 public boolean vazq () { 30 return comp ==0; 31 } 32 33 public boolean pert ( int i) { 34 int j =1; 35 Node aux = prim ; 36 while (j< comp ){ 37 if(aux. val == i) return true ; 38 j ++; 39 } 40 return false ; 41 } 42 43 public void ret ( int i) { 44 if( pert (i)== true ){ 45 if( comp ==1 && prim. val ==i){ 46 comp =0; 47 prim = null ; 48 } else { if( prim. val ==i){ 49 prim = prim. next ; 50 comp =comp -1; 51 } else { 52 Node aux1 = prim ; 53 Node aux2 = aux1. next ; 54 while ( aux2. val!=i){ 55 aux2 = aux2. next ; 56 aux1 = aux1. next ; 57 } 58 aux1. next = aux2. next ; 59 comp =comp -1; 60 } 61 } 22
62 } 63 } 64 65 public void apaga () { 66 comp =0; 67 prim. val = -1; 68 prim. next = null ; 69 } 70 } 23
Prática 3 Notação assimptótica No exercícios que se seguem o aluno deve ter em atenção que podem ser usadas notações diferentes para a notação assimptótica. Em algumas literaturas é usado o símbolo de pertença enquanto que noutras é usado o sinal de igual com a interpretação óbvia. Exercícios propostos para a aula SECÇÃO 3.1 1. Assuma que os termos que se seguem expressão o tempo T(n) gasto por um algoritmo na resolução de um problema para instâncias de tamanho n. Indique o termo dominante e a menor complexidade Oh-grande de cada exemplo. a) 5 + 0.001n 3 + 0.025n b) 500n + 100n 1,5 + 50n log 10 n c) 2 n + 2.5n 1.75 d) n 2 + log 2 n + n(log 2 n) 25
e) 2n log 3 n + n log 2 n f) 3 log 8 n + log 2 log 2 log 2 n g) 100n + 0.01n 2 h) 0.01n + 100n 2 i) 2n + n 0.5 + 0.5n 1.25 j) 0.01n log 2 n + n(log 2 n) 2 k) 100n log 3 n + n 3 + 100n l) 0.003 log 4 n + log 2 log 2 n 2. Diga quais das seguintes afirmações são verdadeiras. a) 3n 2 + 10n log n = O(n log n) b) 3n 2 + 10n log n = Ω(n 2 ) c) 3n 2 + 10n log n = Θ(n 2 ) d) n log n + n/2 = O(n) e) 10 n + log n = O(n) f) n + log n = O(log n) g) n + log n = Θ(log n) h) n + log n = Θ(n) i) 2 n + log n = Θ( n) j) n + log n = Ω(1) k) n + log n = Ω(log n) l) n + log n = Ω(n) 3. Diga quais das seguintes afirmações são verdadeiras. Corrija as falsas. a) O( f + g) = O( f ) + O(g); b) O( f g) = O( f ) O(g); c) g = O( f ) e h = O( f ) então g = O(h); d) n 4 = O(n 6 ); 26
e) 2 n+1 = O(2 n ); f) 2 2n = O(2 n ). 4. Prove rigorosamente que: a) 1 2 n2 3n = Θ(n 2 ); b) 6n 3 = Θ(n 2 ). 5. Ordene por ordem crescente na ordenação da notação Oh-grande as seguintes funções: log n; 2 n 3 ; n 5/2 ; 2 3 log n ; n; 4 n; log 3 n; n 10 ; 2 log n ; 2 3n ; log n 27
Algumas propostas de resolução 1. a) termo 0.001n 3 ; ordem O(n 3 ); b) termo 100n 1.5 ; ordem O(n 1.5 ); c) termo 2 n ; ordem O(2 n ); d) termo n 2 ; ordem O(n 2 ); e) termo são ambos; ordem O(n log n); f) termo 3 log 8 n; ordem O(log n); g) termo 0.01n 2 ; ordem O(n 2 ); h) termo 100n 2 ; ordem O(n 2 ); i) termo 0.5n 1.25 ; ordem O(n 1.25 ); j) termo n(log 2 n) 2 ; ordem O(n(log 2 n) 2 ); k) termo n 3 ; ordem O(n 3 ); l) termo 0.003 log 4 n; ordem O(log n); 2. a) falso; b) verdadeiro; c) verdadeiro; d) falso; e) verdadeiro; f) falso; g) falso; h) falso; 29
i) verdadeiro; j) verdadeiro; k) verdadeiro; l) falso; 3. Diga quais das seguintes afirmações são verdadeiras. Corrija as falsas. a) O( f + g) = O( f ) + O(g); Falso - O( f + g) = O(max{ f, g}) b) O( f g) = O( f ) O(g); Verdadeiro c) g = O( f ) e h = O( f ) então g = O(h); Falso - g = O( f ) e f = O(h) então g = O(h) d) n 4 = O(n 6 ); Verdadeiro e) 2 n+1 = O(2 n ); Verdadeiro f) 2 2n = O(2 n ). Falso 4. Prove rigorosamente que: a) 1 2 n2 3n = Θ(n 2 ); Para provar que 1 2 n2 3n O(n 2 ) basta notar que qualquer que seja o n natural 1 2 n2 3n n 2 pelo que basta tomar na definição de classe Oh n 0 = 1 e c = 1; Para provar que 1 2 n2 3n θ(n 2 ) note-se que: 1 2 n2 3n 1 3 n2 n 18 Basta então tomar na definição de Ω, c = 1/3 e n 0 = 18. b) 6n 3 = Θ(n 2 ). Claramente 6n 3 Ω(n 2 ) pois qualquer que seja o n 6n 3 n 2. Tem de se mostrar então que 6n 3 / Ø(n 2 ). Se 6n 3 Ø(n 2 ) então qualquer que fosse o c e existia n 0 tal que para todo o n n 0 6n 3 cn 2 ou seja n c/6 o que é impossível. 5. Ordene por ordem crescente na ordenação da notação Oh-grande as seguintes funções: log n log n log 3 n 4 n n 2 log n n 5/2 2 3 log n n 10 2 3n 2 n3 30
Prática 4 Pesquisa binária e árvores de pesquisa Exercícios propostos para a aula SECÇÃO 4.1 Implemente a pesquisa binária em vectores ordenados. Implemente a classe árvore ternária com os seguinte métodos: ArvTer() que constrói uma árvore vazia; ArvTer(int key, ArvTer l, ArvTer c, ArvTer d) que constrói uma árvore ternária com os descendentes óbvios; public boolean isheap() que retorna true se a árvore é um acervo, e falso caso contrário. public boolean pesquisa(int key) que assume que a árvore é um acervo e retorna true se a chave ocorre na árvore e false caso contrário. 31
Exercícios propostos 1. Implemente uma árvore com um número arbitrário de descendentes. 32
Algumas propostas de resolução 1 public class Trinode { 2 ArvTer ltree, ctree, rtree ; 3 int key ; 4 Trinode ( int i, ArvTer l, ArvTer c, ArvTer r){ 5 key =i; 6 ltree =l; 7 ctree =c; 8 rtree =r; 9 } 10 } 1 public class ArvTer { 2 Trinode root ; 3 4 public ArvTer () { 5 // TODO Auto - generated method stub 6 root = null ; 7 } 8 9 public ArvTer ( int key, ArvTer l, ArvTer c, ArvTer r) { 10 // TODO Auto - generated method stub 11 root = new Trinode (key, l, c, r); 12 } 13 33
14 public boolean isheap () { 15 if( root == null ) return true ; 16 if( root. ltree!= null && root. ltree. root!= null &&( root.key <= root. ltree. root. key! root. ltree. isheap ())) return false ; 17 if( root. ctree!= null && root. ctree. root!= null &&( root.key <= root. ctree. root. key! root. ctree. isheap ())) return false ; 18 if( root. rtree!= null && root. rtree. root!= null &&( root.key <= root. rtree. root. key! root. rtree. isheap ())) return false ; 19 return true ; 20 } 21 22 public boolean pesquisa ( int k) { 23 if( root == null ) return false ; 24 if( root.key >k) return false ; 25 if( root. key ==k) return true ; 26 return ( root. ltree!= null && root. ltree. pesquisa (k)) 27 ( root. ctree!= null && root. ctree. pesquisa (k) ) 28 ( root. rtree!= null && root. rtree. pesquisa (k) ); 29 } 30 } 34
Prática 5 Grafos com matrizes de adjacência Exercício propostos para a aula SECÇÃO 5.1 1. Implemente o tipo de dados grafo com matrizes de adjacência em Java com os seguintes métodos: classe grafo com o construtor que recebe a dimensão do grafo; adi aresta (recebe dois inteiro e adiciona a aresta entre os nós indexados pelos inteiros); rem aresta (recebe dois inteiro e retira a aresta entre os nós indexados pelos inteiros); adjacenteq (testa de se um nó é adjacente a outro); acessível (testa se um nó é acessível a partir de outro); 35
SECÇÃO 5.2 Exercícios propostos Implemente o tipo de dados grafo com listas de adjacência com os métodos acima descritos. 36
Proposta de resolução 1 public class GOMA { 2 int [][] MA; 3 4 public GOMA ( int dim ){ 5 MA=new int [ dim ][ dim ]; 6 } 7 8 public void adi_ aresta ( int i, int j) { 9 MA[i][j ]=1; 10 11 } 12 13 public void rem_ aaresta ( int i, int j) { 14 MA[i][j ]=0; 15 } 16 17 public boolean adjacenteq ( int i, int j) { 18 return MA[i][j ]==1; 19 } 20 21 private static int proxavisitar ( int [] v){ 22 int i=v. length -1; 23 while (i >=0 && v[i ]!=1) { 24 i - -; 25 } 26 return i; 37
27 } 28 29 public boolean acessivel ( int i, int j) { 30 int aux,next,v []= new int [MA. length ]; 31 v[i ]=1; 32 next = proxavisitar (v); 33 while ( next!= -1) { 34 if( next ==j) return true ; 35 v[ next ]=2; 36 aux =0; 37 while (aux <v. length ) { 38 if( adjacenteq (next, aux ) && v[ aux ]==0) v[ aux ]=1; 39 aux ++; 40 } 41 next = proxavisitar (v); 42 } 43 return false ; 44 } 45 46 public static void main ( String [] args ) { 47 GOMA g= new GOMA (3) ; 48 g. addaresta (1,0) ; 49 g. addaresta (0,1) ; 50 g. addaresta (2,1) ; 51 System. out. println (g. acessivel (0,2) ); 52 } 53 } 38
Prática 6 Pesquisa em profundidade em grafos Exercícios propostos para a aula SECÇÃO 6.1 1. Implemente o algoritmo Deep First Search baseado numa estrutura de pilha (LIFO); 2. Crie uma função que testa se um dado grafo é conexo ou não. 39
Proposta de resolução 1 public interface Tabela { 2 public void insere ( int i); 3 public void retira ( int i); 4 public boolean vazia (); 5 public boolean pesquisa ( int i); 6 } 1 public interface GrafoO { 2 public void addaresta ( int i, int j); 3 public void retiraaresta ( int i, int j); 4 public boolean adjacenteq ( int i, int j); 5 public int [] DFS ( int i); 6 public boolean conexo (); 7 } 1 public interface Pilha { 2 public void insere ( int i); 3 public boolean vazia (); 4 public void retira (); 5 public int ultimo (); 6 } 41
1 class Node { 2 int val ; 3 Node next ; 4 } 1 public class Pilhadyn implements Pilha { 2 3 protected Node first, last ; 4 5 public Pilhadyn (){ 6 first = null ; 7 last = null ; 8 } 9 10 public void insere ( int i) { /* insere no fim da lista */ 11 Node aux = new Node (); 12 aux. val =i; 13 aux. next = null ; 14 if( last!= null ){ 15 last. next = aux ; 16 last = aux ; 17 } else { 18 last = aux ; 19 first = aux ; 20 } 21 } 22 23 public boolean vazia () { 24 return first == null ; 25 } 26 27 public void retira () { /* retira o ultimo da lista */ 28 Node aux = first ; 29 if(aux == null ) return ; 42
30 if(aux. next == null ) { 31 first = null ; 32 last = null ; 33 } 34 else { 35 while ( aux. next!= last ) aux = aux. next ; 36 last = aux ; 37 aux. next = null ; 38 } 39 } 40 41 public int ultimo () { 42 if( last!= null ) return last. val ; 43 return -1; 44 } 45 46 public int primeiro () { 47 if( first!= null ) return first. val ; 48 return -1; 49 } 50 51 public FilaP copia (){ 52 FilaP n= new FilaP (); 53 Node aux = first ; 54 while ( aux!= null ){ 55 n. insere ( aux. val ); 56 aux = aux. next ; 57 } 58 return n; 59 } 60 } 1 public class GOLA implements GrafoO { 2 FilaP LA []; 43
3 4 public GOLA ( int dim ){ 5 LA=new FilaP [ dim ]; 6 int i =0; 7 while (i<dim ) { 8 LA[i]= new FilaP (); 9 i ++; 10 } 11 } 12 13 public void addaresta ( int i, int j) { 14 LA[i]. insere (j); 15 } 16 17 public void retiraaresta ( int i, int j) { 18 LA[i]. retira (j); 19 } 20 21 public boolean adjacenteq ( int i, int j) { 22 return LA[i]. pesquisa (j); 23 } 24 25 FilaP adjacentes ( int i) { 26 return LA[ i]. copia (); /* cria uma copia a arvore com raiz i */ 27 } 28 29 30 public int [] DFS ( int v) { 31 int numnos =LA. length ; 32 int [] order = new int [ numnos ]; 33 int [] visitados = new int [ numnos ]; 34 // 0 nao visitados, 1 colocados na lista w, 2 ja visitados 35 boolean b; 36 Pilhadyn w = new Pilhadyn (); 44
37 w. insere (v); 38 FilaP ladj ; /* lista de nos ( inteiros ) auxiliar */ 39 int i=0, cur_ord =0, nextno ; 40 while (i< numnos ) { visitados [i ]=0; i ++;} /* comeca por se por todos os valores a 0 indicando que nenhum vertice foi visitado */ 41 order [v]= cur_ord ; 42 while (!w. vazia ()) { 43 nextno =w. ultimo (); 44 w. retira (); 45 visitados [ nextno ] =2; 46 ladj = adjacentes ( nextno ); /* copia */ 47 cur_ ord ++; 48 order [ nextno ]= cur_ord ; 49 b= false ; 50 while (! ladj. vazia () &&!b) { 51 if( visitados [ ladj. ultimo () ]==0) { 52 w. insere ( ladj. ultimo ()); 53 visitados [ ladj. ultimo () ]=1; 54 b= true ; 55 } 56 ladj. retira (); 57 } 58 } 59 return order ; 60 } 61 62 public boolean conexo (){ 63 int [] order = new int [LA. length ]; 64 order = DFS (LA [0]. primeiro ()); 65 int i =0; 66 while (i< LA. length ){ 67 if ( order [i ]==0) return false ; 68 i ++; 69 } 70 return true ; 45
71 } 72 } 46