602 lines
12 KiB
Java
602 lines
12 KiB
Java
package cl.cromer.estructuras;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.logging.Level;
|
|
|
|
/**
|
|
* Esta clase tiene la estrutura de dato de tipo arbol.
|
|
*
|
|
* @author Chris Cromer
|
|
*/
|
|
public class Arbol {
|
|
/**
|
|
* El arbol.
|
|
*/
|
|
private ArbolNodo arbol;
|
|
|
|
/**
|
|
* La cantidad de nodos que están en el arbol.
|
|
*/
|
|
private int size;
|
|
|
|
/**
|
|
* La altura del arbol.
|
|
*/
|
|
private int altura;
|
|
|
|
/**
|
|
* Los nivles del arbol con todos sus nodos.
|
|
*/
|
|
private List<List<ArbolNodo>> niveles;
|
|
|
|
/**
|
|
* El orden que ha sido usado.
|
|
*/
|
|
private List<ArbolNodo> order;
|
|
|
|
/**
|
|
* Inicilizar el arbol.
|
|
*/
|
|
public Arbol() {
|
|
this.arbol = null;
|
|
this.altura = 0;
|
|
this.niveles = new ArrayList<>();
|
|
this.order = new ArrayList<>();
|
|
}
|
|
|
|
/**
|
|
* Insertar un valor al arbol.
|
|
*
|
|
* @param valor int: El valor a insertar.
|
|
*
|
|
* @return boolean: Verdad si fue insertado, falso si ya existe el nodo.
|
|
*/
|
|
public boolean insertar(int valor) {
|
|
if (this.arbol == null) {
|
|
arbol = new ArbolNodo(valor);
|
|
size++;
|
|
|
|
setAltura(calcularAltura(arbol));
|
|
|
|
niveles = new ArrayList<>();
|
|
for (int i = 0; i <= getAltura(); i++) {
|
|
niveles.add(new ArrayList<>());
|
|
}
|
|
calcularNiveles(arbol, 0);
|
|
niveles.remove(niveles.size() - 1);
|
|
|
|
return true;
|
|
}
|
|
else {
|
|
ArbolNodo nuevo = new ArbolNodo(valor);
|
|
ArbolNodo actual = arbol;
|
|
ArbolNodo padre;
|
|
while (true) {
|
|
padre = actual;
|
|
if (valor == actual.getValor()) {
|
|
// Ya existe.
|
|
return false;
|
|
}
|
|
else if (valor < actual.getValor()) {
|
|
// Izquerda
|
|
actual = actual.getIzquerda();
|
|
if (actual == null) {
|
|
nuevo.setPadre(padre);
|
|
padre.setIzquerda(nuevo);
|
|
size++;
|
|
setAltura(calcularAltura(arbol));
|
|
|
|
niveles = new ArrayList<>();
|
|
for (int i = 0; i <= getAltura(); i++) {
|
|
niveles.add(new ArrayList<>());
|
|
}
|
|
calcularNiveles(arbol, 0);
|
|
niveles.remove(niveles.size() - 1);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
// Derecha
|
|
actual = actual.getDerecha();
|
|
if (actual == null) {
|
|
nuevo.setPadre(padre);
|
|
padre.setDerecha(nuevo);
|
|
size++;
|
|
setAltura(calcularAltura(arbol));
|
|
|
|
niveles = new ArrayList<>();
|
|
for (int i = 0; i <= getAltura(); i++) {
|
|
niveles.add(new ArrayList<>());
|
|
}
|
|
calcularNiveles(arbol, 0);
|
|
niveles.remove(niveles.size() - 1);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Eliminar un valor del arbol.
|
|
*
|
|
* @param valor int: El valor a elminiar.
|
|
*
|
|
* @return boolean: Verdad si fue eliminado, falso si no existe.
|
|
*/
|
|
public boolean eliminar(int valor) {
|
|
if (arbol == null) {
|
|
return false;
|
|
}
|
|
|
|
ArbolNodo actual = arbol;
|
|
ArbolNodo padre = arbol;
|
|
boolean izquerda = true;
|
|
|
|
while (actual.getValor() != valor) {
|
|
padre = actual;
|
|
if (valor < actual.getValor()) {
|
|
izquerda = true;
|
|
actual = actual.getIzquerda();
|
|
}
|
|
else {
|
|
izquerda = false;
|
|
actual = actual.getDerecha();
|
|
}
|
|
if (actual == null) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (actual.getIzquerda() == null && actual.getDerecha() == null) {
|
|
if (actual == arbol) {
|
|
arbol = null;
|
|
}
|
|
else if (izquerda) {
|
|
padre.setIzquerda(null);
|
|
}
|
|
else {
|
|
padre.setDerecha(null);
|
|
}
|
|
}
|
|
else if(actual.getDerecha() == null) {
|
|
if (actual == arbol) {
|
|
arbol = actual.getIzquerda();
|
|
arbol.setPadre(null);
|
|
}
|
|
else if (izquerda) {
|
|
padre.setIzquerda(actual.getIzquerda());
|
|
actual.setPadre(padre);
|
|
}
|
|
else {
|
|
padre.setDerecha(actual.getIzquerda());
|
|
actual.setPadre(padre);
|
|
}
|
|
}
|
|
else if(actual.getIzquerda() == null) {
|
|
if (actual == arbol) {
|
|
arbol = actual.getDerecha();
|
|
arbol.setPadre(null);
|
|
}
|
|
else if (izquerda) {
|
|
padre.setIzquerda(actual.getDerecha());
|
|
actual.setPadre(padre);
|
|
}
|
|
else {
|
|
padre.setDerecha(actual.getDerecha());
|
|
actual.setPadre(padre);
|
|
}
|
|
}
|
|
else {
|
|
ArbolNodo successorParent = actual;
|
|
ArbolNodo successor = actual;
|
|
ArbolNodo current = actual.getDerecha();
|
|
while (current != null) {
|
|
successorParent = successor;
|
|
successor = current;
|
|
current = current.getIzquerda();
|
|
}
|
|
if (successor != actual.getDerecha()) {
|
|
successorParent.setIzquerda(successor.getDerecha());
|
|
successor.setDerecha(actual.getDerecha());
|
|
actual.setPadre(successor);
|
|
}
|
|
|
|
if (actual == arbol) {
|
|
arbol = successor;
|
|
arbol.setPadre(null);
|
|
}
|
|
else if (izquerda) {
|
|
padre.setIzquerda(successor);
|
|
successor.setPadre(padre);
|
|
}
|
|
else {
|
|
padre.setDerecha(successor);
|
|
successor.setPadre(padre);
|
|
}
|
|
|
|
successor.setIzquerda(actual.getIzquerda());
|
|
actual.setPadre(successor);
|
|
}
|
|
size--;
|
|
setAltura(calcularAltura(arbol));
|
|
|
|
niveles = new ArrayList<>();
|
|
for (int i = 0; i <= getAltura(); i++) {
|
|
niveles.add(new ArrayList<>());
|
|
}
|
|
calcularNiveles(arbol, 0);
|
|
niveles.remove(niveles.size() - 1);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Rotar el arbol usando el hijo a la derecha como un pivot.
|
|
*
|
|
* @param valor int: El valor a rotar.
|
|
*
|
|
* @return boolean: Verdad si fue rotado.
|
|
*/
|
|
public boolean rotarIzquerda(int valor) {
|
|
for (int i = 0; i < getAltura(); i++) {
|
|
for (int j = 0; j < niveles.get(i).size(); j++) {
|
|
if (niveles.get(i).get(j) != null && niveles.get(i).get(j).getValor() == valor) {
|
|
ArbolNodo padre = niveles.get(i).get(j);
|
|
ArbolNodo abuelo = padre.getPadre();
|
|
|
|
ArbolNodo hijo = padre.getDerecha();
|
|
if (hijo == null) {
|
|
return false;
|
|
}
|
|
ArbolNodo hijoIzquerda = hijo.getIzquerda();
|
|
|
|
if (arbol == padre) {
|
|
arbol = hijo;
|
|
}
|
|
else {
|
|
if (abuelo.getDerecha() == padre) {
|
|
abuelo.setDerecha(hijo);
|
|
}
|
|
else {
|
|
abuelo.setIzquerda(hijo);
|
|
}
|
|
}
|
|
|
|
hijo.setIzquerda(padre);
|
|
hijo.setPadre(abuelo);
|
|
padre.setPadre(hijo);
|
|
if (hijoIzquerda != null) {
|
|
padre.setDerecha(hijoIzquerda);
|
|
hijoIzquerda.setPadre(padre);
|
|
}
|
|
else {
|
|
padre.setDerecha(null);
|
|
}
|
|
|
|
setAltura(calcularAltura(arbol));
|
|
|
|
niveles = new ArrayList<>();
|
|
for (int k = 0; k <= getAltura(); k++) {
|
|
niveles.add(new ArrayList<>());
|
|
}
|
|
calcularNiveles(arbol, 0);
|
|
niveles.remove(niveles.size() - 1);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Rotar el arbol usando el hijo a la izquerda como un pivot.
|
|
*
|
|
* @param valor int: El valor a rotar.
|
|
*
|
|
* @return boolean: Verdad si fue rotado.
|
|
*/
|
|
public boolean rotarDerecha(int valor) {
|
|
for (int i = 0; i < getAltura(); i++) {
|
|
for (int j = 0; j < niveles.get(i).size(); j++) {
|
|
if (niveles.get(i).get(j) != null && niveles.get(i).get(j).getValor() == valor) {
|
|
ArbolNodo padre = niveles.get(i).get(j);
|
|
ArbolNodo abuelo = padre.getPadre();
|
|
|
|
ArbolNodo hijo = padre.getIzquerda();
|
|
if (hijo == null) {
|
|
return false;
|
|
}
|
|
ArbolNodo hijoDerecha = hijo.getDerecha();
|
|
|
|
if (arbol == padre) {
|
|
arbol = hijo;
|
|
}
|
|
else {
|
|
if (abuelo.getDerecha() == padre) {
|
|
abuelo.setDerecha(hijo);
|
|
}
|
|
else {
|
|
abuelo.setIzquerda(hijo);
|
|
}
|
|
}
|
|
|
|
hijo.setDerecha(padre);
|
|
hijo.setPadre(abuelo);
|
|
padre.setPadre(hijo);
|
|
if (hijoDerecha != null) {
|
|
padre.setIzquerda(hijoDerecha);
|
|
hijoDerecha.setPadre(padre);
|
|
}
|
|
else {
|
|
padre.setIzquerda(null);
|
|
}
|
|
|
|
setAltura(calcularAltura(arbol));
|
|
|
|
niveles = new ArrayList<>();
|
|
for (int k = 0; k <= getAltura(); k++) {
|
|
niveles.add(new ArrayList<>());
|
|
}
|
|
calcularNiveles(arbol, 0);
|
|
niveles.remove(niveles.size() - 1);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Ordenar el arbol usando preOrder.
|
|
*
|
|
* @return List: La lista del orden.
|
|
*/
|
|
public List<ArbolNodo> preOrder() {
|
|
order = new ArrayList<>();
|
|
preOrder(arbol);
|
|
return order;
|
|
}
|
|
|
|
/**
|
|
* Ordenar el arbol usando inOrder.
|
|
*
|
|
* @return List: La lista del orden.
|
|
*/
|
|
public List<ArbolNodo> inOrder() {
|
|
order = new ArrayList<>();
|
|
inOrder(arbol);
|
|
return order;
|
|
}
|
|
|
|
/**
|
|
* Ordenar el arbol usando postOrder.
|
|
*
|
|
* @return List: La lista del orden.
|
|
*/
|
|
public List<ArbolNodo> postOrder() {
|
|
order = new ArrayList<>();
|
|
postOrder(arbol);
|
|
return order;
|
|
}
|
|
|
|
/**
|
|
* El meteodo recursivo de preOrder que acumulará los nodos en una lista.
|
|
*
|
|
* @param nodo ArbolNodo: El nodo a trabajar.
|
|
*/
|
|
public void preOrder(ArbolNodo nodo) {
|
|
if (nodo != null) {
|
|
order.add(nodo);
|
|
preOrder(nodo.getIzquerda());
|
|
preOrder(nodo.getDerecha());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* El meteodo recursivo de inOrder que acumulará los nodos en una lista.
|
|
*
|
|
* @param nodo ArbolNodo: El nodo a trabajar.
|
|
*/
|
|
public void inOrder(ArbolNodo nodo) {
|
|
if (nodo != null) {
|
|
preOrder(nodo.getIzquerda());
|
|
order.add(nodo);
|
|
preOrder(nodo.getDerecha());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* El meteodo recursivo de postOrder que acumulará los nodos en una lista.
|
|
*
|
|
* @param nodo ArbolNodo: El nodo a trabajar.
|
|
*/
|
|
public void postOrder(ArbolNodo nodo) {
|
|
if (nodo != null) {
|
|
preOrder(nodo.getIzquerda());
|
|
preOrder(nodo.getDerecha());
|
|
order.add(nodo);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Devolver el arbol.
|
|
*
|
|
* @return ArbolNodo: La raiz del arbol.
|
|
*/
|
|
public ArbolNodo getArbol() {
|
|
return arbol;
|
|
}
|
|
|
|
/**
|
|
* Devolver la cantidad de nodos que están en el arbol.
|
|
*
|
|
* @return int: La cantidad.
|
|
*/
|
|
public int size() {
|
|
return size;
|
|
}
|
|
|
|
/**
|
|
* Devolver la altura del arbol.
|
|
*
|
|
* @return int: La altura.
|
|
*/
|
|
public int getAltura() {
|
|
return altura;
|
|
}
|
|
|
|
/**
|
|
* Cambiar la altura del arbol.
|
|
*
|
|
* @param altura int: La altura nueva.
|
|
*/
|
|
private void setAltura(int altura) {
|
|
this.altura = altura;
|
|
}
|
|
|
|
/**
|
|
* Devolver la lista de nivles del arbol.
|
|
*
|
|
* @return List: La lista de niveles.
|
|
*/
|
|
public List<List<ArbolNodo>> getNiveles() {
|
|
return niveles;
|
|
}
|
|
|
|
/**
|
|
* Encontrar y devolver la altura del arbol usando recursividad.
|
|
*
|
|
* @param nodo ArbolNodo: El nodo a trabajar.
|
|
*
|
|
* @return int: La altura.
|
|
*/
|
|
public int calcularAltura(ArbolNodo nodo) {
|
|
if (nodo == null) {
|
|
return 0;
|
|
}
|
|
else {
|
|
int alturaIzquerda = calcularAltura(nodo.getIzquerda());
|
|
int alturaDercha = calcularAltura(nodo.getDerecha());
|
|
if (alturaIzquerda > alturaDercha) {
|
|
return (alturaIzquerda + 1);
|
|
}
|
|
else {
|
|
return (alturaDercha + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calcular los nivles del arbol usando recursividad.
|
|
*
|
|
* @param nodo ArbolNodo: El nodo a trabajar.
|
|
* @param nivel int: El Nivel donde está el nodo.
|
|
*/
|
|
public void calcularNiveles(ArbolNodo nodo, int nivel) {
|
|
try {
|
|
if (nodo != null) {
|
|
niveles.get(nivel).add(nodo);
|
|
nivel++;
|
|
calcularNiveles(nodo.getIzquerda(), nivel);
|
|
calcularNiveles(nodo.getDerecha(), nivel);
|
|
}
|
|
else if (nivel != getAltura()) {
|
|
niveles.get(nivel).add(null);
|
|
nivel++;
|
|
calcularNiveles(null, nivel);
|
|
calcularNiveles(null, nivel);
|
|
}
|
|
}
|
|
catch (Exception exception) {
|
|
Logs.log(Level.SEVERE, exception);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Esta clase contiene los arbolTipo de arboles.
|
|
*
|
|
* @author Chris Cromer
|
|
*/
|
|
final static public class Tipos {
|
|
/**
|
|
* Tipo general.
|
|
*/
|
|
static final public int GENERAL = 0;
|
|
|
|
/**
|
|
* Tipo binario.
|
|
*/
|
|
static final public int BINARIO = 1;
|
|
|
|
/**
|
|
* Tipo busqueda binaria.
|
|
*/
|
|
static final public int BUSQUEDA_BINARIA = 2;
|
|
|
|
/**
|
|
* Tipo AVL.
|
|
*/
|
|
static final public int AVL = 3;
|
|
|
|
/**
|
|
* Tipo rojo-negro.
|
|
*/
|
|
static final public int ROJO_NEGRO = 4;
|
|
|
|
/**
|
|
* Tipo B-Tree.
|
|
*/
|
|
static final public int B_TREE = 5;
|
|
|
|
/**
|
|
* El tipo elegido.
|
|
*/
|
|
final private int tipo;
|
|
|
|
/**
|
|
* Inicilizar el tipo de arbol.
|
|
*
|
|
* @param tipo int: El tipo de lista enlazada, {@value #GENERAL}, {@value #BINARIO}, {@value #BUSQUEDA_BINARIA}, {@value #AVL}, {@value #ROJO_NEGRO} o {@value #B_TREE}
|
|
*/
|
|
public Tipos(int tipo) {
|
|
switch (tipo) {
|
|
case GENERAL:
|
|
this.tipo = GENERAL;
|
|
break;
|
|
case BINARIO:
|
|
this.tipo = BINARIO;
|
|
break;
|
|
case BUSQUEDA_BINARIA:
|
|
this.tipo = BUSQUEDA_BINARIA;
|
|
break;
|
|
case AVL:
|
|
this.tipo = AVL;
|
|
break;
|
|
case ROJO_NEGRO:
|
|
this.tipo = ROJO_NEGRO;
|
|
break;
|
|
case B_TREE:
|
|
this.tipo = B_TREE;
|
|
break;
|
|
default:
|
|
this.tipo = GENERAL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Devolver el tipo de arbol.
|
|
*
|
|
* @return int: El tipo.
|
|
*/
|
|
public int getTipo() {
|
|
return tipo;
|
|
}
|
|
}
|
|
}
|