AVL Tree

 
  1. /**
  2.  * filename: AVLNode.java
  3.  * package: 
  4.  * author: Nick Ma
  5.  * email: nick.ma85@yahoo.com
  6.  * date: Nov 12, 2008
  7.  * description: this class implements the node of avl tree.
  8.  */
  9. public   class  AVLNode<T  extends  Comparable<T>>  extends  BinaryNode<T> {
  10.      // Data Field
  11.     
  12.      /** the parent node of this current node */
  13.      private  AVLNode<T> parent;
  14.     
  15.      /** the height of this current node */
  16.      private   int  height;
  17.     
  18.      /**
  19.      * description: the constructor to initialize the data
  20.      * @param data - the data in the node
  21.      */
  22.      public  AVLNode(T data) {
  23.          super (data);
  24.          // TODO Auto-generated constructor stub
  25.          this .height =  0 ;
  26.          this .parent =  null ;
  27.     }
  28.      /**
  29.      * description: the constructor with fields
  30.      * @param data - the data in the node
  31.      * @param left - left child of this node
  32.      * @param right - right child of this node
  33.      */
  34.      public  AVLNode(T data, AVLNode<T> left, AVLNode<T> right) {
  35.          super (data, left, right);
  36.          this .height =  0 ;
  37.          this .parent =  null ;
  38.     }
  39.     
  40.      /**
  41.      * description: the constructor to convert this node from a binary node
  42.      * @param node - the binary node
  43.      */
  44.      public  AVLNode(BinaryNode<T> node) {
  45.          super (node.data, node.left, node.right);
  46.          this .height =  0 ;
  47.          this .parent =  null ;
  48.     }
  49.      /**
  50.      * @return the height
  51.      */
  52.      public   int  getHeight() {
  53.          return  height;
  54.     }
  55.      /**
  56.      * @param height the height to set
  57.      */
  58.      public   void  setHeight( int  height) {
  59.          this .height = height;
  60.     }
  61.      /**
  62.      * @return the parent
  63.      */
  64.      public  AVLNode<T> getParent() {
  65.          return  parent;
  66.     }
  67.      /**
  68.      * @param parent the parent to set
  69.      */
  70.      public   void  setParent(AVLNode<T> parent) {
  71.          this .parent = parent;
  72.     }
  73.      /* (non-Javadoc)
  74.      * @see LiMaHW4.BinaryNode#getLeft()
  75.      */
  76.      public  AVLNode<T> getLeft() {
  77.          // TODO Auto-generated method stub
  78.          return  (AVLNode<T>) super .getLeft();
  79.     }
  80.      /* (non-Javadoc)
  81.      * @see LiMaHW4.BinaryNode#getRight()
  82.      */
  83.      public  AVLNode<T> getRight() {
  84.          // TODO Auto-generated method stub
  85.          return  (AVLNode<T>) super .getRight();
  86.     }
  87. }
  88. /**
  89.  * filename: AVLTree.java
  90.  * package:
  91.  * author: Nick Ma
  92.  * email: nick.ma85@yahoo.com
  93.  * date: Nov 12, 2008
  94.  * description: this class implements an avl tree.
  95.  */
  96. public   class  AVLTree<T  extends  Comparable<T>>  extends  BinarySearchTree<T> {
  97.      // Data Field
  98.         
  99.      /**
  100.      * description: insert a node into the tree
  101.      * @param item - the data of the node
  102.      * @return - the node inserted
  103.      */
  104.      public  AVLNode<T> insert(T item) {
  105.          // check if the data is valid
  106.          if (item ==  null ) {
  107.              return   null ;
  108.         }
  109.         
  110.          // create a new node to store the data
  111.         AVLNode<T> newNode =  new  AVLNode<T>(item);
  112.         
  113.          // add this node to the tree
  114.          this .add(newNode);
  115.         
  116.          // reset the height of the inserted node
  117.          this .setHeight(newNode);
  118.         
  119.          // rebalance the tree after insertion
  120.          this .rebalance(newNode);
  121.         
  122.          // return the node inserted
  123.          return  newNode;
  124.     }
  125.     
  126.      /**
  127.      * description: remove a node from the tree
  128.      * @param item - the data in the removed node
  129.      * @return - true if the node is removed
  130.      */
  131.      public   boolean  remove(T item) {
  132.          // delete the node with the data from the tree
  133.          super .delete(item);
  134.         
  135.          if ( this .deletedNode ==  null ) {
  136.              return   false ;
  137.         }
  138.         
  139.          // get the reference of the deleted node
  140.         AVLNode<T> node = (AVLNode<T>) this .deletedNode;
  141.         
  142.          while (! super .isRoot(node)) {
  143.              // reference to its parent
  144.             node = node.getParent();
  145.              // reset the height
  146.              this .setHeight(node);
  147.             
  148.              // rebalance the subtree whose root is node
  149.              this .rebalance(node);
  150.         }
  151.          return   true ;
  152.     }
  153.     
  154.      /**
  155.      * description: display this tree by in-order traversal
  156.      */
  157.      public   void  display() {
  158.         StringBuilder sb =  new  StringBuilder();
  159.          super .inOrderTraverse(root,  0 , sb);
  160.         System.out.println(sb.toString());
  161.     }
  162.     
  163.      /**
  164.      * description: add new node in the tree
  165.      * @param newNode - the new node
  166.      */
  167.      public   void  add(AVLNode<T> newNode) {
  168.          this .root =  this .addAux((AVLNode<T>) this .root, newNode);
  169.          if (newNode ==  this .root) {
  170.             newNode.setParent( null );
  171.         }
  172.     }
  173.     
  174.      /**
  175.      * description: recursive add-auxiliary method
  176.      * @param node - the local root
  177.      * @param newNode - the new node
  178.      * @return - the new local root which contains the new node
  179.      */
  180.      private  AVLNode<T> addAux(AVLNode<T> node, AVLNode<T> newNode) {
  181.          if (node ==  null ) {
  182.              // the tree is empty
  183.              return  newNode;
  184.         }  else  {
  185.              int  result = newNode.getData().compareTo(node.getData());
  186.             
  187.              if (result <  0 ) {
  188.                  // insert new node in the left subtree
  189.                 node.setLeft(addAux(node.getLeft(), newNode));
  190.                 node.getLeft().setParent(node);
  191.             }  else   if  (result >  0 ){
  192.                  // insert new node in the right subtree
  193.                 node.setRight(addAux(node.getRight(), newNode));
  194.                 node.getRight().setParent(node);
  195.             }
  196.              return  node;
  197.         }
  198.     }
  199.     
  200.      /**
  201.      * description: delete the node in the tree
  202.      * @param data - the data of the deleted node
  203.      * @return - the deleted node
  204.      */
  205.      public  AVLNode<T> delete(T data) {
  206.          this .root =  this .deleteAux((AVLNode<T>) this .root, data);
  207.         ((AVLNode<T>) this .root).setParent( null );
  208.          return  (AVLNode<T>) this .deletedNode;
  209.     }
  210.     
  211.      /**
  212.      * description: recursive delete-auxiliary method
  213.      * @param node - the local root
  214.      * @param target - the data of the deleted node
  215.      * @return - the new local root which deletes the target node
  216.      */
  217.      private  AVLNode<T> deleteAux(AVLNode<T> node, T target) {
  218.          if (node ==  null ) {
  219.              // the tree is empty
  220.              return   null ;
  221.         }  else  {
  222.              int  result = target.compareTo(node.getData());
  223.             
  224.              if (result <  0 ) {
  225.                  // target is less than the data in the local root
  226.                 node.setLeft(deleteAux(node.getLeft(), target));
  227.                 node.getLeft().setParent(node);
  228.                  return  node;
  229.             }  else   if  (result >  0 ){
  230.                  // target is greater than the data in the local root
  231.                 node.setRight(deleteAux(node.getRight(), target));
  232.                 node.getLeft().setParent(node);
  233.                  return  node;
  234.             }  else  {
  235.                  // target is equal to the data in the local root
  236.                 
  237.                 deletedNode = node;
  238.         
  239.                  if (node.getLeft() ==  null ) {
  240.                      // there's no left child in the local root
  241.                      return  node.getRight();
  242.                 }  else   if (node.getRight() ==  null ) {
  243.                      // there's no right child in the local root
  244.                      return  node.getLeft();
  245.                 }  else  {
  246.                      // the local root has two children
  247.                      if (node.getLeft().getRight() ==  null ) {
  248.                         node.setData(node.getLeft().getData());
  249.                         node.setLeft(node.getLeft().getLeft());
  250.                         node.getLeft().setParent(node);
  251.                     }  else  {
  252.                         node.setData( super .findLargestChild(node.getLeft()));
  253.                     }
  254.                      return  node;
  255.                 }
  256.             }
  257.         }
  258.     }
  259.     
  260.      // Rotations for AVL Tree
  261.     
  262.      /**
  263.      * description: rotate the avl tree to right
  264.      * @param node - the unbalanced local root
  265.      * @return - the balanced local root
  266.      */
  267.      private  AVLNode<T> rotateR(AVLNode<T> node) {
  268.          // check if the node is valid
  269.          if (node ==  null  || node.getLeft() ==  null ) {
  270.              return   null ;
  271.         }
  272.         
  273.         AVLNode<T> newNode = (AVLNode<T>)node.getLeft();
  274.         node.setLeft(newNode.getRight());
  275.         newNode.setRight(node);
  276.         
  277.          // reset the parent node of the nodes just modified
  278.         node.setParent(newNode);
  279.          if (node.getLeft() !=  null ) {
  280.             node.getLeft().setParent(node);
  281.         }
  282.         
  283.          // reset the height of the nodes just modified
  284.          this .setHeight(node);
  285.          this .setHeight(newNode);
  286.         
  287.          // if root is changed, newNode must be the new root
  288.          if ( super .isRoot(node)) {
  289.             newNode.setParent( null );
  290.              this .root = newNode;
  291.         }
  292.         
  293.          return  newNode;
  294.     }
  295.     
  296.      /**
  297.      * description: rotate the avl tree to left
  298.      * @param node - the unbalanced local root
  299.      * @return - the balanced local root
  300.      */
  301.      private  AVLNode<T> rotateL(AVLNode<T> node) {
  302.          // check if the node is valid
  303.          if (node ==  null  || node.getRight() ==  null ) {
  304.              return   null ;
  305.         }
  306.         
  307.         AVLNode<T> newNode = (AVLNode<T>)node.getRight();
  308.         node.setRight(newNode.getLeft());
  309.         newNode.setLeft(node);
  310.         
  311.          // reset the parent node of the nodes just modified
  312.         node.setParent(newNode);
  313.          if (node.getRight() !=  null ) {
  314.             node.getRight().setParent(node);
  315.         }
  316.         
  317.          // reset the height of the nodes which is just modified
  318.          this .setHeight(node);
  319.          this .setHeight(newNode);
  320.         
  321.          // if root is changed, newNode must be the new root
  322.          if ( super .isRoot(node)) {
  323.             newNode.setParent( null );
  324.              this .root = newNode;
  325.         }
  326.         
  327.          return  newNode;
  328.     }
  329.     
  330.      /**
  331.      * description: doublely rotate the avl tree to left
  332.      * @param node - the unbalanced local root
  333.      * @return - the balanced local root
  334.      */
  335.      private  AVLNode<T> rotateRL(AVLNode<T> node) {
  336.          // check if the node is valid
  337.          // that is, the node has a right child
  338.          // and its right child has a left child
  339.          if (node ==  null  || node.getRight() ==  null
  340.                 || node.getRight().getLeft() ==  null ) {
  341.              return   null ;
  342.         }
  343.         
  344.         node.setRight( this .rotateR(node.getRight()));
  345.         node.getRight().setParent(node);
  346.          return   this .rotateL(node);
  347.     }
  348.     
  349.      /**
  350.      * description: doublely rotate the avl tree to right
  351.      * @param node - the unbalanced local root
  352.      * @return - the balanced local root
  353.      */
  354.      private  AVLNode<T> rotateLR(AVLNode<T> node) {
  355.          // check if the node is valid
  356.          // that is, the node has a left child
  357.          // and its left child has a right child
  358.          if (node ==  null  || node.getLeft() ==  null
  359.                 || node.getLeft().getRight() ==  null ) {
  360.              return   null ;
  361.         }
  362.         
  363.         node.setLeft( this .rotateL(node.getLeft()));
  364.         node.getLeft().setParent(node);
  365.          return   this .rotateR(node);
  366.     }
  367.     
  368.      // End of Rotations for AVL Tree
  369.     
  370.      /**
  371.      * description: rebalance the local root
  372.      * @param node - the local root
  373.      */
  374.      private   void  rebalance(AVLNode<T> node) {
  375.          if (node ==  null ) {
  376.              return ;
  377.         }
  378.         
  379.         AVLNode<T> newNode =  null// the balanced root
  380.         
  381.          // check if the local root isn't the root node of the tree
  382.          while (! super .isRoot(node)) {
  383.              // reference to its parent
  384.             node = node.getParent();
  385.              // reset the height
  386.              this .setHeight(node);
  387.             
  388.              if (! this .isBalanced(node)) {
  389.                  // if unbalanced
  390.                 
  391.                 AVLNode<T> y =  this .tallerChild(node);
  392.                 AVLNode<T> x =  this .tallerChild(y);
  393.                 AVLNode<T> p = node.getParent();
  394.                 
  395.                  // rotate the subtree
  396.                  if (y == node.getLeft() && x == y.getLeft()) {
  397.                     newNode =  this .rotateR(node);
  398.                 }  else   if (y == node.getLeft() && x == y.getRight()) {
  399.                     newNode =  this .rotateLR(node);
  400.                 }  else   if (y == node.getRight() && x == y.getLeft()) {
  401.                     newNode =  this .rotateRL(node);
  402.                 }  else   if (y == node.getRight() && x == y.getRight()) {
  403.                     newNode =  this .rotateL(node);
  404.                 }
  405.                  if (p !=  null  && ! super .isRoot(p)) {
  406.                      if (node == p.getLeft()) {
  407.                         p.setLeft(newNode);
  408.                         p.getLeft().setParent(p);
  409.                     }  else   if (node == p.getRight()) {
  410.                         p.setRight(newNode);
  411.                         p.getRight().setParent(p);
  412.                     }
  413.                 }
  414.                  return ;
  415.             }
  416.         }
  417.     }
  418.     
  419.      /**
  420.      * description: determine if the local root is balanced or not
  421.      * @param node - the local root
  422.      * @return - true if the local root is balanced
  423.      */
  424.      private   boolean  isBalanced(AVLNode<T> node) {
  425.          if (node ==  null ) {
  426.              return   true ;
  427.         }  else   if (node.getLeft() ==  null  && node.getRight() ==  null ) {
  428.              return   true ;
  429.         }  else   if (node.getLeft() !=  null  && node.getRight() ==  null ) {
  430.              // the height of the left subtree is -1
  431.              return  node.getLeft().getHeight() +  1  <=  1 ;
  432.         }  else   if (node.getLeft() ==  null  && node.getRight() !=  null ) {
  433.              // the height of the right child is -1
  434.              return  node.getRight().getHeight() +  1  <=  1 ;
  435.         }  else  {
  436.              return  (Math.abs(node.getLeft().getHeight() - node.getRight().getHeight()) <=  1 );
  437.         }
  438.     }
  439.     
  440.      /**
  441.      * description: set the height of the local root
  442.      * @param node - the local root
  443.      */
  444.      private   void  setHeight(AVLNode<T> node) {
  445.          if (node ==  null ) {
  446.              return ;
  447.         }  else   if (node.getLeft() ==  null  && node.getRight() ==  null ) {
  448.             node.setHeight( 0 );
  449.         }  else   if (node.getLeft() ==  null  && node.getRight() !=  null ) {
  450.             node.setHeight(node.getRight().getHeight() +  1 );
  451.         }  else   if (node.getLeft() !=  null  && node.getRight() ==  null ) {
  452.             node.setHeight(node.getLeft().getHeight() +  1 );
  453.         }  else  {
  454.             node.setHeight(Math.max(node.getLeft().getHeight(), node.getRight().getHeight()) +  1 );
  455.         }
  456.     }
  457.     
  458.      /**
  459.      * description: get the taller child of the local root
  460.      * @param node - the local root
  461.      * @return - the taller child
  462.      */
  463.      private  AVLNode<T> tallerChild(AVLNode<T> node) {
  464.          if (node ==  null ) {
  465.              return   null ;
  466.         }  else   if (node.getLeft() ==  null  && node.getRight() ==  null ) {
  467.              return   null ;
  468.         }  else   if (node.getLeft() ==  null  && node.getRight() !=  null ) {
  469.              return  node.getRight();
  470.         }  else   if (node.getLeft() !=  null  && node.getRight() ==  null ) {
  471.              return  node.getLeft();
  472.         }  else  {
  473.              return  (node.getLeft().getHeight() > node.getRight().getHeight()) ? node.getLeft() : node.getRight();
  474.         }
  475.     }
  476.     
  477. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值