Lista Duplamente Encadeada ("Inserção no Meio")

6 respostas
M

Estou utilizando as classes do Prof, nada das coleções padrão do Java. Consigo fazer inserções no inicio e no fim da lista, mas no meio não consigo de forma alguma.

A lógica é a seguinte:

  • Se menor que primeiro nodo, então insere antes do primeiro nodo
  • Se maior que ultimo nodo, insere após o último nodo
  • Se não, corre a lista e insere antes do nodo que seja maior que ele

Dessa forma teria no final uma lista em organizada de forma crescente.

Pra correr a lista eu sei que preciso buscar no Nodo as informações do nodo seguinte e anterior e criar um nodo “atual”, porém não consigo buscar esses dados… Uso a classe lista pra fazer uma lista, e tenho que criar a classe filha listaOrdenada.

Alguém poderia me ajudar a correr a lista duplamente encadeada verificando os valores dos nodos? Qualquer ajuda é bem vinda. Abaixo os códigos:

public class Node {
private String data;
private Node nextNode;
public Node( String element ) {
this( element, null );
}
public Node( String element, Node node ) {
data = element;
nextNode = node;
}
public String getData() {
return data;
}
public void setData(String element){
data = element;
}
public Node getNext() {
return nextNode;
}
public void setNext(Node node) {
nextNode = node;
}
}
public class List {
	private Node firstNode;
	private Node lastNode;
	private String name;
	public List() {
	this("list");
	}
	
	public List(String listName) {
		name = listName;
		firstNode = lastNode = null;
	}

	public boolean isEmpty() {
		return firstNode == null;
	}	

	public String getFirst() throws UnderflowException {
		if (isEmpty()) throw new UnderflowException();
		return firstNode.getData();
	}

	public String getLast() throws UnderflowException {
		if (isEmpty()) throw new UnderflowException();
		return lastNode.getData();
	}

	public void insertAtFront (String insertItem) {
		if (isEmpty()) {
		firstNode = lastNode = new Node(insertItem);
	} else {
		firstNode = new Node(insertItem, firstNode);
		}
	}

	public void insertAtBack (String insertItem) {
		if (isEmpty()) {
		firstNode = lastNode = new Node(insertItem);
		} else {
		lastNode.setNext(new Node(insertItem));
		lastNode = lastNode.getNext();
		}
	}

	public String removeFromFront() throws UnderflowException {
		if (isEmpty()) {
		throw new UnderflowException();
	}

	String removedItem = firstNode.getData();
		if (firstNode == lastNode) {
		firstNode = lastNode = null;
	} else {
		firstNode = firstNode.getNext();
		}return removedItem;
	}

	public String removeFromBack() throws UnderflowException {
		if (isEmpty()) {
		throw new UnderflowException();
	}
	String removedItem = lastNode.getData();
		if (firstNode == lastNode) {
		firstNode = lastNode = null;
	} else {
	Node current = firstNode;
	while (current.getNext() != lastNode) {
		current = current.getNext();
		} lastNode = current;
		current.setNext(null);
	}
	return removedItem;
	}

