Lista Duplamente Encadeada (com Nó Cabeça) Perfeita! Para fins didáticos

Pode copiar e analisar à vontade.
Apenas peço que, se você fizer algum melhoramento, republique para que possamos aprender mais.

Para quem está enfrentando aquela famosa tarefa de Estrutura de Dados na Faculdade de SI.
:slight_smile:

Tinha um erro, mas, acabei de corrigir.

Classe principal:

[code]package listas;

import javax.swing.JOptionPane;

/**

    • @author robson.alcantara
      */
      public class ListaDE_NoCabeca {

    static final String[] menuGeral = { “Métodos de Inserção”,
    “Métodos de Remoção”, “Métodos de Busca”, “Métodos de Listagem”,
    “Sair” };
    static final String[] menuInicialInserir = { “Inserir no Início”,
    “Inserir no Final”, “Inserir Antes”, “Inserir Após”,
    “Inserir ordenado”, “Sair” };
    static final String[] menuInicialRemover = { “Remover do Início”,
    “Remover do Final”, “Remover Antes”, “Remover Após”,
    “Remover um valor”, “Sair” };
    static final String[] menuInicialBuscas = { “Recuperar o primeiro”,
    “Recuperar o último”, “Localizar um elemento”, “Sair” };
    static final String[] menuInicialManutencao = { “Ordenar a Lista”,
    “Limpar a Lista”, “Listar”, “Sair” };

    public static void main(String[] args) {

     ClasseListaDE<String> auxiliar, novo, enc, kbeca = new ClasseListaDE<>();
     String entrada, depois;
     int opcao;
     boolean pronto;
     do {
     	opcao = (JOptionPane
     			.showOptionDialog(null, "Escolha sua opção",
     					"Painel de opções", JOptionPane.DEFAULT_OPTION,
     					JOptionPane.QUESTION_MESSAGE, null, menuGeral,
     					menuGeral[0]));
     	switch (opcao) {
     	case 0:
     		int opcao1 = (JOptionPane.showOptionDialog(null,
     				"Escolha sua opção", "Painel de opções",
     				JOptionPane.DEFAULT_OPTION,
     				JOptionPane.QUESTION_MESSAGE, null, menuInicialInserir,
     				menuInicialInserir[0]));
     		switch (opcao1) {
     		case 0:
     			do {
     				entrada = (JOptionPane
     						.showInputDialog(
     								null,
     								"Informe o elemento a ser inserido no início da lista.\nPode ser inteiro, string, palavra, o que você quiser!",
     								"Inserção de elementos",
     								JOptionPane.QUESTION_MESSAGE));
     				auxiliar = kbeca;
     				pronto = false;
     				ClasseListaDE busca = localizar(entrada, auxiliar,
     						"inserir");
     				if (busca == null) {
     					pronto = true;
     					if (kbeca.getProximo() == null
     							|| kbeca.getAnterior() == null) {
     						novo = new ClasseListaDE<>(entrada);
     						kbeca.setProximo(novo);
     						kbeca.setAnterior(novo);
     						novo.setProximo(kbeca);
     						novo.setAnterior(kbeca);
     						ClasseListaDE.aumentaTamanho();
     					} else {
     						novo = new ClasseListaDE<>(entrada, kbeca,
     								kbeca.getProximo());
     						kbeca.getProximo().setAnterior(novo);
     						kbeca.setProximo(novo);
     						ClasseListaDE.aumentaTamanho();
     					}
     				}
     			} while (pronto == false);
     			break;
     		case 1:
     			do {
     				entrada = (JOptionPane
     						.showInputDialog(
     								null,
     								"Informe o elemento a ser inserido no fim da lista.\nPode ser inteiro, string, palavra, o que você quiser!"));
     				auxiliar = kbeca;
     				pronto = false;
     				ClasseListaDE busca = localizar(entrada, auxiliar,
     						"inserir");
     				if (busca == null) {
     					pronto = true;
     					if (kbeca == null) {
     						novo = new ClasseListaDE<>(entrada);
     						kbeca.setProximo(novo);
     						kbeca.setAnterior(novo);
     						novo.setProximo(kbeca);
     						novo.setAnterior(kbeca);
     						ClasseListaDE.aumentaTamanho();
     					} else {
     						novo = new ClasseListaDE<>(entrada,
     								kbeca.getAnterior(), kbeca);
     						kbeca.getAnterior().setProximo(novo);
     						kbeca.setAnterior(novo);
     						ClasseListaDE.aumentaTamanho();
     					}
     				}
     			} while (pronto == false);
     			break;
     		case 2:
     			do {
     				entrada = (JOptionPane
     						.showInputDialog(
     								null,
     								"Informe o elemento a ser inserido.\nPode ser inteiro, string, palavra, o que você quiser!"));
     				auxiliar = kbeca;
     				pronto = false;
     				ClasseListaDE busca = localizar(entrada, auxiliar,
     						"inserir");
     				if (busca == null) {
     					pronto = true;
     				}
     			} while (pronto == false);
     			depois = (JOptionPane.showInputDialog(null,
     					"Ele será inserido antes de qual elemento?"));
     			auxiliar = kbeca;
     			enc = localizar(depois, auxiliar, "");
     			if (enc != null) {
     				novo = new ClasseListaDE<>(entrada, enc.getAnterior(),
     						enc);
     				enc.getAnterior().setProximo(novo);
     				enc.setAnterior(novo);
     			} else {
     				JOptionPane.showMessageDialog(null,
     						"Elemento não foi inserido.", "Lamento, mané!",
     						JOptionPane.ERROR_MESSAGE);
     			}
     			break;
     		case 3:
     			do {
     				entrada = (JOptionPane
     						.showInputDialog(
     								null,
     								"Informe o elemento a ser inserido.\nPode ser inteiro, string, palavra, o que você quiser!"));
     				auxiliar = kbeca;
     				pronto = false;
     				ClasseListaDE busca = localizar(entrada, auxiliar,
     						"inserir");
     				if (busca == null) {
     					pronto = true;
     				}
     			} while (pronto == false);
     			depois = (JOptionPane.showInputDialog(null,
     					"Ele será inserido após qual elemento?"));
     			auxiliar = kbeca;
     			enc = localizar(depois, auxiliar, "");
     			if (enc != null) {
     				novo = new ClasseListaDE<>(entrada, enc,
     						enc.getProximo());
     				enc.getProximo().setAnterior(novo);
     				enc.setProximo(novo);
     			} else {
     				JOptionPane.showMessageDialog(null,
     						"Elemento não foi inserido.", "Lamento, mané!",
     						JOptionPane.ERROR_MESSAGE);
     			}
     			break;
     		case 4:
     			do {
     				entrada = (JOptionPane
     						.showInputDialog(
     								null,
     								"Informe o elemento a ser inserido na lista.\nPode ser inteiro, string, palavra, o que você quiser!\n"
     										+ "O programa buscará o primeiro elemento que seja\n"
     										+ "menor que o que você irá inserir e o colocará depois dele."));
     				auxiliar = kbeca;
     				pronto = false;
     				ClasseListaDE busca = localizar(entrada, auxiliar,
     						"inserir");
     				if (busca == null) {
     					pronto = true;
     					if (kbeca.getProximo() == null
     							|| kbeca.getAnterior() == null) {
     						novo = new ClasseListaDE<>(entrada);
     						kbeca.setProximo(novo);
     						kbeca.setAnterior(novo);
     						novo.setProximo(kbeca);
     						novo.setAnterior(kbeca);
     						ClasseListaDE.aumentaTamanho();
     					} else {
     						auxiliar = kbeca.getProximo();
     						boolean encontrado = false;
     						do {
     							if (auxiliar.getObjeto().compareTo(entrada) > 0) {
     								encontrado = true;
     								break;
     							} else {
     								auxiliar = auxiliar.getProximo();
     							}
     						} while (auxiliar.getObjeto() != null);
     						if (encontrado == true) {
     							novo = new ClasseListaDE<>(entrada,
     									auxiliar.getAnterior(), auxiliar);
     							auxiliar.getAnterior().setProximo(novo);
     							auxiliar.setAnterior(novo);
     							ClasseListaDE.aumentaTamanho();
     						} else {
     							novo = new ClasseListaDE<>(entrada,
     									kbeca.getAnterior(), kbeca);
     							kbeca.getAnterior().setProximo(novo);
     							kbeca.setAnterior(novo);
     							ClasseListaDE.aumentaTamanho();
     						}
     					}
     				}
     			} while (pronto == false);
     			break;
     		case 5:
     		}
     		break;
     	case 1:
     		int opcao2 = (JOptionPane.showOptionDialog(null,
     				"Escolha sua opção", "Painel de opções",
     				JOptionPane.DEFAULT_OPTION,
     				JOptionPane.QUESTION_MESSAGE, null, menuInicialRemover,
     				menuInicialRemover[0]));
     		switch (opcao2) {
     		case 0:
     			if (kbeca.getTamanho() == 1) {
     				limparLista(kbeca);
    

ClasseListaDE.diminuiTamanho();
} else {
if (kbeca != null) {
kbeca.getProximo().getProximo().setAnterior(kbeca);
kbeca.setProximo(kbeca.getProximo().getProximo());
ClasseListaDE.diminuiTamanho();
}
}
break;
case 1:
if (kbeca.getTamanho() == 1) {
limparLista(kbeca);
ClasseListaDE.diminuiTamanho();
} else {
if (kbeca != null) {
kbeca.getAnterior().getAnterior().setProximo(kbeca);
kbeca.setAnterior(kbeca.getAnterior().getAnterior());
ClasseListaDE.diminuiTamanho();
}
}
break;
case 2:
entrada = (JOptionPane
.showInputDialog(null,
“Informe o elemento cujo antecessor será removido.”));
auxiliar = kbeca;
if (auxiliar.getTamanho() == 1) {
limparLista(kbeca);
ClasseListaDE.diminuiTamanho();
} else {
enc = localizar(entrada, auxiliar, “buscar”);
if (enc != null) {
if (enc.getAnterior().getObjeto() == null) {
} else {
if (enc.getAnterior().getAnterior().getObjeto() == null) {
kbeca.setProximo(enc);
enc.setAnterior(kbeca);
ClasseListaDE.diminuiTamanho();
} else {
enc.getAnterior().getAnterior()
.setProximo(enc);
enc.setAnterior(enc.getAnterior()
.getAnterior());
ClasseListaDE.diminuiTamanho();
}
}
}
}
break;
case 3:
entrada = (JOptionPane.showInputDialog(null,
“Informe o elemento cujo sucessor será removido.”));
auxiliar = kbeca;
if (auxiliar.getTamanho() == 1) {
limparLista(kbeca);
ClasseListaDE.diminuiTamanho();
} else {
enc = localizar(entrada, auxiliar, “buscar”);

					if (enc != null) {
						if (enc.getProximo().getObjeto() == null) {
						} else {
							if (enc.getProximo().getProximo().getObjeto() == null) {
								kbeca.setAnterior(enc);
								enc.setProximo(kbeca);
								ClasseListaDE.diminuiTamanho();
							} else {
								enc.getProximo().getProximo()
										.setAnterior(enc);
								enc.setProximo(enc.getProximo()
										.getProximo());
								ClasseListaDE.diminuiTamanho();
							}
						}
					}
				}
				break;
			case 4:
				entrada = (JOptionPane.showInputDialog(null,
						"Informe o elemento que será removido."));
				auxiliar = kbeca;
				if (auxiliar.getTamanho() == 1) {
					limparLista(kbeca);

ClasseListaDE.diminuiTamanho();
} else {
enc = localizar(entrada, auxiliar, “buscar”);

					if (enc != null) {
						enc.getProximo().setAnterior(enc.getAnterior());
						enc.getAnterior().setProximo(enc.getProximo());
						ClasseListaDE.diminuiTamanho();
					}
				}
				break;
			case 5:
			}
			break;
		case 2:
			int opcao3 = (JOptionPane.showOptionDialog(null,
					"Escolha sua opção", "Painel de opções",
					JOptionPane.DEFAULT_OPTION,
					JOptionPane.QUESTION_MESSAGE, null, menuInicialBuscas,
					menuInicialBuscas[0]));
			switch (opcao3) {
			case 0:
				if (kbeca.getProximo() != null
						|| kbeca.getAnterior() != null) {
					JOptionPane.showMessageDialog(null,
							"O primeiro elemento da lista é: "
									+ kbeca.getProximo().getObjeto());
				}
				break;
			case 1:
				if (kbeca.getProximo() != null
						|| kbeca.getAnterior() != null) {
					JOptionPane.showMessageDialog(null,
							"O último elemento da lista é: "
									+ kbeca.getAnterior().getObjeto());
				}
				break;
			case 2:
				entrada = (JOptionPane.showInputDialog(null,
						"Informe o elemento a ser procurado"));
				auxiliar = kbeca;
				localizar(entrada, auxiliar, "buscar");
				break;
			case 3:
			}
			break;
		case 3:
			int opcao4 = (JOptionPane.showOptionDialog(null,
					"Escolha sua opção", "Painel de opções",
					JOptionPane.DEFAULT_OPTION,
					JOptionPane.QUESTION_MESSAGE, null,
					menuInicialManutencao, menuInicialManutencao[0]));
			switch (opcao4) {
			case 0:
				if (kbeca.getProximo() != null
						|| kbeca.getAnterior() != null) {
					JOptionPane
							.showMessageDialog(
									null,
									"Esta opção ordenará todos os elementos que você já inseriu.\n"
											+ "Fará igual no mapa de caracteres. Números na frente e alfabeto depois.\n"
											+ "As palavras inseridas também serão colocadas em ordem.",
									"Ordenação da Lista",
									JOptionPane.INFORMATION_MESSAGE);
					auxiliar = kbeca.getProximo();
					String pivo;
					int vezes, cont = 0;
					do {
						vezes = 0;
						do {
							if (auxiliar.getObjeto().compareTo(
									auxiliar.getProximo().getObjeto()) > 0) {
								pivo = auxiliar.getObjeto();
								auxiliar.setObjeto(auxiliar.getProximo()
										.getObjeto());
								auxiliar.getProximo().setObjeto(pivo);
								vezes++;
								cont++;
							}
							auxiliar = auxiliar.getProximo();
						} while (auxiliar.getProximo().getObjeto() != null);
						do {
							if (auxiliar.getObjeto().compareTo(
									auxiliar.getAnterior().getObjeto()) < 0) {
								pivo = auxiliar.getObjeto();
								auxiliar.setObjeto(auxiliar.getAnterior()
										.getObjeto());
								auxiliar.getAnterior().setObjeto(pivo);
								vezes++;
								cont++;
							}
							auxiliar = auxiliar.getAnterior();
						} while (auxiliar.getAnterior().getObjeto() != null);
					} while (vezes != 0);
					JOptionPane.showMessageDialog(null, "Houve " + cont
							+ " permutações.");
				}
				break;
			case 1:
				limparLista(kbeca);
				break;
			case 2:
				listar(kbeca);
				break;
			case 3:
			}
			break;
		}
	} while (opcao != 4);
}

/**
 * Método que localiza determinado elemento em uma lista. A busca é
 * recursiva e o elemento poderá, ou não, ser encontrado.
 * 
 * @param entrada
 * @param lista
 * @return
 */
private static ClasseListaDE localizar(String entrada,
		ClasseListaDE<String> lista, String quemPediu) {
	ClasseListaDE auxiliar = lista.getProximo();
	if (auxiliar != null) {
		boolean encontrado = false;
		do {
			if (auxiliar.getObjeto().equals(entrada)) {
				encontrado = true;
				break;
			} else {
				auxiliar = auxiliar.getProximo();
			}
		} while (auxiliar.getObjeto() != null);
		if (encontrado == true) {
			if (auxiliar.getProximo().getObjeto() == null) {
				switch (quemPediu) {
				case "inserir":
					JOptionPane.showMessageDialog(null,
							"O elemento indicado já existe. Informe outro",
							"Mensagem de Erro!!!",
							JOptionPane.ERROR_MESSAGE);
					break;
				case "buscar":
					JOptionPane.showMessageDialog(null,
							"O elemento foi encontrado. Ele é o último: "
									+ auxiliar.getObjeto(),
							"Busca finalizada",
							JOptionPane.INFORMATION_MESSAGE);
					break;
				}
				return auxiliar;
			} else {
				if (auxiliar.getAnterior().getObjeto() == null) {
					switch (quemPediu) {
					case "inserir":
						JOptionPane
								.showMessageDialog(
										null,
										"O elemento indicado já existe. Informe outro",
										"Mensagem de Erro!!!",
										JOptionPane.ERROR_MESSAGE);
						break;
					case "buscar":
						JOptionPane.showMessageDialog(null,
								"O elemento foi encontrado. Ele é o primeiro: "
										+ auxiliar.getObjeto(),
								"Busca finalizada",
								JOptionPane.INFORMATION_MESSAGE);
						break;
					}
					return auxiliar;
				} else {
					switch (quemPediu) {
					case "inserir":
						JOptionPane
								.showMessageDialog(
										null,
										"O elemento indicado já existe. Tá no meio do bolo!",
										"Mensagem de Erro!!!",
										JOptionPane.ERROR_MESSAGE);
						break;
					case "buscar":
						JOptionPane
								.showMessageDialog(null,
										"O elemento foi encontrado. Ele está entre o "
												+ auxiliar.getAnterior()
														.getObjeto()
												+ " e o "
												+ auxiliar.getProximo()
														.getObjeto(),
										"Busca finalizada",
										JOptionPane.INFORMATION_MESSAGE);
						break;
					}
					return auxiliar;
				}
			}
		} else {
			switch (quemPediu) {
			case "inserir":
				break;
			case "buscar":
				JOptionPane
						.showMessageDialog(null,
								"O elemento não foi encontrado.",
								"Busca finalizada",
								JOptionPane.INFORMATION_MESSAGE);
				break;
			}
			return null;
		}
	} else {
		switch (quemPediu) {
		case "inserir":
			break;
		case "buscar":
			JOptionPane.showMessageDialog(null,
					"O elemento não foi encontrado.", "Busca finalizada",
					JOptionPane.INFORMATION_MESSAGE);
			break;
		}
		return null;
	}
}

/**
 * Este método limpa a lista. O parâmetro passado é o nó cabeça.
 * 
 * @param kbeca
 */
private static void limparLista(ClasseListaDE<String> kbeca) {
	ClasseListaDE novo;
	novo = new ClasseListaDE<>("", kbeca, kbeca);
	kbeca.setProximo(novo);
	kbeca.setAnterior(novo);
	ClasseListaDE.setTamanho(0);
}

/**
 * Este método faz a listagem em caixa de mensagem.
 * 
 * @param kbeca
 */
private static StringBuilder listar(ClasseListaDE<String> kbeca) {
	StringBuilder saida = new StringBuilder();
	if (kbeca.getProximo() != null) {
		ClasseListaDE auxiliar;
		auxiliar = kbeca;
		while (auxiliar.getProximo().getObjeto() != null) {
			saida.append(auxiliar.getProximo().getObjeto().toString())
					.append(" ");
			auxiliar = auxiliar.getProximo();
		}
		JOptionPane.showMessageDialog(null, saida.toString());
	}
	return saida;
}

}
[/code]

