Advertisement
FacundoCruz

AVLTP5E8

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