	public void print() {
		if (isEmpty()) {
		System.out.println("Empty " + name);
	} else {
		System.out.print("The " + name + " is: ");
		Node current = firstNode;
		while (current != null) {
			System.out.print(current.getData().toString() + " ");
			current = current.getNext();
	}
	System.out.println("\n");
	}
	}
public class ListTest {
		public static void main(String args[]) {
			List list = new List();
			list.insertAtFront("a");
			list.insertAtFront("b");
			list.insertAtBack("c");
			list.insertAtBack("d");
			list.print();
			String removedEl;
		try {
			removedEl = list.removeFromFront();
			System.out.println(removedEl.toString() + " removed");
			removedEl = list.removeFromFront();
			System.out.println(removedEl.toString() + " removed");
			removedEl = list.removeFromBack();
			System.out.println(removedEl.toString() + " removed");
			removedEl = list.removeFromBack();
			System.out.println(removedEl.toString() + " removed");
		} catch (UnderflowException e) {
			System.out.println(e.toString());
	}
	}
	}

6 Respostas

L

Basicamente vc tem que achar o node da posicao que deve inserir (por exemplo “a, b, e, f”, vc quer inserir “c”, vc tem que achar o node “b”), esse node (o “b”) tera como next o node inserido (“c”) e o next desse node inserido sera o next do node que vc achou (o next de “c” sera o next atual de “b” ou seja, “d”).

Segue mais ou menos como ficaria:

public void inserePosicionado(String s) {
			if (isEmpty() || firstNode.getData().compareTo(s) > 0) {
				// insere na primeira posicao caso a lista esteja vazia ou o
				// primeiro noh ja eh menor
				insertAtFront(s);
			} else {
				Node current = firstNode;
				while (current != null) {
					final Node next = current.getNext();
					if (next == null) {
						// insere na ultima posicao caso chegou ao final da
						// lista sem achar ponto de insercao
						insertAtBack(s);
						return;
					}

					if (next.getData().compareTo(s) > 0) {
						// insere na posicao encontrada, ou seja, cria o node
						// com o next sendo o next do node atual, e o node
						// criado sendo o next do node atual
						final Node node = new Node(s, next);
						current.setNext(node);
						return;
					}
					current = current.getNext();
				}
			}
		}
	}
M

Muito obrigado pela ajuda! :smiley:

Hoje quando chegar em casa vou testar, ontem eu desenvolvi uma lógica e é bem parecida, acho que agora conseguirei.

Lavieri

bom vou postar em duas partes ... primeiro vou postar meu Node, depois vou postar como solucionar o problema que vc quer fazer

