Advertisement
andresnogales

AVLTree.java

Nov 10th, 2021
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 15.10 KB | None | 0 0
  1.  
  2. public class AVLTree<ELEMENT extends Comparable<ELEMENT>> {
  3.      
  4.     protected class AVLNode<ELEMENT> {
  5.         public ELEMENT item;
  6.         public AVLNode<ELEMENT> left;
  7.         public AVLNode<ELEMENT> right;
  8.         public int balance;
  9.  
  10.         public AVLNode() {
  11.             this(null, null, null, 0);
  12.         }
  13.         public AVLNode(ELEMENT item) {
  14.             this(item, null, null, 0);
  15.         }
  16.         public AVLNode(ELEMENT item, AVLNode<ELEMENT> left, AVLNode<ELEMENT> right, int balance) {
  17.             this.item = item;
  18.             this.left = left;
  19.             this.right = right;
  20.             this.balance = balance;
  21.         }
  22.  
  23.         @Override
  24.         public String toString() {
  25.             return this.item.toString();
  26.         }
  27.  
  28.         // Método para propósitos académicos
  29.         public void Visit() {
  30.             System.out.printf("%s ", this.item.toString());
  31.         }
  32.     }
  33.  
  34.  
  35.     protected AVLNode<ELEMENT> root;
  36.     // atributo para propositos académicos
  37.     protected boolean verbose;
  38.  
  39.     public AVLTree() {
  40.         this.root = null;
  41.         this.verbose = false;
  42.     }
  43.  
  44.     // método para propósitos académicos
  45.     public boolean setVerbose(boolean verbose) {
  46.         this.verbose = verbose;
  47.         return this.verbose;
  48.     }
  49.  
  50.  
  51.     @Override
  52.     public String toString() {
  53.         return toString(this.root);
  54.     }
  55.     protected String toString(AVLNode<ELEMENT> root) {
  56.         StringBuilder sb = new StringBuilder();
  57.         if (root != null) {
  58.             sb.append(root.item.toString());
  59.             //sb.append("[" + root.balance.toString() + "]");
  60.             sb.append((root.balance < 0) ? "[-]" : (root.balance == 0) ? "[.]" : "[+]" );
  61.             if (root.left != null) {
  62.                 sb.append("(" + toString(root.left));
  63.                 if (root.right != null) {
  64.                     sb.append(", " + toString(root.right));
  65.                 }
  66.                 sb.append(")");
  67.             } else {
  68.                 if (root.right != null) {
  69.                     sb.append("(, " + toString(root.right) + ")");
  70.                 }
  71.             }
  72.         }
  73.         return sb.toString();
  74.     }
  75.  
  76.  
  77.     //region Métodos para recorrer el árbol
  78.     public void PreOrder() {
  79.         PreOrder(this.root);
  80.     }
  81.     protected void PreOrder(AVLNode<ELEMENT> root) {
  82.         if (root != null) {
  83.             root.Visit();
  84.             PreOrder(root.left);
  85.             PreOrder(root.right);
  86.         }
  87.     }
  88.  
  89.     public void InOrder() {
  90.         InOrder(this.root);
  91.     }
  92.     protected void InOrder(AVLNode<ELEMENT> root) {
  93.         if (root != null) {
  94.             InOrder(root.left);
  95.             root.Visit();
  96.             InOrder(root.right);
  97.         }
  98.     }
  99.  
  100.     public void PostOrder() {
  101.         PostOrder(this.root);
  102.     }
  103.     protected void PostOrder(AVLNode<ELEMENT> root) {
  104.         if (root != null) {
  105.             PostOrder(root.left);
  106.             PostOrder(root.right);
  107.             root.Visit();
  108.         }
  109.     }
  110.  
  111.     public void DescendingOrder() {
  112.         DescendingOrder(this.root);
  113.     }
  114.     protected void DescendingOrder(AVLNode<ELEMENT> root) {
  115.         if (root != null) {
  116.             DescendingOrder(root.right);
  117.             root.Visit();
  118.             DescendingOrder(root.left);
  119.         }
  120.     }
  121.     //endregion
  122.  
  123.     //region Métodos para contar elementos del árbol
  124.     public int NodeCount() {
  125.         return NodeCount(this.root);
  126.     }
  127.     protected int NodeCount(AVLNode<ELEMENT> root) {
  128.         if (root != null) {
  129.             return 1 + NodeCount(root.left) + NodeCount(root.right);
  130.         }
  131.         return 0;
  132.     }
  133.  
  134.  
  135.     public int LeafCount() {
  136.         return LeafCount(this.root);
  137.     }
  138.     protected int LeafCount(AVLNode<ELEMENT> root) {
  139.         if (root != null) {
  140.             if ( (root.left == null) && (root.right == null) ) {
  141.                 return 1;
  142.             } else {
  143.                 return LeafCount(root.left) + LeafCount(root.right);
  144.             }
  145.         }
  146.         return 0;
  147.     }
  148.  
  149.  
  150.     public int InternalCount() {
  151.         return InternalCount(this.root);
  152.     }
  153.     protected int InternalCount(AVLNode<ELEMENT> root) {
  154.         if (root != null) {
  155.             if ( (root.left == null) && (root.right == null) ) {
  156.                 return 0;
  157.             } else {
  158.                 return 1 + InternalCount(root.left) + InternalCount(root.right);
  159.             }
  160.         }
  161.         return 0;
  162.     }
  163.  
  164.  
  165.     public int MaxLevel() {
  166.         return MaxLevel(this.root);
  167.     }
  168.     protected int MaxLevel(AVLNode<ELEMENT> root) {
  169.         if (root != null) {
  170.             if ( (root.left != null) || (root.right != null) ) {
  171.                 int leftLevel = MaxLevel(root.left);
  172.                 int rightLevel = MaxLevel(root.right);
  173.                 return 1 + Math.max(leftLevel, rightLevel);
  174.             }
  175.             return 0;
  176.         }
  177.         return -1;
  178.     }
  179.  
  180.     public int Height() {
  181.         return MaxLevel() + 1;
  182.     }
  183.     //endregion
  184.  
  185.     //region Métodos para buscar
  186.     public boolean contains(ELEMENT item) {
  187.         return contains(this.root, item);
  188.     }
  189.     private boolean contains(AVLNode<ELEMENT> root, ELEMENT item) {
  190.         if (root == null) {
  191.             return false;
  192.         }
  193.         if (item.compareTo(root.item) < 0) {
  194.             return contains(root.left, item);
  195.         }
  196.         if (item.compareTo(root.item) > 0) {
  197.             return contains(root.right, item);
  198.         }
  199.         return true;
  200.     }
  201.     //endregion
  202.  
  203.     //region Métodos para agregar elementos al árbol
  204.  
  205.     public void add(ELEMENT item) {
  206.         if (this.verbose) {
  207.             System.out.printf("Agrega %s", item.toString());
  208.         }
  209.  
  210.         boolean[] change = { false };
  211.         this.root = addAVL(this.root, item, change);
  212.  
  213.         if (this.verbose) {
  214.             System.out.printf("\t %s\n", this.toString());
  215.         }
  216.     }
  217.  
  218.     private AVLNode<ELEMENT> addAVL(AVLNode<ELEMENT> root, ELEMENT item, boolean[] change) {
  219.         AVLNode<ELEMENT> n1;
  220.  
  221.         if (root == null) {
  222.             root = new AVLNode<ELEMENT>(item);
  223.             change[0] = true; // cambia el balance
  224.             return root;
  225.         }
  226.  
  227.         if (item.compareTo(root.item) < 0) { // el nuevo elemento es menor
  228.             root.left = addAVL(root.left, item, change); // agrega por la izquierda
  229.             if (change[0]) { // cambió el balance?
  230.                 switch (root.balance) { // balance = hD - hI
  231.                     case 1: // antes izquierda < derecha
  232.                         root.balance = 0; // después izquierda == derecha
  233.                         change[0] = false; // balance ajustado
  234.                         break;
  235.                     case 0: // antes izquierda == derecha
  236.                         root.balance = -1; // después izquierda > derecha
  237.                         break;
  238.                     case -1: // antes izquierda > derecha
  239.                         n1 = root.left;
  240.                         if (n1.balance == -1) { // izquierda izquierda es mayor
  241.                             root = leftleftRotation(root, n1); // LR rotación doble
  242.                         } else {
  243.                             root = leftrightRotation(root, n1); // LL rotación simple
  244.                         }
  245.                         change[0] = false; // balance ajustado
  246.                         break;
  247.                 }
  248.             }
  249.             return root;
  250.         }
  251.  
  252.         if (item.compareTo(root.item) > 0) { // el nuevo elemento es mayor
  253.             root.right = addAVL(root.right, item, change); // agregar por la derecha
  254.             if (change[0]) { // cambió el balance?
  255.                 switch (root.balance) { // balance = hD - hI
  256.                     case -1: // antes izquierda > derecha
  257.                         root.balance = 0; // ahora izquierda == derecha
  258.                         change[0] = false; // balance ajustado
  259.                         break;
  260.                     case 0: // antes izquierda == derecha
  261.                         root.balance = 1; // ahora izquierda < derecha
  262.                         break;
  263.                     case 1: // antes izquierda < derecha
  264.                         n1 = root.right;
  265.                         if (n1.balance == 1) { // derecha derecha es mayor
  266.                             root = rightrightRotation(root, n1); // RR rotación simple
  267.                         } else {
  268.                             root = rightleftRotation(root, n1); // RL rotación doble
  269.                         }
  270.                         change[0] = false; // balance ajustado
  271.                         break;
  272.                 }
  273.             }
  274.             return root;
  275.         }
  276.         throw new RuntimeException("Claves repetidas");
  277.     }
  278.     //endregion
  279.  
  280.     //region Rotaciones LL LR RR RL
  281.     private AVLNode<ELEMENT> leftleftRotation(AVLNode<ELEMENT> n, AVLNode<ELEMENT> n1) {
  282.         if (this.verbose) {
  283.             System.out.print(" LL ");
  284.         }
  285.  
  286.         n.left = n1.right;
  287.         n1.right = n;
  288.         if (n1.balance == -1) {
  289.             n.balance = 0;
  290.             n1.balance = 0;
  291.         } else {
  292.             n.balance = -1;
  293.             n1.balance = 1;
  294.         }
  295.         return n1;
  296.     }
  297.  
  298.     private AVLNode<ELEMENT> leftrightRotation(AVLNode<ELEMENT> n, AVLNode<ELEMENT> n1) {
  299.         if (this.verbose) {
  300.             System.out.print(" LR ");
  301.         }
  302.  
  303.         AVLNode<ELEMENT> n2;
  304.         n2 = n1.right;
  305.         n.left = n2.right;
  306.         n2.right = n;
  307.         n1.right = n2.left;
  308.         n2.left = n1;
  309.         n1.balance = (n2.balance == 1) ? -1 : 0;
  310.         n.balance = (n2.balance == -1) ? 1 : 0;
  311.         n2.balance = 0;
  312.         return n2;
  313.     }
  314.  
  315.     private AVLNode<ELEMENT> rightrightRotation(AVLNode<ELEMENT> n, AVLNode<ELEMENT> n1) {
  316.         if (this.verbose) {
  317.             System.out.print(" RR ");
  318.         }
  319.  
  320.         n.right = n1.left;
  321.         n1.left = n;
  322.         if (n1.balance == 1) {
  323.             n.balance = 0;
  324.             n1.balance = 0;
  325.         } else {
  326.             n.balance = 1;
  327.             n1.balance = -1;
  328.         }
  329.         return n1;
  330.     }
  331.  
  332.  
  333.     private AVLNode<ELEMENT> rightleftRotation(AVLNode<ELEMENT> n, AVLNode<ELEMENT> n1) {
  334.         if (this.verbose) {
  335.             System.out.print(" RL ");
  336.         }
  337.  
  338.         AVLNode<ELEMENT> n2;
  339.         n2 = n1.left;
  340.         n.right = n2.left;
  341.         n2.left = n;
  342.         n1.left = n2.right;
  343.         n2.right = n1;
  344.         n.balance = (n2.balance == 1) ? -1: 0;
  345.         n1.balance = (n2.balance == -1) ? 1 : 0;
  346.         n2.balance = 0;
  347.         return n2;
  348.     }
  349.     //endregion
  350.  
  351.     //region Métodos para remover elementos
  352.  
  353.     public void remove(ELEMENT item) {
  354.         if (this.verbose) {
  355.             System.out.printf("Extrae %s", item.toString());
  356.         }
  357.  
  358.         boolean[] change = { false };
  359.         this.root = removeAVL(this.root, item, change);
  360.  
  361.         if (this.verbose) {
  362.             System.out.printf("\t %s\n", this.toString());
  363.         }
  364.     }
  365.     private AVLNode<ELEMENT> removeAVL(AVLNode<ELEMENT> root, ELEMENT item, boolean[] change) {
  366.  
  367.         if (root == null) {
  368.             throw new RuntimeException("No existe");
  369.         }
  370.  
  371.         if (item.compareTo(root.item) < 0) { // el elemento es menor
  372.             root.left = removeAVL(root.left, item, change); // borrar por la izquierda
  373.             if (change[0]) { // cambió el balance?
  374.                 root = leftBalance(root, change); // ajustar el balance izquierdo
  375.             }
  376.             return root;
  377.         }
  378.  
  379.         if (item.compareTo(root.item) > 0) { // el elemento es mayor
  380.             root.right = removeAVL(root.right, item, change); // borrar por la derecha
  381.             if (change[0]) { // cambió el balance?
  382.                 root = rightBalance(root, change); // ajustar el balance derecho
  383.             }
  384.             return root;
  385.         }
  386.  
  387.  
  388.         AVLNode<ELEMENT> q;
  389.         q = root;
  390.         if (q.left == null) { // no hay izquierda
  391.             root = q.right; // un descendiente por la derecha u hoja
  392.             change[0] = true; // cambia el balance
  393.         } else {
  394.             if (q.right == null) { // no hay derecha
  395.                 root = q.left; // un descendiente por la izquierda
  396.                 change[0] = true; // cambia el balance
  397.             } else { // dos descendientes !!!
  398.                 root.left = eldestOfMinors(root, root.left, change); // mayor de los menores
  399.                 if (change[0]) { // cambió el balance?
  400.                     root = leftBalance(root, change); // ajustar el balance izquierdo
  401.                 }
  402.                 q = null; // eliminar el nodo
  403.             }
  404.         }
  405.         return root;
  406.     }
  407.  
  408.     private AVLNode<ELEMENT> eldestOfMinors(AVLNode<ELEMENT> n, AVLNode<ELEMENT> eldest, boolean[] change) {
  409.         if (eldest.right != null) { // hay algo a la derecha
  410.             eldest.right = eldestOfMinors(n, eldest.right, change); // busca el mayor de los menores
  411.             if (change[0]) { // cambió el balance?
  412.                 eldest = rightBalance(eldest, change); // ajustar el balance derecho
  413.             }
  414.         } else {
  415.             n.item = eldest.item;
  416.             n = eldest;
  417.             eldest = eldest.left;
  418.             n = null;
  419.             change[0] = true;
  420.         }
  421.         return eldest;
  422.     }
  423.  
  424.     private AVLNode<ELEMENT> leftBalance(AVLNode<ELEMENT> n, boolean[] change) {
  425.         AVLNode<ELEMENT> n1;
  426.         switch (n.balance) { // balance = hD - hI
  427.             case -1 : // antes izquierda > derecha
  428.                 n.balance = 0; // ahora izquierda == derecha
  429.                 break;
  430.             case 0 : // antes izquierda == derecha
  431.                 n.balance = 1; // ahora izquierda < derecha
  432.                 change[0] = false; // balance ajustado
  433.                 break;
  434.             case 1 : // antes izquierda < derecha
  435.                 n1 = n.right;
  436.                 if (n1.balance >= 0) {
  437.                     if (n1.balance == 0) {
  438.                         change[0] = false; // balance ajustado
  439.                     }
  440.                     n = rightrightRotation(n, n1);
  441.                 } else {
  442.                     n = rightleftRotation(n, n1);
  443.                 }
  444.                 break;
  445.         }
  446.         return n;
  447.     }
  448.  
  449.     private AVLNode<ELEMENT> rightBalance(AVLNode<ELEMENT> n, boolean[] change) {
  450.         AVLNode<ELEMENT> n1;
  451.         switch (n.balance) { // balance = hD - hI
  452.             case -1 : // antes izquiera > derecha
  453.                 n1 = n.left;
  454.                 if (n1.balance <= 0) {
  455.                     if (n1.balance == 0) {
  456.                         change[0] = false; // balance ajustado
  457.                     }
  458.                     n = leftleftRotation(n, n1);
  459.                 } else {
  460.                     n = leftrightRotation(n, n1);
  461.                 }
  462.                 break;
  463.             case 0 : // antes izquierda == derecha
  464.                 n.balance = -1; // ahora izquierda > derecha
  465.                 change[0] = false; // balance ajustado
  466.                 break;
  467.             case 1 : // antes izquierda < derecha
  468.                 n.balance = 0;
  469.                 break;
  470.         }
  471.         return n;
  472.     }
  473.     //endregion
  474.  
  475. }
  476.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement