Baixe o app para aproveitar ainda mais
Prévia do material em texto
CONTEÚDOS: (Conhecimentos, Habilidades, Atitudes) Tipos abstratos de dados: Abstração. Modularização. Encapsulamento. Ocultamento de informações. Listas lineares: Conceituação. Tipos de listas. Operações básicas. Implementações. Aplicações. Pilhas: Conceituação. Operações básicas. Implementações. Aplicações. Filas: Conceituação. Tipos de filas. Operações básicas. Implementações. Aplicações. Árvores: Conceituação. Tipos de árvores. Aplicações. Árvores binárias: Conceituação. Formas de passeio. Árvores binárias de pesquisa: Conceituação. Operações básicas. Implementação. Aplicações. AVALIAÇÃO DA APRENDIZAGEM : Avaliação única resultante da média ponderada das listas de exercício (peso 4), participação (peso 1), atividades avaliativas (peso 3), e projeto (peso 2). FONTES DE PESQUISA: (Bibliografia) Básica: CORMEN, Thomas H.; LEISERSON, Charles E.; RIVEST, Ronald L.; STEIN, Clifford. Algoritmos: teoria e prática. 3. ed. Rio de Janeiro: Elsevier, 2012. EDELWEISS, Nina. Estruturas de dados. Porto Alegre: Bookman, 2011. (online) (muito básico sem exercicios resolvidos por enquanto) GOODRICH, Michael T. Estruturas de dados & algoritmos em Java. 5. ed. Porto Alegre: Bookman, 2013. (online) (muito raso ) Complementar: http://denan.com.br/documentos/JavaDeitel.pdf (melhor até agora) https://www.youtube.com/watch?v=tujIyo7cMds&list=PLjcmNukBom6_nyEVge9stJLdq -bAeDoWx DEITEL, Harvey M.; DEITEL, Paul J. Java: como programar. 8. ed. São Paulo: Pearson, 2011. DROZDEK, Adam. Estrutura de dados e algoritmos em C++. 2. ed. São Paulo: Cengage Learning, 2018. ( só no papel ) MORAES, Celso Roberto. Estruturas de dados e algoritmos: uma abordagem didática. 2. ed. São Paulo: Futura, 2003. PEREIRA, Silvio do Lago. Estruturas de dados fundamentais: conceitos e aplicações. 12. ed. São Paulo: Érica, 2012. SZWARCFITER, Jayme Luiz. Estruturas de dados e seus algoritmos. 3. ed. Rio de Janeiro: LTC, 2010. http://denan.com.br/documentos/JavaDeitel.pdf https://www.youtube.com/watch?v=tujIyo7cMds&list=PLjcmNukBom6_nyEVge9stJLdq-bAeDoWx https://www.youtube.com/watch?v=tujIyo7cMds&list=PLjcmNukBom6_nyEVge9stJLdq-bAeDoWx 1 Aula Open files from System Selecione a pasta e finalize ● Se não funcionar faça isso(imagem); ● Todas as modificações serão no main, nunca nos testes. ● Toda modificação vai ser no main; ● com botão direito fazemos no teste para ver os erros; ● clique duas vezes com botão esquerdo e vai abrir essa tela ● ela vai mostrar os erros e falhas que temos no projeto; erro - compilação errada falha - menos grave apenas lógica errada; Na parte de baixo você clica nos erros e vai aparecer a opção de consertar, assim sai do vermelho para azul ( falhas). Lembre de colocar rerun para ir verificando o que falta Dicas: crie um novo projeto, coloque o nome do prof e depois abra a pasta do windows e arraste o source para cima da pasta do Eclipse Os tipos abstratos de dados (TADs) são estruturas de dados capazes de representar os tipos de dados que não foram previstos no núcleo das linguagens de programação e que, normalmente, são necessários para aplicações específicas. Essas estruturas são divididas em duas partes: os dados e as operações. A especificação de um TAD corresponde à escolha de uma boa maneira de armazenar os dados e à definição de um conjunto adequado de operações para atuar sobre eles. Aula 2 e 3 - 19 /08/21 a 23/08/21 Alocação Dinâmica na Memória Criar e manter estrutura de dados exige uma alocação dinâmica de memória. O Java não libera memória, ele simplesmente faz uma coleta de lixo automática sobre os objetos as quais não se faz mais referência. O new é primordial para uma alocação dinâmica. Assert.assertEquals(expected,actual) Quando vc consertou mas ficou alguma falha (azul), vc clica nela e vai mostrar onde está essa falha assim depois vc clica na 1 linha deste código da falha e vai debugar De 40:00 até 1: 10 ele ensina a debugar. s Lista 00 Questão 1 Crie uma classe SumDivision que contém os dois métodos static a seguir: 1. método sum que recebe dois parâmetros x1 e x2 do tipo double e retorna um double que é a soma entre x1 e x2. 2. Método divide que recebe dois parâmetros: x1 e x2 do tipo double e retorna um double que é o resultado da divisão de x1 por x2. A variável result no código a seguir double n = 15; double result = SumDivision.sum(n, 0); Armazena o seguinte conteúdo. 15 Questão 2 Crie uma classe Volume contendo um método static chamado getName que recebe volume do tipo int e retorna uma String com a descrição de volume a seguir 1. “Min Volume”, caso volume seja menor ou igual a 0; 2. “Low Volume”, caso volume seja maior que 0 e menor ou igual à 25; 3. “Medium Volume”, caso volume seja maior que 25 e menor ou igual que 75; 4. “High Volume”, caso volume seja maior que 75 e menor que 100; 5. “Max Volume”, caso volume seja maior ou igual à 100. Exemplos: A variável result no código a seguir int volume = 25; String result = Volume.getName(volume); Armazena o seguinte conteúdo. "Low Volume" Questão 3 Crie uma classe Pair para encapsular um par de strings contendo: 1. 2 atributos left e right ambos do tipo String ; 2. Construtor que recebe as variáveis left e right e inicializa os respectivos atributos left e right; 3. Sobrescreva o método toString para retornar o valor dos atributos left e right entre parênteses e separados por vírgula: “(left, right)” 4. Sobrescreva o método equals para que a igualdade entre 2 objetos do tipo Pair retorne true apenas quando tanto left quanto right de ambos sejam iguais. Crie uma classe Pairing para encapsular o pareamento entre 2 strings contendo 1. Atributo pairs do tipo vetor de Pair e respectivo método acessador getPairs; 2. Método getList a. Modificador de acesso private; b. Recebe uma string s como argumento; c. Retorna um vetor de elementos do tipo String com um elemento para cada substring em s separada por vírgula 3. Método obtainPairs a. modificador de acesso public b. Recebe como argumento duas variáveis s1 e s2 do tipo String c. Retorna um vetor de elementos do tipo Pair em que o i-ésimo elemento tem como left e right, respectivamente, o i-ésimo elemento getList(s1) e getList(s2). d. Lança exceção caso o tamanho do vetor getList(s1) seja diferente do vetor getList(s2) 4. Construtor a. Recebe String s1, String s2 b. Lança exceção c. Inicializa o atributo pairs a partir do resultado obtainPairs(s1,s2) Exemplos: A variável result no código a seguir String s1 = "Person 1, Person 3, Person 5"; String s2 = "Person 2, Person 4, Person 6"; Pairing pairing = new Pairing(s1, s2); String result = pairing.toString(); Armazena o seguinte conteúdo. "(Person 1, Person 2), (Person 3, Person 4), (Person 5, Person 6)" package com.diegopinheiro.ed1_00_workshop; public class Pair { // 1. 2 atributos left e right ambos do tipo String ; private String left, right; // 2. Construtor que recebe as variáveis left e right //e inicializa os respectivos atributos left e right; public Pair(String left, String right) { this.left = left; this.right = right; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if(obj instanceof Pair ) { Pair other = (Pair)obj; return this.left.equals(other.left) && this.right.equals(other.right); } return false; } @Override public String toString() { return "("+ this.left + ", " + this.right + ")"; } } package com.diegopinheiro.ed1_00_workshop; public class Pairing { private Pair [] pairs; // 1. Atributo pairs do tipo vetor de Pair public Pairing (String s1, String s2)throws Exception { this.pairs = obtainPairs(s1, s2); } // 1. método acessador getPairs; public Pair[] getPairs() { return pairs; } private String [] getList (String s) { if (s.isEmpty()) { return new String[0]; } return s.split(", "); } public Pair [] obtainPairs(String s1, String s2) throws Exception{ int tam1, tam2, i; String arr1 [] = getList(s1); String arr2 [] = getList(s2); Pair [] pairArr; tam1 = arr1.length; tam2 = arr2.length; if(s1.equals("")&& s2.equals("")) { pairArr = new Pair[0]; //se as strings estiverem vazias o Pair tem tamanho 0. } else if(tam1 == tam2) { pairArr = new Pair[tam1]; for ( i = 0; i < tam1; i++) { pairArr[i] = new Pair(arr1[i], arr2[i]); } } else { throw new Exception("Cannot obtain pairs with different sizes!"); } return pairArr; } @Override public String toString() { int tam = this.pairs.length; String frase = ""; if (tam != 0) { for (int i=0; i<tam; i++) { if (i != this.pairs.length-1) { //verifica se esta na ultima palavra do array frase += pairs[i] + ", "; } else { frase += pairs[i]; } } } return frase; } } Aula 4 - 26/08/21 Aula 5 - 30/08/21 Ele continuou a revisão de POO Garbage collector - ajuda no gerenciamento de memória, ele pega endereços de memória que não estão sendo usados e desaloca, deixando livre. (apagando) PS: procurar ver sobre Tipo de dado de Referência: Pair (Diego indicou o Core Java 11 edição ) Data Abstract - os dados primitivos são colocados dentro das referências. É um tipo onde sua representação é escondida(hidden) do client ( ) . 1:20 em diante - This - variável que guarda a auto referência das instâncias do objeto. Aula 6 - Pilhas 02/09/2021 - aula 2 e 3 ele falou de @test e @before ( executa antes dos outros ) String - encapsula char Determinadas listas lineares apresentam uma disciplina restrita organização e de acesso aos seus nodos, que deve ser obedecida por todas as operações realizadas nestas listas. São listas especiais nas quais não são permitidas operações sobre quaisquer nodos, somente sobre aqueles definidos pela organização da lista. Políticas de Abstração LIFO ( last in first out) - o último elemento (nodo) a ser inserido, será o primeiro a ser retirado. Assim, uma pilha permite acesso a apenas um item de dados, o último inserido. Para processar o penúltimo item inserido, deve-se remover o último. São exemplos de uso de pilha em um sistema: ● Funções recursivas em compiladores; ● Mecanismo de desfazer/refazer dos editores de texto; ● Navegação entre páginas Web; Todas as operações em uma pilha podem ser imaginadas como as que ocorre numa pilha de pratos ( um novo prato é sempre colocado no topo da pilha, e o primeiro prato a ser retirado e o do topo da pilha): ● criação: informar a capacidade ( se for implementação sequencial - vetor); ● push - empilhar (com argumento, sem retorno); ● pop - desempilhar (sem argumento, com retorno); ● consultar e/ou modificar e/ou mostrar o topo; TAD pilha inclui os seguintes métodos auxiliares: ● isEmpty - verificar se a pilha está vazia (retorna boolean); ● is Full - verificar se a pilha está cheia (implementação sequencial - vetor). Todas as consultas, alterações, inclusões e remoções de nodos somente podem ser realizadas sobre um nodo, o da extremidade (topo da pilha). No Livro: GOODRICH, Michael T. Estruturas de dados & algoritmos em Java -5/2013 na página 208 capítulo 5 , ele mostra uma estrutura básica de pilha: @Before - colocar para executar antes dos outros Basicamente, se sua estrutura for uma pilha você faz a aplicação baseada nos recurso que ela possui citados acima (push, pop, top…). Estrutura básica de pilha segundo Isidro (aula youtube): package pilhas; public class Pilha { private int valores[]; private int topo; public Pilha(){ // construtores valores = new int[5]; topo = -1; // com esse valor a pilha está vazia } public void push(int elementos){ // empilhar - inserir elementos topo ++; valores[topo] = elementos; } public boolean isEmpty(){ //verificar se esta vazia ou nao return topo == -1; } public boolean isFull() { return topo == 4; } public int pop() { int elementos; elementos = valores[topo]; topo --; return elementos; } } Lista 01 Questão 1 Crie uma classe StackArray para implementar o Tipo Abstrato de Dados Pilha. Você deve utilizar arrays na implementação e a interface IStack fornecida. Ou seja, deve possuir os métodos 1. void push(Integer value), 2. Integer pop() throws IllegalStateException; 3. boolean isEmpty() package com.diegopinheiro.ed1_01_lista; public class StackArray implements IStack { private Integer[] pilhaArray; // isso aqui é o próprio corpo da pilha (array) // a pilha tem o topo e o corpo private int top; public StackArray(int capacity) { // método construtor this.pilhaArray = new Integer[capacity]; this.top = 0; // Pq nao posso gerar em source?? } @Override public void push(Integer value) { if (this.isFull()) { throw new IllegalStateException("Nao da"); } pilhaArray[this.top] = value; this.top ++; } @Override public Integer pop() throws IllegalStateException { Integer num; if (this.isEmpty()) { throw new IllegalStateException(); } num = this.pilhaArray[top-1]; this.pilhaArray[top-1] = null; /*Com as duas posições preenchidas do array teremos o top = 2. * Logo top-1 = pos do último elemento do array*/ this.top--; return num; } @Override public boolean isEmpty() { return this.top == 0; // como a pilha e um vetor de array, e ela está cheia então o top(topo) é igual ao comprimento do vetor } private boolean isFull() { return this.top == this.pilhaArray.length; } } ==================================================== Revisão: ==================================================== public class StackArray implements IStack { private Integer [] pilhaArray ; // a pilha tem o topo e o corpo inicialmente private int top; public StackArray(int capacity) { this.pilhaArray = new Integer [capacity]; // nao entendi bem isso this.top = -1; // pilha vazia segundo o livro e isidro }; @Override public void push(Integer value) { // antes de adc temos que saber se a pilha está cheia ou vazia if(this.isFull() ) { throw new IllegalStateException("Ta cheio bro"); } else { // Coloquei um else mesmo pilhaArray[top] = value; // como não está vazia, o topo vai ser acima do valor que colocaremos, por isso top++ top++; } } private boolean isFull() { return this.top == pilhaArray.length; // como a pilha e um vetor de array ela está cheia então o top(topo) é igual ao comprimento do vetor } @Override public Integer pop() throws IllegalStateException { Integer valu = null; // pq ele fez embaixo this.pilhaArray[top-1] = null;???? Foi para inicializar, mas como ele sabia disso?? if(this.isEmpty()) { throw new IllegalStateException("Ta vazio bro"); } else { pilhaArray[top -1] = valu ; this.top--; } return valu; } @Override public boolean isEmpty() { return this.top == 0; } } Aula 7 - Filas 06/09/21 (Faltei) Total: 2 Outra estrutura de dados fundamental. E uma “prima” da pilha, pois uma fila é uma coleção de objetos que são inseridos e removidos de acordo com o princípio FIFO (First in, first out - o primeiro que entra é o primeiro que sai). ● Head - início S; ● enqueue - enfileirar (Insere o elemento no fim da fila.); ● Tail - final; ● dequeue - Retira e retorna o objeto da frente da fila. Ocorre erro se a fila estiver vazia. Funcionamento de uma fila de banco, onde as pessoas são atendidas na ordem que entram na fila: o primeiro a chegar será o primeiro a ser atendido TAD fila inclui os seguintes métodos auxiliares: ● size - Retorna o número de objetos na fila ● isEmpty - Retorna um booleano indicando se a fila está vazia. ● front - Retorna, mas não remove o objeto na frente da fila. Ocorre erro se a fila estiver vazia. Aula 8 - Filas 09/09/21 Herança de Interface para pilhas em Java Para usar um tipo abstrato de dados em Java envolve dois passos: ● Definição de uma Application Programming Interface (API, ou interface), que descreve os nomes dos métodos que o TAD suporta e como eles são declarados e usados; ● Definição de exceções para qualquer erro que possa ocorrer. exemplo de Herança de Interface Herança de Implementação Outro mecanismo que tem essa estrutura abaixo: Lista 01 Questão 2 Crie uma classe QueueArray para implementar o Tipo Abstrato de Dados Fila. Você deve utilizar arrays na implementação e a interface IQueue fornecida. 1. void enqueue(Integer value);2. Integer dequeue() throws Exception; 3. boolean isEmpty(); package com.diegopinheiro.ed1_01_lista; public class QueueArray implements IQueue { private Integer [] listaArray ; private int head; public QueueArray(int capacity) { this.listaArray = new Integer [capacity]; this.head = 0; } @Override public void enqueue(Integer value) { if(this.isFull()) { throw new IllegalStateException(" Nao pode colocar mais que 3"); } listaArray[this.head] = value; this.head ++; } @Override public Integer dequeue() throws Exception { if(this.isEmpty()) { throw new IllegalStateException(" Ta cheio"); } return head; } @Override public boolean isEmpty() { return this.head == 0; } private boolean isFull() { return this.head == this.listaArray.length; } } Revisão public class QueueArray implements IQueue { private Integer[] listaArray; private int head; public QueueArray(int capacity) { this.listaArray = new Integer [capacity]; this.head = 0; } @Override public void enqueue(Integer value) { if(this.isFull()) { throw new IllegalStateException("ta cheio colega"); } listaArray[this.head] = value; this.head++; } private boolean isFull() { return this.head == this.listaArray.length; } @Override public Integer dequeue() throws Exception { Integer num ; if (this.isEmpty()) { throw new IllegalStateException("Vazio"); } num = this.listaArray [head-1] ; this.listaArray[head-1] = null; this.head--; return num; } @Override public boolean isEmpty() { return this.head == 0; } } Lista 01 Questão 3 Implemente o método void reverse(IQueue queueToBeReversed, IStack stackAuxiliary) na classe Utils que reverte a fila queueToBeReversed. Apenas utilize os métodos da IQueue e IStack para reverter a fila queueToBeReversed. Ps: Uma Stack para reverter uma fila, assim vamos empilhar a fila package com.diegopinheiro.ed1_01_lista; import java.util.Iterator; // da onde veio isso?? public class Utils { public static void reverse (IQueue queueToBeReversed, IStack stackAuxiliary) { try { while (!queueToBeReversed.isEmpty()) { stackAuxiliary.push(queueToBeReversed.dequeue()); } while (!stackAuxiliary.isEmpty()) { queueToBeReversed.enqueue(stackAuxiliary.pop()); } }catch(Exception e) { e.printStackTrace(); } } } Ps: try/catch: uso quando não quero que a exceção se perpetue pelo código, pois não vou usar aquele "problema" em nenhum outro lugar. ● try{ … } - linhas de código que podem vir a lançar uma exceção. ● catch(tipo_excessao e) { … } - ação que ocorrerá quando a exceção for capturada. throws: quando quero passar a possível exceção do método que estou para outras classes, quando o tratamento não é necessário naquela classe pois vou precisar da exceção em outra classe. throw: quando eu quero lançar uma exceção/quando quero que aquele método específico de um erro(exceção) Aula 9 - Listas Unicamente Encadeadas 13/09/21 (Faltei Total 3) (Singly Linked Lista) E mais uma estrutura de dados abstrata, dinâmica (seu comprimento pode aumentar ou diminuir), e recursiva. Cada quadrado desse é um node, que vai ter um valor e o next. A lista termina quando o next aponta para null. Como o nome diz, são nodos conectados por links que fazem a referência. Esses links dizem como vai ser o acesso no nodo posterior. Os nodos podem conter dados de qualquer tipo até mesmo objetos de outras classes. Um array é limitado pois temos que declarar seu tamanho, assim se esperamos mais itens vamos declarar mais espaços, e os espaços excedentes podem não ser usados assim vai ter uma perda de desempenho (desperdiçando memória). Já nas listas encadeadas adicionamos e retiramos os elementos de acordo com a demanda (alocação dinâmica de memória). Podemos imaginar como se fosse uma pessoa apontando para outra que tem uma camisa preta, e essa de camisa preta aponta para (mesmo tipo - pessoa) outra de camisa branca e por aí vai, ou a pessoa pode apontar para si mesmo. Inserindo Aula 10 - Listas Unicamente Encadeadas Parte 2 16/09/21 Explicou sobre o equals (retorna boolean) de 20:00 até 40:00. ? == true CompareTo - retorna um inteiro Size Listas Unicamente Encadeadas 1. Percorre o array para saber o tamanho. Começamos pelo head (currentNode = this.head ). 2. O próximo nó e o próprio nó mais value e next assim: currentNode = currentNode.getNext(); 3. Fazer isso enquanto o nó for diferente de null : while(currentNode != null) 4. Como e tamanho vamos incrementar e depois retornar esse tamanho, assim você fecha o que a função pede retornando o incremento; Aula 11 e 12 - Listas Unicamente Encadeadas 20/09/21 a 23/09/21 Delete (questão 6) Deletar um node significa que ele perdeu a referência e o garbage collector do programa percebe isso e desaloca a memória (apaga). Não vamos escrever nada para apagar deixamos para o garbage collector. Vamos pegar o getPrevious Outro exemplo de aula, caso base: aplicado até numa lista com apenas 1 elemento. 1. Encontrar o node anterior ( previous começa no head), assim o previous get.next nao for igual ao no que quer deletar passa para o próximo; 2. Atribuir ao próximo como o próximo do próximo; Para o reverse Dicas and Cheats Listas Unicamente Encadeadas 1. get (obter valor) ele vai ser uma função assim vai ter um retorno e se for set (atribui valor) vai ser um método apenas tendo que colocar parâmetro entre parênteses; 2. O size do SinglyLinkedList vai ser o mesmo de CircularLinkedList: public int size() { int size = 0; SinglyListNode node = this.head; while (node != null) { size++; node = node.getNext(); } return size; } 3. Para o método (função) isOrdered se estiver vazia vai estar ordenada!! 4. Qual a diferença entre ??? SinglyListNode node = this.head; SinglyListNode newHead = new SinglyListNode(this.head,value); 5. No addFirst invés de colocar assim: SinglyListNode newHead = new SinglyListNode(this.head, value); ou SinglyListNode newHead = this.head; 6. Às vezes Diego gosta de simplificar, logo fiquem atentos: public boolean isOrdered(boolean ascending) { if(isEmpty()) { return true; } Integer lastValue; -- Integer lastValue = node.getValue() SinglyListNode node; -- SinglyListNode node = this.head; node = this.head; lastValue = node.getValue(); 7. O método addLast(value) e um espelho do addFirst ; 8. Lembre-se que a ordem dos parâmetros definida pelo construtor na classe SinglyListNode vai ser aplicada em SinglyLinkedList; 9. No addFirst, addLast, isOrdered, reverse e delete, iremos usar o isEmpty(); 10.No delete podemos “deletar”, no início, meio ou fim. Assim sendo Lista 02 1. Crie uma classe SinglyListNode que contém os atributos next do tipo SinglyListNode, um atributo value do tipo Integer, um construtor para inicializar value e next, e os métodos get and set desses atributos. Não utilize uma variável de instância previous. Ps: lista vazia o head == null package com.diegopinheiro.ed01_02_lista; public class SinglyListNode { private SinglyListNode next ; private Integer value; public SinglyListNode(SinglyListNode next, Integer value) { this.next = next; this.value = value; } public SinglyListNode getNext() { return next; } public void setNext(SinglyListNode next) { this.next = next; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } } // Aqui precisamos adicionar dois procedimentos: Funcao equals e toString // em alguma aula ele resumiu isso (aula 10) ?? @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(getClass() != obj.getClass()) // da onde veio getClass?? return false; SinglyListNode other = (SinglyListNode) obj ; return this.value.equals(other.value); } @Override public String toString() { return String.valueOf(this.value); } } 2. Crie uma classe de uma lista unicamente ligada SinglyLinkedList que contenha a referência head para a cabeça da lista do tipo ListNode (não utilize uma variável de instância tail), e contenha os seguintes métodos: a. isEmpty(), que retorna true quando alista está vazia e false caso contrário; package com.diegopinheiro.ed01_02_lista; public class SinglyLinkedList { private SinglyListNode head; public boolean isEmpty() { // ele pede true quando a lista está vazia e false caso contrário; // Inicialmente a lista está vazia, logo o head aponta para null, ai nao precisa fazer if e else return this.head == null; } b. addFirst(value), adiciona o elemento value no início da lista; public void addFirst(Integer value) { // aqui vai criar um novo no SinglyListNode newHead = new SinglyListNode(this.head,value); this.head = newHead; } // aqui adicionamos o value e depois declaramos que a cabeça e o no que acabamos de instanciar c. search(value), que retorna o nó ListNode cujo elemento procurado value se encontra ou null caso o elemento não esteja na lista; public SinglyListNode search(Integer value) { SinglyListNode node = this.head; // ??? while(node != null) { if(value == node.getValue()) { // o que esse getValue faz?? return node; } node = node.getNext(); } return null; } d. size(), retorna o tamanho da lista; public int size() { // esse size vai ser o mesmo para listas circulares int size = 0; SinglyListNode node = this.head; while (node != null) { size++; node = node.getNext(); } return size; } 3. Implemente o método isOrdered(ascending) que retorna true caso os elementos estejam ordenados e false caso contrário. Os elementos podem estar ordenados ascendentemente quando ascending é true (i.e., 1,2,3,4) ou descendentemente quando ascending é false (ie., 4,3,2,1). ???? Está dando loop public boolean isOrdered(boolean ascending) { // pq se está vazia, vai estar ordenada!! if(isEmpty()) { return true; } SinglyListNode node = this.head; // aqui criamos um novo nó e dizemos que e" a cabeça (head) Integer lastValue = node.getValue(); // o último valor e o no while(node.getNext() != null) { /* enquanto o próximo nó não for nulo, não vai estar vazia e assim veremos se é ascendente ou descendente */ node = node.getNext(); if(ascending) { if(lastValue > node.getValue()){ return false; } }else { if(lastValue < node.getValue()){ return false; } } lastValue = node.getValue(); //???? } return true; } 4. Implemente o método addLast(value) na classe SinglyLinkedList que adiciona o value no fim da lista. public void addLast(Integer value) { // espelho do addFirst if(isEmpty()){ // se estiver vazia o último adc é igual ao primeiro por isso chama o addFirst addFirst(value); return; } // lembre-se que a ordem definida pelo construtor em SinglyListNode aplica-se aqui SinglyListNode novoNode = new SinglyListNode(value, null); // Aqui cria um novo no?? SinglyListNode node = this.head; while(node.getNext() != null) { node = node.getNext(); } node.setNext(novoNode); } 5. Implemente o método reverse() na classe SinglyLinkedList que reverte a ordem dos itens. Não crie uma nova instância da SinglyLinkedList ou SinglyListNode. Atualize apenas as referências next de cada SinglyListNode e head da SinglyLinkedList. DÚVIDA public void reverse() { if(isEmpty() || size() == 1) { // nao tira o return pois vai ser o break do if return; } SinglyListNode ultimoNode = this.head; // está invertendo, assim o que era a cabeca passa a ser o ultimo SinglyListNode node = ultimoNode.getNext(); // o próximo node SinglyListNode nextNode = node.getNext(); //pq cria esse?? do { node.setNext(ultimoNode); ultimoNode = node; node = nextNode; if (node != null) { nextNode = node.getNext(); } } while (node != null); node = this.head; this.head = ultimoNode; node = search(node.getValue()); node.setNext(null); } 6. Implemente o método delete(node) na classe SinglyLinkedList. public void delete(SinglyListNode nodeDelete) { if(isEmpty()) { return ; } SinglyListNode ultimoNode = this.head; if(nodeDelete.equals(this.head)) { /* se o nó a ser deletado for o inicio, como vai deletar o início se está dizendo na linha acima que o ultimoNode = this.head*/ this.head = nodeDelete.getNext(); }else { // deletar no meio ou fim while(ultimoNode != null) { if(ultimoNode.getNext().equals(nodeDelete)) { // ultimo vai ser deletado ???? ultimoNode.setNext(nodeDelete.getNext()); // ??? break; } ultimoNode = ultimoNode.getNext(); } } } ====================================================== Lista 02 COMPLETA ====================================================== package com.diegopinheiro.ed01_02_lista; public class SinglyListNode { private SinglyListNode next; private Integer value; public SinglyListNode(Integer value, SinglyListNode next ) { this.next = next; this.value = value; } public SinglyListNode getNext() { return next; } public void setNext(SinglyListNode next) { this.next = next; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } // precisamos adicionar dois procedimentos: Funcao equals e toString @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(getClass() != obj.getClass()) // checando se a classe deles é diferente return false; SinglyListNode other = (SinglyListNode) obj ; return this.value.equals(other.value); } @Override public String toString() { return String.valueOf(this.value); // retorna o valor do no } } ----------------------------------------------------- package com.diegopinheiro.ed01_02_lista; public class SinglyLinkedList { private SinglyListNode head; public boolean isEmpty() { //Inicialmente a lista está vazia, logo o head aponta para null, ai nao precisa fazer if e else return this.head == null; } public void addFirst(Integer value) { // aqui vai criar um novo no SinglyListNode newHead = new SinglyListNode(value, this.head); // tive que trocar a ordem pq?? Obedece a ordem do construtor da classe SinglyListNode this.head = newHead; } public SinglyListNode search(Integer value) { SinglyListNode node = this.head; while(node != null) { if(value == node.getValue()) { return node; } node = node.getNext(); } return null; } public int size() { // esse size vai ser o mesmo para listas circulares int size = 0; SinglyListNode node = this.head; // pq usa SinglyListNode?? while (node != null) { size++; node = node.getNext(); } return size; } public boolean isOrdered(boolean ascending) { // pq se esta vazia, vai estar ordenada?? Meio vago if(isEmpty()) { return true; } SinglyListNode node = this.head; // aqui criamos um novo nó e dizemos que e" a cabeça (head) Integer lastValue = node.getValue(); // o último valor e o no while(node.getNext() != null) { /* enquanto o próximo nó não for nulo não vai estar vazia e assim veremos se e ascendente ou descendente */ node = node.getNext(); if(ascending) { if(lastValue > node.getValue()){ return false; } }else { if(lastValue < node.getValue()){ return false; } } lastValue = node.getValue(); } return true; } public void addLast(Integer value) { // espelho do addFirst if(isEmpty()){ // se estiver vazia o ultimo adc e igual ao primeiro addFirst(value); return; } // lembre-se que a ordem definida pelo construtor em SinglyListNode aplica-se aqui SinglyListNode novoNode = new SinglyListNode(value, null); // Aqui cria um novo no?? SinglyListNode node = this.head; while(node.getNext() != null) { // Pq pega o getNext()??? node = node.getNext(); } node.setNext(novoNode); } public void reverse() { if(isEmpty() || size() == 1) { // Pq nao tira o retunr??? return; } SinglyListNode ultimoNode = this.head; // esta invertendo SinglyListNode node = ultimoNode.getNext(); // ??? SinglyListNode nextNode = node.getNext(); // ??? do { node.setNext(ultimoNode); ultimoNode = node; node = nextNode; if (node != null) { nextNode = node.getNext(); } } while (node != null); node = this.head; this.head = ultimoNode; node = search(node.getValue()); node.setNext(null); } public SinglyListNode getHead() { return this.head; } public void delete(SinglyListNode nodeDelete) { if(isEmpty()) { return ; } SinglyListNodeultimoNode = this.head; if(nodeDelete.equals(this.head)) { /* se o no a ser deletado for o inicio, como vai deletar o inicio se esta dizendo na linha acima que o ultimoNode = this.head*/ this.head = nodeDelete.getNext(); }else { // deletar no meio ou fim while(ultimoNode != null) { if(ultimoNode.getNext().equals(nodeDelete)) { // ultimo vai ser deletado ???? ultimoNode.setNext(nodeDelete.getNext()); // ??? break; } ultimoNode = ultimoNode.getNext(); } } } } Aula 13 - Listas Duplamente Encadeadas 27/09/21 Doubly Linked List Agora os nodes vão ter 3 atributos sendo adicionado o previous que vai fazer referência. Ps: ele comentou sobre label attachment. E aquela que possui duas referências ao invés de uma, permitindo que a lista seja percorrida nos dois sentidos – do início para o final, e do final para o início. Para que isto seja possível, cada nodo apresenta dois elos: um que armazena o endereço do nodo imediatamente anterior na lista (Previous/Anterior) e o outro que armazena o endereço do nodo seguinte (Next/Próximo). Ps: A operação de criação (muda somente o tipo de nodo utilizado) e de destruição da lista duplamente encadeada, vai ser igual da lista simplesmente encadeada. Já as operações de: inserção, remoção e acesso devem ser adaptadas. Adição/ inserção O valor vai ser o valor, o old head não tem (nulo). DoublyListNode newHead = new DoublyListNode(value, this.head, null) if (this.isEmpty ()){ tail = newHead; }else{ head.setPrevious(newHead); } head = newHead; Ele colocou os passos no desenho e no código. Aula 15 - Listas Duplamente Encadeadas parte 3 04/10/21 null Aula 16 - Listas Circulares 07/10/21 Size para Listas Duplamente encadeadas Fez na lista 3 parte 1 questão 2: public int size() { int size = 0; DoublyListNode currentNode = this.head; while(currentNode != null) { size ++; } Dicas and Cheats Listas Duplamente Encadeadas 1. get (obter valor) ele vai ser uma função assim vai ter um retorno e se for set (atribui valor) vai ser um método apenas tendo que colocar parâmetro entre parênteses; 2. Diferença entre atributo e variável ??? 3. O DoublyListNode vai ser a mesma coisa do SinglyListNode, com a diferença que vai ter um atributo a mais: next. 4. O isEmpty()vai ter a mesma implementação da lista single o ideal seria colocar assim: return this.head == null && return this.tail == null; 5. Size vai ser exatamente igual ao da lista SinglyLinkedList: public int size() { int size = 0; // o nó atual e o head, aí enquanto for diferente de nulo, vamos ao próximo e incrementamos o size DoublyListNode currentNode = this.head; while(currentNode != null) { size ++; currentNode = currentNode.getNext(); } return size; } 6. Para o addFirst vamos criar um novo nó, sendo o mesmo um nó que tem o início (head) e não tem fim (null), para dele fazer as condicionais. public void addFirst(Integer value) { DoublyListNode newNo = new DoublyListNode ( value, this.head, null); if(this.isEmpty()) { // se estiver vazio a tail e o novo no(newHead) this.tail = newNo; } else { head.setPrevious(newNo); // senão, a cabeça vai ser o próximo no que é o newNo (newHead) } head = newNo; // ??? no caso a cabeça e igual ao novo no (newHead) } 7. O search vai ser parecido com o size. Vamos criar dois nos para percorrer a lista: temporário ( atribuímos ao this.head) e resultado (atribuímos a null). Se o temporário for igual ao valor retorne o temporário, caso não seja igual, pegamos o próximo. Se não for nenhuma das condições acima retornaremos o resultado. public DoublyListNode search(Integer value) { if(isEmpty()) { return null; } // vamos criar dois nos: temporário e resultado para percorrer a lista DoublyListNode temp = this.head; DoublyListNode result = null; do { if(temp.getValue().equals(value)) { // se o temporário for igual ao valor retorne o temporário return temp; } temp = temp.getNext(); // caso não seja igual pegamos o próximo. }while(temp != null); return result; // Se não for nenhuma das condições acima retornaremos o resultado } 8. O addLast vai ser um espelho do add first, sendo que usa tail pois adiciona por último ( no caso ao invés de criarmos uma nova Cabeça ( newHead), vamos criar um newTail 9. O reverse() dúvida 10. O delete() antes de "deletar" temos que verificar se a lista vai estar vazia ou apenas com um node, por isso checaremos os isEmpty() e o size(). 11. O isOrdered(boolean ascending) antes de confirmar a ordem, temos que verificar se a lista vai estar vazia ou apenas com um node, por isso checaremos os isEmpty() e o size(), assim se estiver vazia vai estar ordenada e se o tamanho for único vai estar ordenada também 12. Lista 3 - Parte 1 Questão 1 - Crie uma nova classe DoublyListNode e, além dos value e next, adicione o atributo previous do tipo DoublyListNode. Crie um construtor para inicializar os 3 atributos, e os métodos get and set dos atributos. package com.diegopinheiro.ed01_03_lista; public class DoublyListNode { private Integer value; private DoublyListNode next; // ja tinha esse private DoublyListNode previous; public DoublyListNode(Integer value, DoublyListNode next, DoublyListNode previous) { // construtor this.value = value; // inicializar os atributos this.next = next; this.previous = previous; } public Integer getValue() { return value; } public void setValue(Integer value) { this.value = value; } public DoublyListNode getNext() { return next; } public void setNext(DoublyListNode next) { this.next = next; } public DoublyListNode getPrevious() { return previous; } public void setPrevious(DoublyListNode previous) { this.previous = previous; } PS: Ele falou anteriormente sobre esse equals @Override public boolean equals(Object obj) { if(this == obj) { return true; } if(obj instanceof DoublyListNode) { DoublyListNode other = (DoublyListNode) obj; return this.value.equals(other.value); } return false; ????????? Ou @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(getClass() != obj.getClass()) // checando se a classe deles é diferente return false; DoublyListNode other = (DoublyListNode) obj ; return this.value.equals(other.value); } @Override public String toString() { return String.valueOf(this.value); // retorna o valor do no } } Questão 2 -Crie uma outra classe DoublyLinkedList que, além do atributo head para a cabeça da lista da DoublyLinkedList, também contenha a referência tail para a calda a lista. package main.java.com.diegopinheiro.ed01_03_lista; public class DoublyLinkedList { private DoublyLinkedList head, tail; public DoublyLinkedList(DoublyListNode head, DoublyListNode tail) { this.head = head; this.tail = tail; } public DoublyListNode getHead() { return head; } public void setHead(DoublyListNode head) { this.head = head; } public DoublyListNode getTail() { return tail; } public void setTail(DoublyListNode tail) { this.tail = tail; } Questão 3 - Considerando que a DoublyLinkedList também tem um atributo tail e que o DoublyNodeList agora possui o novo atributo previous, implemente os seguintes métodos: 1. isEmpty(), que retorna true quando a lista está vazia e false caso contrário; 2. size(), retorna o tamanho da lista; 3. addFirst(value), adiciona o elemento elem no início da lista; 4. search(value), que retorna o nó ListNode cujo elemento procurado elem se encontra ou null caso o elemento não esteja na lista; 5. addLast(value) que adiciona no fim da lista; 6. reverse() que reverte a ordem dos itens da lista; 7. o método delete(node) que deleta no node da lista. 8. isOrdered(ascending) que retorna true caso os elementos estejam ordenados e false caso contrário. Os elementos podem estar ordenados ascendentemente quando ascending é true (i.e., 1,2,3,4) ou descendentemente quando ascending é false (ie., 4,3,2,1). package com.diegopinheiro.ed01_03_lista; public class DoublyLinkedList { private DoublyListNode head, tail; public DoublyLinkedList(DoublyListNode head, DoublyListNodetail) { this.head = head; this.tail = tail; } public DoublyListNode getHead() { return head; } public void setHead(DoublyListNode head) { this.head = head; } public DoublyListNode getTail() { return tail; } public void setTail(DoublyListNode tail) { this.tail = tail; } 1) public boolean isEmpty() { return this.head == this.tail; // o ideal seria colocar assim: //return this.head == null && return this.tail == null } 2) public int size() { int size = 0; DoublyListNode currentNode = this.head; while(currentNode != null) { size ++; currentNode = currentNode.getNext(); o no corrido e o head, aí enquanto for diferente de nulo, vamos ao próximo e incrementamos o size } return size; } 3)public void addFirst(Integer value) { DoublyListNode newHead = new DoublyListNode(value, this.head, null); // vamos criar um novo nó, sendo o mesmo um nó que tem o início (head) e nao tem fim (null),para dele fazer as condicionais // essa ordem obedece a ordem do CONSTRUTOR // previous e null if(this.isEmpty()) { // se estiver vazio a tail e o novo no(newHead) tail = newHead; }else { head.setPrevious(newHead); //senão, a cabeça vai ser o próximo no que é o newHead. Pq usa o Previous??? } head = newHead; // Pq não usa o this.head??? no caso a cabeça e igual ao novo no (newHead)} 5) public void addLast(Integer value) { // vai ser um espelho do add first, sendo que usa tail pois adc por último DoublyListNode newTail= new DoublyListNode(value,null, this.tail); if(this.isEmpty()) { this.head = newTail; //se está vazio a cabeça e o rabo }else { tail.setPrevious(newTail); // Previous ? } tail = newTail; } } 4) public DoublyListNode search(Integer value) { // vai ser a mesma coisa do size if(this.isEmpty()) { return null; } // percorrer a lista DoublyListNode resultado = null; DoublyListNode temporaria = this.head; while(temporaria != null) { if(temporaria.getValue().equals(value)) { return temporaria; } temporaria = temporaria.getNext(); } return resultado; } 6) public void reverse() { // como vai reverter vamos ter que atribuir 4 nos para as diversas situacoes DoublyListNode nodeAnterior = this.head; // no caso e o 1 no DoublyListNode nodeMeio = this.head.getNext(); // pegamos o proximo DoublyListNode nodeProximo = nodeMeio.getNext(); // proximo do proximo DoublyListNode oldHead = this.head; do { nodeMeio.setNext(nodeAnterior); // proximo troca para o meio e o meio vai para o anterior nodeMeio.setPrevious(nodeProximo); // a anterior do nodeMeio era o anteriorNode, sendo que agora é o próximo nodeAnterior = nodeMeio; nodeMeio = nodeProximo; if(nodeMeio != null) { nodeProximo = nodeMeio.getNext(); // o primeiro no nao esta sendo alterado } }while(nodeMeio != null); // se for nulo vai ter apenas o nodeAnterior e assim não vai reverter // ???? toda essa passagem não entendi oldHead.setPrevious(oldHead.getNext()); oldHead.setNext(null); // virou o tail, ai o próximo do tail sempre e null this.tail = this.head; this.head = nodeAnterior; } 7) public void delete(DoublyListNode nodeDelete) { // antes de "deletar" temos que verificar se a lista vai estar vazia ou apenas com um node if(isEmpty() || size() == 1) { // pq nao tira o head e tail é só colocar o return?? this.head = null; this.tail = null; return; // se não colocar o return ele vai para parte de baixo } DoublyListNode anteriorNode = nodeDelete.getPrevious(); // atribuindo a um node previousNode que deleta o node anterior DoublyListNode proximoNode = nodeDelete.getNext(); // atribuindo a um node nextNode que deleta o próximo node if(nodeDelete.equals(this.head)) { // se o nor a ser deletado for a (igual) cabeça, ao próximo node deve ser nulo proximoNode.setPrevious(null); this.head = proximoNode; // atualizando a cabeça para o próximo node } else if(nodeDelete.equals(this.tail)) { // se o nor a ser deletado for a (igual) calda, ao node anterior deve ser nulo anteriorNode.setNext(null); this.tail = anteriorNode; // atualizando a calda para o node anterior } else { // se nenhuma das condições acima for encaixada faremos: proximoNode.setPrevious(anteriorNode); // ????? anteriorNode.setNext(proximoNode); // ????? } } 8) public boolean isOrdered(boolean ascending) { if (isEmpty() || size() == 1) { return true; } DoublyListNode node = this.head; Integer previousValue; while(node.getNext() != null) { node = node.getNext(); previousValue = node.getPrevious().getValue(); if (ascending) { if (previousValue > node.getValue()) { //verifica se a ordem crescente esta incorreta return false; } } else { if (previousValue < node.getValue()) { //verifica se a ordem decrescente esta incorreta return false; } } } return true; } ======================================OU============= Tirar essa dúvida com Aquiles: public boolean isOrdered(boolean ascending) { // antes de confirmar a ordem, temos que verificar se a lista vai estar vazia ou apenas com um node, por isso checaremos os isEmpty() e o size(). if (isEmpty() || size() == 1) { // se estiver vazia vai estar ordenada e se o tamanho for único vai estar ordenada também return true; } DoublyListNode node = this.head; Integer value; while(node.getNext() != null) { // enquanto o proximo no for diferente de nulo, significa que nao chegou ao fim this.head.getNext(); value = this.head.getNext().getValue(); if(ascending) { if(value > this.head.getValue()) { //verifica se a ordem crescente esta incorreta return false; } else { if(value < this.head.getValue()) { //verifica se a ordem decrescente esta incorreta return false; } } } } return true; } ======================================================== Revisão package com.diegopinheiro.ed01_03_lista; public class DoublyLinkedList { private DoublyListNode head; private DoublyListNode tail; public DoublyListNode getHead() { return head; } public void setHead(DoublyListNode head) { this.head = head; } public DoublyListNode getTail() { return tail; } public void setTail(DoublyListNode tail) { this.tail = tail; } public boolean isEmpty() { return this.head == null; // mesma implementação da lista single // o ideal seria colocar assim: return this.head == null && return this.tail == null; } public void addFirst(Integer value) { DoublyListNode newHead = new DoublyListNode(value, this.head, null); // essa ordem obedece a ordem do CONSTRUTOR //criação de novo no previous e null if(this.isEmpty()) { this.tail = newHead; }else { DoublyListNode oldHead = this.head; oldHead.setPrevious(newHead); // pq coloca o set?? Previous??? } this.head = newHead; } public int size() { int size = 0; DoublyListNode currentNode = this.head; while(currentNode != null) { size ++; currentNode = currentNode.getNext(); } return size; } public void addLast(Integer value) { // vai ser um espelho do add first, sendo que usa tail pois adc por último DoublyListNode newTail = new DoublyListNode(value, null, this.tail); if(this.isEmpty()) { this.head = newTail; // se está vazio a cabeça e o rabo }else { this.tail.setNext(newTail); // tem que ser set pois ele muda, o get retorna } this.tail = newTail; } public DoublyListNode search(Integer value) { // vai ser a mesma coisa do size if(this.isEmpty()) { return null; } // percorrer a lista DoublyListNode temporaria = this.head; while(temporaria != null) { if(temporaria.getValue().equals(value)) { return temporaria; } temporaria = temporaria.getNext(); } return null; } public void delete(DoublyListNode nodeDelete) { // antes de "deletar" temos que verificar se a lista vai estar vazia ou apenas com um node if(isEmpty() || size() == 1 ) { this.head = null; this.tail = null; return ; // se não colocar o return ele vai para parte de baixo } DoublyListNode anteriorNode = nodeDelete.getPrevious(); // criando um no previousNode DoublyListNode proximoNode = nodeDelete.getNext(); if(nodeDelete.equals(this.head)) { proximoNode.setPrevious(null); this.head = proximoNode; } else if(nodeDelete.equals(this.tail)) { anteriorNode.setNext(null); this.tail= anteriorNode; } else { proximoNode.setPrevious(anteriorNode); anteriorNode.setNext(proximoNode); } } public boolean isOrdered(boolean ascending) { return false; } public void reverse() { DoublyListNode anteriorNode = this.head; DoublyListNode meioNode = this.head.getNext(); DoublyListNode proximoNode = this.head.getNext().getNext(); DoublyListNode oldHead = this.head; do { meioNode.setNext(anteriorNode); // desenhar meioNode.setPrevious(proximoNode); anteriorNode = meioNode; meioNode = proximoNode; if(meioNode != null) { proximoNode = meioNode.getNext(); // o primeiro no nao esta sendo alterado } }while(meioNode != null); oldHead.setPrevious(oldHead.getNext()); oldHead.setNext(null); this.tail = this.head; this.head = anteriorNode; } } Questão 4 Crie uma classe Utils e implemente o método static isPalindrome(list) que recebe uma list do tipo DoublyLinkedList e retorna true caso a sequência de values na list seja um palíndromo e false caso contrário. Um palíndromo é uma sequência que tem a propriedade de poder ser lida tanto da esquerda para a direita quanto da direita para a esquerda. Por exemplo, 2 -> 5 -> 5 -> 2 é um palíndromo e 2 -> 5 -> 1 -> 2 não é um palíndromo. Listas Circulares 07/11/21 Dicas and Cheats Listas Circulares 1. O CircularListNode vai ser igual ao DoublyListNode no caso de declarar as variáveis: public class CircularListNode { private Integer value; private CircularListNode next, previous; 2. Depois gera os get e set lembrando: get - (obter valor) ele vai ser uma função assim vai ter um retorno set - (atribui valor) vai ser um método apenas tendo que colocar parâmetro entre parênteses; Lista 3 - Parte 2 Questão 5 - Crie uma class CircularLinkedList que, em vez de possuir head and tail, possui uma sentinel do tipo CircularListNode inicializado com ambos next e previous apontando para sentinel e implemente os seguintes métodos: 1. isEmpty(), que retorna true quando a lista está vazia e false caso contrário; 2. addFirst(elem), adiciona o elemento elem no início da lista; 3. search(elem), que retorna o nó ListNode cujo elemento procurado elem se encontra ou null caso o elemento não esteja na lista; 4. size(), retorna o tamanho da lista; 5. addLast(elem) que adiciona no fim da lista; public void addLast(Integer value) { CircularListNode node = new CircularListNode(value, null, getTail()); if(isEmpty()) { setHead(node); }else { getTail().setNext(node); } setTail(node); } ========================================= public void addLast(Integer value) { CircularListNode oldNode = getTail(); CircularListNode newNode = new CircularListNode(value, null, oldNode); oldNode.setNext(newNode); setTail(newNode); } 6. reverse() que reverte a ordem dos itens da lista; 7. o método delete(node) que deleta no node da lista. if(isEmpty() || size() == 1 ) { this.sentinel.setNext(this.sentinel); this.sentinel.setPrevious(this.sentinel); return ; // se nao colocar o return ele vai para parte de baixo } CircularListNode anteriorNode = nodeDelete.getPrevious(); // criando um no previousNode CircularListNode proximoNode = nodeDelete.getNext(); if(nodeDelete.equals(getHead())) { setHead(proximoNode); } else if(nodeDelete.equals(getTail())) { setTail(anteriorNode); } else { proximoNode.setPrevious(anteriorNode); anteriorNode.setNext(proximoNode); } } ==================================== public void delete(CircularListNode nodeDelete) { CircularListNode anteriorNode = nodeDelete.getPrevious(); CircularListNode proximoNode = nodeDelete.getNext(); anteriorNode.setNext(proximoNode); // basta tirar a referencia dele e o garbagge colector destroi proximoNode.setPrevious(anteriorNode); } ======================================================= public boolean isOrdered(boolean ascending) { if(isEmpty()) { return true; } CircularListNode node = getHead(); do { if(ascending) { if(node.getValue() > node.getNext().getValue()) { return false; } }else { if(node.getValue() < node.getNext().getValue()) { return false; } } node = node.getNext(); }while (node.getNext() != this.sentinel); return true; } Questão 6 - Implemente o método copy() na CircularLinkedList que retorna uma cópia também do tipo CircularLinkedList baseado no objeto em que o método foi chamado. Utilize o método addLast(value) implementado anteriormente. Questão 7 - Implemente o método isEquals(list) na CircularLinkedList que recebe um list do tipo CircularLinkedList e retorna true caso a list seja igual a lista na qual o método foi chamado ou false caso contrário. public boolean isEquals(CircularLinkedList l2) { if(size() != l2.size()) { return false; } CircularListNode nodeList1 = getHead(); CircularListNode nodeList2 = l2.getHead(); do { if(nodeList1.getValue() != nodeList2.getValue()) { return false; } nodeList1 = nodeList1.getNext(); nodeList2 = nodeList2.getNext(); }while(nodeList1.getNext() != this.sentinel); // se nao colocar getNext() o do While vai querer pegar o rpxoximo = null point exception return true; } Questão 8 - Implemente o método get(index) na CircularLinkedList que percorre a lista circular e obtém o elemento da posição index da lista e retorna uma exceção caso a lista esteja vazia. Caso index > 0 continue circulando a lista até encontrar o valor. Dado, por exemplo, a list = {1,2,3}, list.get(0) == list.get(3) == list.get(6) == 1. Da mesma forma, list.get(1) == list.get(4) == list.get(7) == 2. Dica: você tem que “pular” a sentinela. public int get(Integer index ) throws Exception { if(isEmpty()) { throw new Exception("List is empty"); } CircularListNode node = getHead(); for(int i = 0; i < index ; i ++) { node = getSuccessor(node); } return node.getValue(); } Lista 03 COMPLETA package com.diegopinheiro.ed01_03_lista; public class CircularLinkedList { private CircularListNode sentinel; // criou uma etiqueta public CircularLinkedList() { this.sentinel = new CircularListNode(null, null, null); // sentinela sem valor this.sentinel.setNext(this.sentinel); this.sentinel.setPrevious(this.sentinel); } public boolean isEmpty() { return getHead() == this.sentinel; } public CircularListNode getHead() { return this.sentinel.getNext(); } public void addFirst(Integer value) { CircularListNode node = new CircularListNode(value, getHead(), this.sentinel); if(isEmpty()) { setTail(node); }else { getHead().setPrevious(node); } setHead(node); } public void setHead(CircularListNode node) { node.setPrevious(this.sentinel); this.sentinel.setNext(node); } public void setTail(CircularListNode node) { node.setNext(this.sentinel); this.sentinel.setPrevious(node); } public int size() { int size = 0; CircularListNode currentNode = this.getHead(); while(currentNode != this.sentinel) { size ++; currentNode = currentNode.getNext(); } return size; } public void addLast(Integer value) { CircularListNode node = new CircularListNode(value, null, getTail()); if(isEmpty()) { setHead(node); }else { getTail().setNext(node); } setTail(node); } public boolean isOrdered(boolean ascending) { return false; } public CircularListNode search(Integer value) { if(isEmpty()) { return null; } CircularListNode auxilio = getHead(); while(auxilio != this.sentinel) { if(auxilio.getValue() == value) { return auxilio; } auxilio = auxilio.getNext(); } return null; } public void delete(CircularListNode nodeDelete) { if(isEmpty() || size() == 1 ) { this.sentinel.setNext(this.sentinel); this.sentinel.setPrevious(this.sentinel); return ; // se nao colocar o return ele vai para parte de baixo } CircularListNode anteriorNode = nodeDelete.getPrevious(); // criando um no previousNode CircularListNode proximoNode = nodeDelete.getNext(); if(nodeDelete.equals(getHead())) { setHead(proximoNode); } else if(nodeDelete.equals(getTail())) { setTail(anteriorNode); } else { proximoNode.setPrevious(anteriorNode); anteriorNode.setNext(proximoNode); } } public CircularListNode getTail() { return this.sentinel.getPrevious(); } public boolean isEquals(CircularLinkedListl2) { return false; } public CircularLinkedList copy() { CircularLinkedList lista = new CircularLinkedList(); CircularListNode auxilio = getHead(); while(auxilio != this.sentinel) { lista.addLast(auxilio.getValue()); auxilio = auxilio.getNext(); } return lista; } public int get(int i) throws Exception { if(isEmpty()) { throw new Exception("List is empty"); } return 0; } public CircularListNode getSuccessor (CircularListNode currentNode) throws Exception { if(isEmpty()) { throw new Exception("List is empty"); } if(currentNode.getNext() == this.sentinel) { return currentNode.getNext().getNext(); } return currentNode.getNext(); } public void reverse() { } } Aula 16 07/10/21 Quando uma lista linear encadeada apresenta um elo ligando o último nodo ao primeiro, ela se torna uma lista circular. As operações apresentadas para listas simplesmente encadeadas podem ser adaptadas para listas circulares. A criação da lista não é alterada, uma vez que somente o ponteiro da lista é inicializado. A lista é vazia quando o ponteiro para o seu início é nulo. A operação de destruição da lista é praticamente a mesma, mudando somente a identificação do último nodo a ser liberado, que é aquele que contém o endereço do primeiro em seu campo de elo. Já as operações de inserção, remoção e busca apresentam algumas alterações SENTINEL - o próximo dele é ele mesmo e o anterior é ele mesmo. Não temos mais head e tail, são trocados por getHead e getTail . Inicializamos o Sentinel. Add First Ps: list node tem 3 variáveis de instância?? passo e criar o nó, depois CircularListNode newHead = new CircularListNode (value, getHead, sentinel) if(isEmpty()){ } getHead().setPrevious(newHead); setHead(newHead); Ps: o previous vai ser sempre o sentinel Ps: esse getHead faz o papel do oldHead (Diego prefere colocar oldHead pois hoje está fácil de perceber que está implícito, mas em 10 anos na frente não saberemos). Aula 18 14/10/21 Considere pessoas dispostas em um círculo para serem executadas uma a uma até que apenas uma sobreviva. As n pessoas são colocadas em círculo nas posições de 0 até n-1. Partindo da posição 0, cada cada m-ésima vai sendo executada percorrendo o círculo até que apenas 1 pessoa sobreviva. O josephus problem consiste em encontrar qual a posição inicial uma pessoa deve escolher para não ser executada. Crie a classe JosephusProblem e implemente o método estático Integer[] solve(int m, int n) para retornar a ordem na qual as pessoas são executadas. - Por exemplo, solve(2,7) deve retornar {1, 3, 5, 0, 4, 2, 6}. Ou seja, a pessoa na posição 6 sobrevive. - Por exemplo, solve(4,7) deve retornar {3, 0, 5, 4, 6, 2, 1}. Ou seja, a pessoa na posição 1 sobrevive. 1. Utilize uma CircularLinkedList 2. Os métodos get, search, e delete podem ajudar; 3. A criação de um método getSuccessor(node) na lista circular pode ajudar a evitar retornar a sentinel; 4. A criação de um get(currentNode, index) pode ajudar também. Aula 19 18/10/21 Ele foi convencido a não fazer a prova hoje!! Delete(node) Ele falou novamente do garbage collector, assim vamos tirar as referências do no que queremos deletar. Para fazer um by-pass” vamos setar o anterior assim: next = nodeDelete.getNext(); previous = nodeDelete.getPrevious(); next.setPrevious(previous); previous.setNext(next); Nesse ultimo print serve para deletar o ultimo no. ps: 8:36 - mostrou como era o delete antigo com 2 linhas Prova 1 1. Sua tela inteira deve estar compartilhada durante todo o tempo da avaliação, caso contrário sua avaliação será anulada. 2. Você deve estar presente na sala durante todo o tempo da avaliação caso contrário sua avaliação será anulada. 3. Você deve utilizar o projeto java disponibilizado em formato .ZIP no classroom da disciplina. 4. Você pode reutilizar qualquer código implementados por você em sua listas da disciplina de qualquer forma. 5. Sua implementação deve estar dentro da pasta src/main/java (não coloque dentro da pasta src/test/java). 6. A submissão deve conter todo o projeto compactado em formato .ZIP 7. O nome do arquivo .ZIP submetido deve respeitar a nomenclatura recebida exceto NOME_SOBRENOME que devem ser substituídos por seu nome e sobrenome, respectivamente. 8. A submissão não deve ser feita após o prazo (nem 1 minuto a mais) Crie uma class CircularLinkedList que, em vez de possuir head and tail, possui uma sentinel do tipo ListNode inicializado com ambos next e previous apontando para sentinel. Considerando a CircularLinkedList criada, faça as questões a seguir. Questão 1 Implemente os métodos 1. isEmpty(), que retorna true quando a lista está vazia e false caso contrário; 2. addFirst(value), adiciona o elemento value no início da lista; 3. addLast(value) que adiciona no fim da lista; 4. reverse() que reverte a ordem dos nós da lista; 5. size() que retorna a quantidade de nós na lista; Questão 2 Implemente o método toString() que retorna a representação da lista em string como uma sequência de cada value contido na lista. Exemplo: [1, 2, 3, 4] Questão 3 Implemente um método copy() que retorna uma cópia também do tipo CircularLinkedList baseado no objeto em que o método foi chamado. Utilize o método addLast(value) implementado anteriormente. Não modifique a lista original na qual o método copy() foi chamado. Questão 4 Implemente o método isReverse(otherList) em uma CircularLinkedList que recebe como parâmetro otherList, um objeto também também do tipo CircularLinkedList, e retorna true caso otherList esteja na ordem revertida em relação à lista no qual o método isReverse foi chamado. Por exempl, caso list seja {1,2,3} e otherList seja {3,2,1}, então list.isReverse(otherList) retorna true. Prova 2 Crie uma class CircularLinkedList que, em vez de possuir head and tail, possui uma sentinel do tipo ListNode inicializado com ambos next e previous apontando para sentinel. Considerando a CircularLinkedList criada, faça as questões a seguir. Questão 1 Implemente os métodos 1. isEmpty(), que retorna true quando a lista está vazia e false caso contrário; 2. addFirst(value), adiciona o elemento value no início da lista; 3. addLast(value) que adiciona no fim da lista; 4. reverse() que reverte a ordem dos nós da lista; 5. size() que retorna a quantidade de nós na lista; Questão 2 Implemente o método toString() que retorna a representação da lista em string como uma sequência de cada value contido na lista. Exemplo: [1, 2, 3, 4] Questão 3 Implemente o método deleteAll(value) que deleta todos os nós da lista cujo value é value. Questão 4 Implemente o método get(index) na CircularLinkedList que percorre a lista circular e obtém o elemento da posição index da lista ou retorna uma exceção caso a lista esteja vazia. Index pode ser positivo ou negativo. Por exemplo, se list = {1,2,3,4}, então - list.get(0) == list.get(4) == list.get(-4) == list.get(8) == list.get(-8) == 1. - list.get(1) == list.get(-3) == list.get(5) == list.get(-7) == 2. Projeto Considere pessoas dispostas em um círculo para serem executadas uma a uma até que apenas uma sobreviva. As n pessoas são colocadas em círculo nas posições de 0 até n-1. Partindo da posição 0, cada cada m-ésima vai sendo executada percorrendo o círculo até que apenas 1 pessoa sobreviva. O josephus problem consiste em encontrar qual a posição inicial uma pessoa deve escolher para não ser executada. Crie a classe JosephusProblem e implemente o método estático Integer[] solve(int m, int n) para retornar a ordem na qual as pessoas são executadas. - Por exemplo, solve(2,7) deve retornar {1, 3, 5, 0, 4, 2, 6}. Ou seja, a pessoa na posição 6 sobrevive. - Por exemplo, solve(4,7) deve retornar {3, 0, 5, 4, 6, 2, 1}. Ou seja, a pessoa na posição 1 sobrevive. 1. Utilize uma CircularLinkedList 2. Os métodos get, search, e delete podem ajudar; 3. A criação de um método getSuccessor(node) na lista circular pode ajudar a evitar retornar a sentinel; 4. A criação de um get(currentNode, index) pode ajudar também. Lista: 04 – Pilhase Filas com Listas Circulares Interface como se fosse um conjunto.A intersecção entre esses e em comum entre eles. Questão 1 Considerando a interface genérica IStack<Value> de Value, implemente a classe genérica StackCircularLinkedList<Value> de Value que implements IStack<Value>, ou seja, faz herança de interface (i.e., subtyping apenas). Utilizando uma Lista Circular com sentinela como base, a classe StackCircularLinkedList<Value> deve possuir os seguintes métodos: 1. Value pop() throws Exception 2. void push(Value value) 3. boolean isEmpty() Questão 2 Considerando a interface genérica IQueue<Value> de Value, implemente a classe genérica StackCircularLinkedList<Value> de Value que implements IQueue <Value>, ou seja, faz herança de interface (i.e., subtyping apenas). Utilizando uma Lista Circular com sentinela como base, a classe QueueCircularLinkedList<Value> deve possuir os seguintes métodos: 1. void enqueue(Value item) 2. Value dequeue() throws Exception 3. boolean isEmpty() package com.diegopinheiro.ed01_04_lista; public class CircularListNode <Value>{ private Value value; private CircularListNode <Value> next; private CircularListNode <Value> previous; public CircularListNode(Value value, CircularListNode <Value> next, CircularListNode <Value> previous) { this.value = value; this.next = next; this.previous = previous; } public <Value>Object getValue() { return this.value; } public void setValue(Value value) { // this.value = value; } public CircularListNode <Value> getNext() { return next; } public void setNext(CircularListNode <Value> next) { this.next = next; } public CircularListNode <Value> getPrevious() { return previous; } public void setPrevious(CircularListNode <Value> previous) { this.previous = previous; } @Override public boolean equals (Object obj) { CircularListNode other = (CircularListNode) obj; return this.value.equals(this.value); } @Override public String toString() { return String.valueOf(this.value); } } package com.diegopinheiro.ed01_04_lista; public class CircularLinkedList <Value>{ public CircularListNode <Value> sentinel; public CircularLinkedList() { this.sentinel = new CircularListNode(0, null, null); this.sentinel.setNext(this.sentinel); this.sentinel.setPrevious(this.sentinel); } public boolean isEmpty() { return getHead() == this.sentinel; // return this.sentinel.getNext() == this.sentinel; } public CircularListNode getHead() { return this.sentinel.getNext(); } public CircularListNode getTail() { return this.sentinel.getPrevious(); } public void setHead(CircularListNode node) { node.setPrevious(this.sentinel); this.sentinel.setNext(node); } public void setTail(CircularListNode node) { node.setNext(this.sentinel); this.sentinel.setPrevious(node); } public void addFirst(Value value) { CircularListNode oldHead = this.sentinel.getNext(); CircularListNode newHead = new CircularListNode(value, oldHead, this.sentinel); oldHead.setPrevious(newHead); this.sentinel.setNext(newHead); } public void addLast(Value value) { CircularListNode oldTail = this.sentinel.getNext(); CircularListNode newTail = new CircularListNode(value, this.sentinel, oldHead); oldTail.setNext(newTail); this.sentinel.setNext(newHead); } public CircularListNode getSuccessor (CircularListNode <Value> currentNode) throws Exception { if(isEmpty()) { throw new Exception("List is empty"); } if(currentNode.getNext() == this.sentinel) { return currentNode.getNext().getNext(); } return currentNode.getNext(); } } package com.diegopinheiro.ed01_04_lista; public class StackCircularLinkedList <Value> implements IStack <Value> { private CircularLinkedList <Value> list ; //this.stack = new Integer[value]; public StackCircularLinkedList () { // construtor para inicializar this.list = new CircularLinkedList<Value>(); } @Override public boolean isEmpty() { return this.list.isEmpty(); } @Override public void push(Value key) { this.list.addFirst(key); // antes de adc temos que saber se a pilha está cheia ou vazia //if (this.isFull()) { // throw new IllegalStateException("Nao da"); } // nao tem o isFull pois so precisamos de apenas as funcoes da pilha @Override public Value pop() throws Exception { Integer num; if (this.isEmpty()) { throw new IllegalStateException("Stack is Empty"); } else { CircularListNode node = list.getHead(); list.delete(node); return (Value) node.getValue(); } return null; } } package com.diegopinheiro.ed01_04_lista; public class QueueCircularLinkedList<value> { public boolean isEmpty() { return false; } public void enqueue(Integer valueFirst) { } public Integer dequeue() { return null; } } Aula 23 01/1/21 Aula 24 04/01/21 Stack com singly Linked List O push se traduz num addFirst ou num addLast: Para um pop: - verificar se está vazia node = getHead() Num processo inverso seria no addLast: ---------------------------------------- 8:49 Aula 27 18/11/21 Quando formos criar nossos nós public class Node < key implements Comparable < key> , Value > { private Key key; private Value value; private Node < key, value >; left; private Node < key, value > right; Árvores Tipo específico de grafos. Precisa da raiz para existir, eles podem estar ligados de forma direta ou indireta. No caso o grau vai ser determinado pela quantidade de nós que forem criados a partir de outro Árvores Binárias Consideramos que uma árvore vai ter subárvores, podendo elas estarem vazias ou não . Árvore binária de Busca - os nós possuem : 1. Comparable Key 2. Value 3. Restrição de Busca Em uma BST cada nó possui uma comparable key ( respectivo Value, e satisfaz a restrição que a key de qualquer nó é maior que as keys de qualquer nó em sua subárvore esquerda e menor que as keys de qualquer nó da substring direita. Aula 22/11/21 O A e menor que E por isso fica abaixo, podemos ver o no como um nó ou uma árvore, 8:00 até 8:34 public Value get (key x) { return get(this.root, key) ; private Value get ( node <key,value> x, key x ) { // métodos com o mesmo nome o que os diferencia são os argumentos if(x == null ){ return null; } // se não estiver vazia: int compare = key.compareTo(x.getkey()); if (compare < 0 ){ return get(x.getLeft() , key ); } else if(compare > 0 ){ return get(x.getRight(), key); } else { return x.getValue(); } Aula 25/11/21 Lista 5 - Árvore Binária de busca Subclasse - Subtipos - herda interface usando implements extends - Aula 29/11/21 public void put Aula 31 - 02/12/21 In order (x) inOrder(x.getL3eft) visit(x) atualizar imagem visitação em profundidade Visitação (breadthFirst) 08: 09 Inicializa a pilha com root. Ordem diferente vamos precisar de uma outra estrutura de dados se o right do E não for null coloca na pilha e se o left também coloca na pilha. 8:25 - pilha e busca de profundidade - fila busca de http://www2.ic.uff.br/~vanessa/material/ed/04-ArvoresBinariasBusca.pdf Diversas aplicações precisam buscar um determinado valor em um conjunto de dados. Árvores binárias possibilitam buscas com eficiência Exemplo: buscar dados de uma pessoa que possui um determinado CP, são armazenados numa árvore binária de busca e o CPF funciona como “chave”, pois é único para cada pessoa. Aula 32 - Delete delete(x node, key key ) Lista 5 Parte 1 Implemente uma classe genérica Node<Key, Value> em que a classe Value possa ser de qualquer tipo e a classe Key tem que extends Comparable<Key>. A classe Node deve possuir os atributos (e respectivos métodos get e set) a seguir: 1. key do tipo Key; 2. value do tipo Value; 3. left do tipo Node<Key, Value>; 4. right do tipo Node<Key, Value>; e 5. size do tipo int. Parte 2 package com.diegopinheiro.ed1_05; public class TreeNode <Key extends Comparable <Key> ,Value> { private Key key; private Value value; private int size; http://www2.ic.uff.br/~vanessa/material/ed/04-ArvoresBinariasBusca.pdf private TreeNode <Key, Value> left; private TreeNode <Key, Value> right; public int getSize() { return size; }public void setSize(int size) { this.size = size; } public Key getKey() { return key; } public void setKey(Key key) { this.key = key; } public Value getValue() { return value; } public void setValue(Value value) { this.value = value; } public TreeNode<Key, Value> getLeft() { return left; } public void setLeft(TreeNode<Key, Value> left) { this.left = left; } public TreeNode<Key, Value> getRight() { return right; } public void setRight(TreeNode<Key, Value> right) { this.right = right; } } Implemente uma classe genérica BinarySearchTree<Key, Value> em que a classe Value possa ser de qualquer tipo e a classe Key tem que extends Comparable<Key>. Implemente os seguintes métodos: 1. Value get(Key key), que recebe um Key e retorna um Value encontrado; 2. void put(Key key, Value value) que adiciona um Value na Key; 3. int size() que retorna um int com a quantidade de nós; 4. Key min() que retorna a Key de menor valor; 5. Key max() que retorna a Key de maior valor; 6. void delete(Key key) que remove o nó associado com a Key; package com.diegopinheiro.ed1_05; public class BinarySearchTree <Key extends Comparable <Key> ,Value> { private TreeNode <Key,Value> root; public void delete(String string) { } public void put(String value, Key key ) { } public void put(Key key, Value value) { // Aula 29/11 // root - rotula null de comeco this.root = this.put(this.root, key, value); // vai ser associado a esse put } private TreeNode<Key,Value> put(TreeNode<Key, Value> x , Key key, Value value){ if(x == null) { return new TreeNode<Key,Value>(key,value,1); } int emp = key.compareTo(x.getKey()); if(emp < 0) { TreeNode <Key,Value> leftNode = this.put(x.getLeft(),key, value); x.setLeft(leftNode); }else if (emp > 0) { TreeNode<Key, Value> rightsubTreenewwithPuttedNode = this.put(x.getRight(), key, value); x.setRight(rightsubTreenewwithPuttedNode); }else { x.setValue(value); } int newsize = this.size(x.getLeft()) + this.size(x.getRight()) +1; // pq esse mais 1??? x.setSize(newsize); return x; } private put(TreeNode, key, value) { } public int size() { return this.size(this.root); } private int size (TreeNode <Key, Value> x) { if(x == null) { return 0; } else { return x.getSize(); } } public Value get (Key key) { // return get(this.root, key); } private Value get(TreeNode <Key,Value> x , Key key) { int compare = key.compareTo(x.getKey()); return x.getValue(); } } Parte 3 Implemente uma classe genérica BinarySearchTree<Key, Value> em que a classe Value possa ser de qualquer tipo e a classe Key tem que extends Comparable<Key>. A BinarySearchTree<Key, Value> recebe uma BinarySearchTree<Key, Value> em seu construtor. Implemente métodos que visitam a árvore e retornam uma List<Key> contendo as chaves nas ordens visitadas a seguir: 1. List<Key> inOrder() 2. List<Key> breadthFirst() 3. List<Key> preorder() 4. List<Key> postorder()
Compartilhar