Meu Node
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * Uma cadeia de nodos com valore inalteráveis, onde há referencia apenas ao
 * proximo elemento, nunca ao anterior. Cada nodo é um {@link Iterable} do
 * restante de sua cadeia de nodos<BR>.
 * <BR>Um nodo é capaz de acrecentar um valor entre ele e o proximo nodo
 * {@link #addAtNext(Object, boolean)}, ou ao final da cadeia de nodos
 * {@link #add(Object)}.
 * <BR>
 * <BR>É possivel também quebrar o restante da cádeia de nodos a partir de um
 * nodo atual, transformando o nodo atual no ultimo nodo da cadeia
 * {@link #breakNodo()}.
 * @author Tomaz Lavieri
 */
public class Node<T> implements Iterable<Node<T>> {
    /**
     * O valor intalterável deste nodo.
     */
    private final T value;
    /**
     * O proximo elemento no nodo, se houver.
     */
    private Node<T> next;

    /**
     * Encapsula o valor passado <tt>T</tt> em um {@link Node}<T> incial
     * de uma cadeia de Nodos.<BR>
     * <BR>
     * Esta cádeia de é um Iterator de Nodos 
     * {@link Iterator}<{@link Node}<T>>.
     * @param value o valor inalterável deste nodo.
     */
    public Node(T value) {
        this.value = value;
    }
    /**
     * Encapsula o valor passado <tt>T</tt> em um {@link Node}<T> incial
     * que precede o node <tt>next</tt> enviado.
     * @param value O valor inalterável do deste nodo inical.
     * @param next O nodo seguinte desde nodo.
     */
    public Node(T value , Node<T> next) {
        this.value = value;
        this.next = next;
    }
    /**
     * Encapsula o valor passado <tt>T</tt> em um {@link Node}<T> incial
     * de uma cadeia de Nodos, e adciona ao proximo nodo o valor <tt>next</tt>.
     * <BR>
     * <BR>Esta cádeia de é um Iterator de Nodos
     * {@link Iterator}<{@link Node}<T>>.
     * @param value o valor inalterável deste nodo.
     * @param next o valor do nodo seguinte.
     */
    public Node(T value, T next) {
        this.value = value;
        this.next = new Node(next);
    }
    /**
     * Cria uma cadeia de nodos a partir da coleção de valores enviado, com os
     * mesmos elementos e ordem da coleção enviada.<br>
     * <BR>
     * Porém a cadeia de nodos não é linkada a coleção, e esta é usada apenas
     * como base no momento de sua criação.
     * @param values coleção de valores a serem encadedos em nodos.
     */
    public Node(Collection<T> values) {
        if (values == null || values.size() == 0) {
            this.value = null;
        } else {
            Iterator<T> itr = values.iterator();
            this.value = itr.next();
            Node<T> last = this;
            while(itr.hasNext()) {
                last = last.add(itr.next());
            }
        }
    }
    /**
     * Verifica se existe um proximo nodo na cadeia
     * @return  <tt>true</tt> - se houver um proximo nodo na cadeia<br>
     *          <tt>false</tt> - caso contrario.
     */
    public boolean hasNext() {
        return next != null;
    }
    /**
     * Busca, se houver, o proximo nodo da cadeia.<BR>
     * <BR>
     * Obs.: Caso não exista um proximo nodo uma {@link NoSuchElementException}
     * será lançada, verifique {@link #hasNext()} antes de invocar um
     * {@link #next()}.
     * @return  O proximo nodo da cadeia.
     * @throws  NoSuchElementException quando não há um proximo nodo na cadeia,
     *          é possivel verificar se há um proximo nodo invocando
     *          {@link #hasNext()}.
     * @see #hasNext()
     */
    public Node<T> next() throws NoSuchElementException {
        if (!hasNext())
            throw new NoSuchElementException();
        return next;
    }

    /**
     * Busca o valor inalterado deste nodo. Não é possivel alterar o valor de um
     * nodo após criado, o objeto retornado por este método será sempre o mesmo.
     * <BR><BR>
     * Obs.: É possivel ter um nodo com valores nulos, tome cuidado.
     * @return o valor deste nodo.
     */
    public T getValue() {
        return value;
    }
    /**
     * Adciona o objeto <tt>value</tt> enviado a um {@link Node}<T>, no
     * final desta cadeia de nodos.
     * @param   value objeto a ser adcionado a um nodo no final desta cadeia de
     *          nodos.
     * @return O {@link Node} recentemente criado, encapsulando o valor passado.
     */
    public Node<T> add(T value) {
        return addAtNext(value,false);
    }
    public void addAll(Collection<T> values) {
        Node<T> last = last();
        for(T nextValue : values)
            last = last.add(nextValue);
    }
    /**
     * Adciona o objeto <tt>value</tt> enviado a um {@link Node}<T>, entre 
     * este e o proximo elementos desta cadeia, se <tt>atNext == true</tt>, ou
     * ao final desta cadeia de nodos, se <tt>atNext == false</tt>.
     * @param   value o valor a ser encapsulado a um nodo desta cádeia de nodos.
     * @param   atNext se o valor deve ser adicionado entre este e o proximo
     *          nodo (<tt>true</tt>) ou ao final da cadeia de nodos
     *          (<tt>false</tt>).
     * @return O {@link Node} recentemente criado, encapsulando o valor passado.
     */
    public Node<T> addAtNext(T value, boolean atNext) {
        if (atNext)
            return next = new Node(value, next);
        else
            return last().next = new Node<T>(value);
    }
    /**
     * Adciona uma coleção de valores entre este e o proximo nodo, quando
     * <tt>atNext == true</tt>, ou ao final desta cadeia de nodos, quando
     * <tt>atNext == false.</tt>
     * @param   values A coleção de valores a serem encapsulada nesta cadéia de
     *          nodos.
     * @param   atNext se os valores devem ser adicionados entre este e o
     *          proximo nodo (<tt>true</tt>) ou ao final da cadeia de nodos
     *          (<tt>false</tt>).
     */
    public void addAllAtNext(Collection<T> values, boolean atNext) {
        if (atNext) {
            Node<T> oldNext = this.next;
            Node<T> nextNode = this;
            for (T nextValue : values)
                nextNode = nextNode.add(nextValue);
            nextNode.next = oldNext;
        } else
            addAll(values);
    }
    /**
     * Busca o ultimo {@link Node} desta cadeia.
     * @return o ultimo {@link Node} desta cadeia.
     */
    public Node<T> last() {
        Node<T> last = this;
        while (last.hasNext()) {
            last = last.next();
        }
        return last;
    }
    /**
     * Quebra a cadeia de nodos neste ponto, a referencia aos proximos nodos é
     * removida, e este nodo passa a ser o ultimo nodo da cadeia.
     */
    public void breakNodo() {
        next = null;
    }
    /**
     * Verifica se algum nodo da cadeia, deste ponto em diante, contem o valor
     * passdo no parametro.
     * @param value o valor a ser verificado.
     * @return  <tt>true</tt> - se este Nodo ou algum nodo do restante da cadeia
     *          contém o <tt>value</tt> enviado.<br>
     *          <tt>false</tt> - caso nenhum elemento do restante da cadeia
     *          contenha este <tt>value</tt>.
     */
    public boolean contains(T value) {
        boolean result = false;
        for (Node<T> node : this) {
            if (result = node.getValue().equals(value))
                break;
        }
        return result;
    }


    public Iterator<Node<T>> iterator() {
        return new Itr(this);
    }
    private static class Itr<T> implements Iterator<Node><T>> {
        private Node<T> cursor;

        public Itr(Node<T> cursor) {
            this.cursor = cursor;
        }
        public boolean hasNext() {
            return cursor != null;
        }

        public Node<T> next() {
            if (cursor == null)
                throw new NoSuchElementException();
            Node<T> old = cursor;
            cursor = cursor.next;
            return old;
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}
Lavieri

ai o uma lista para inserir ordenadamente seria assim

public class FilaOrdenada<T extends Comparable> {
    private Node<T> first;
    private Node<T> last;
    private int size = 0;
    
    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean add(T element) throws NullPointerException {
        if (element == null) //se enviar nulo, lança exceção
            throw new NullPointerException(); 
        if (isEmpty()) //se for vazio, guarda o nodulo no inicio e no fim
            last = first = new Node<T>(element);
        else {
            if (first.getValue().compareTo(element) >= 0) //se for menor que o primeiro...
                first = new Node<T>(element, first); //cria um nodulo antes
            else if (last.getValue().compareTo(element) <= 0) //se for maior que o ultimo...
                last = last.add(element); //adciona o nodulo no final
            else { // caso o nodulo fique entre o primeiro e o ultimo
                Node<T> before = first; //guarda sempre um referencia do ultimo nodulo que acabou de verificar
                for (Node<T> node : first) { //faz um foreach pelo nodulo
                    if(node.getValue().compareTo(element) >= 0) { //encontrando um elemento maior que o enviado
                        before.addAtNext(element, true); //adciona o elemento antes deste maior
                        break; //e para o for-each, pois ja encontrou o elemento.
                    }
                    before = node; //se não achou, no próximo loop o este nodo passa a ser o anterior
                }
            }
        }
        size++;
        return true;
    }

    /**
     * Remove e retorna o primeiro elemento da fila, ou <tt>null</tt> caso não
     * haja nenhum elemento na fila.
     * @return o primeiro elemento da fila.
     */
    public T poll() {
        if (isEmpty())
            return null;
        T oldValue = first.getValue();

        if (!first.hasNext())
            first = last = null;
        else
            first = first.next();
        size--;
        return oldValue;
    }
    
}
Lavieri

aqui um pequeno exemplo

public class TesteTeste { public static void main(String ... args) { FilaOrdenada<String> strings = new FilaOrdenada<String>(); strings.add("atirei"); strings.add("o pau"); strings.add("no gato"); strings.add("to to"); strings.add("mais o gato"); strings.add("to to"); strings.add("não morreu"); strings.add("reu reu"); strings.add("dona"); strings.add("xica"); strings.add("ca ca"); strings.add("dimirou"); strings.add("se se"); strings.add("du berrou"); strings.add("du berrou"); strings.add("q o gato deu"); strings.add("miau!!"); while(!strings.isEmpty()) { System.out.println(strings.poll()); } } }

e a saida do console é:

atirei
ca ca
dimirou
dona
du berrou
du berrou
mais o gato
miau!!
no gato
não morreu
o pau
q o gato deu
reu reu
se se
to to
to to
xica

X

E como eu faço para imprimir a lista duplamente encadeada do luBS sendo que na ordem decrescente?

Criado 11 de maio de 2009
Ultima resposta 6 de out. de 2009
Respostas 6
Participantes 4