Classe do tipo (com três construtores diferentes para usar da forma que convir:

[code]package Listas;

/**

  • @author robson.alcantara
    */
    public class Classe_ListaDencadeada {

    private static int tamanho;
    private E objeto;
    private Classe_ListaDencadeada proximo;
    private Classe_ListaDencadeada anterior;

    /**

    • Este construtor cria um nó que recebe como valor o objeto passado como
    • parâmetro. Ele, automaticamente, apontará para anterior nulo e para
    • próximo nulo.
    • @param objeto
      */
      public Classe_ListaDencadeada(E objeto) {
      this.objeto = objeto;
      this.anterior = null;
      this.proximo = null;
      }

    public Classe_ListaDencadeada() {
    this.objeto = null;
    this.anterior = null;
    this.proximo = null;
    }

    /**

    • Este construtor cria um nó e o aloca entre os nós passados como
    • parâmetros. Ele automaticamente apontará para os nós.
    • @param objeto
    • @param anterior
    • @param proximo
      */
      public Classe_ListaDencadeada(E objeto, Classe_ListaDencadeada anterior, Classe_ListaDencadeada proximo) {
      this.objeto = objeto;
      this.proximo = proximo;
      this.anterior = anterior;
      }

    public static int getTamanho() {
    return tamanho;
    }

    public static void setTamanho(int tamanho) {
    Classe_ListaDencadeada.tamanho = tamanho;
    }

    public static void aumentaTamanho() {
    tamanho++;
    }

    public static void diminuiTamanho() {
    tamanho–;
    }

    public E getObjeto() {
    return objeto;
    }

    public void setObjeto(E objeto) {
    this.objeto = objeto;
    }

    /**

    • Método que retorna o próximo nó da lista.
    • @return
      */
      public Classe_ListaDencadeada getProximo() {
      return proximo;
      }

    /**

    • Método que determina o nó para quem o nó atual apontará. Ou seja, define
    • o próximo.
    • @param proximo
      */
      public void setProximo(Classe_ListaDencadeada proximo) {
      this.proximo = proximo;
      }

    /**

    • Método que retorna o nó anterior da lista.
    • @return
      */
      public Classe_ListaDencadeada getAnterior() {
      return anterior;
      }

    public void setAnterior(Classe_ListaDencadeada anterior) {
    this.anterior = anterior;
    }
    }
    [/code]