0

我在编写红黑树删除函数(带有哨兵)时遇到了麻烦。

经过数小时的故障排除后,我得出的结论是,问题出现在以下步骤中:

插入 14、11、7 和 8,然后删除 11(即根)。

11 被替换为没有孩子的 14。然后,x(参见代码)获取 NULL 节点的值 - 这使得 x.parent 之类的函数变得毫无意义(对吗?)

然后程序在一个空异常中停止。

有什么想法有什么问题吗?

*我希望我已经把自己说清楚了——如果不是,我很乐意提供更多信息。

谢谢!

整个相关代码:

public class RBTree {

    private RBNode DUMMYROOT;
    private RBNode NULL;
    private int numOfNodes;


    public RBTree() {
        this.numOfNodes=0;
        this.NULL = new RBNode();
        this.DUMMYROOT = new RBNode();

        this.DUMMYROOT.setKey(Double.POSITIVE_INFINITY);
        this.DUMMYROOT.setLeftChild(NULL);
        this.DUMMYROOT.setColor("black");
        this.NULL.setColor("black");

    }

    public RBNode getNULL() {
        return this.NULL;
    }

  /**
   * public boolean empty()
   * 
   * returns true if and only if the tree is empty
   *  
   */


  public boolean empty() {
    if (this.numOfNodes==0)
        return true;
    return false;
  }

  /**
   * public boolean search(int i)
   * 
   * returns true if and only if the tree contains i
   *  
   */
  public boolean search(double i) {
      return (recursiveSearch(i, this.DUMMYROOT.getLeftChild())!=NULL);
  }

  public RBNode searchNode(double i) {
      return recursiveSearch(i, this.DUMMYROOT.getLeftChild());
  }


  private RBNode recursiveSearch(double i, RBNode rbNode) {
      if (rbNode==NULL)
          return NULL;
      else if (rbNode.getKey()==i)
          return rbNode;
      else if (rbNode.getKey()<i)
          return recursiveSearch(i,rbNode.getRightChild());
      else
          return recursiveSearch(i,rbNode.getLeftChild());
}

/**
   * public void insert(int i)
   * 
   * inserts the integer i into the binary tree; the tree
   * must remain valid (keep its invariants).
   * the function returns the number of color flips, or 0 if i was already in the tree
   * 
   */
  public int insert(int i) {
       RBNode rb = new RBNode(i);
       if (this.search((double)i)==false) {
           this.numOfNodes++;
           return RBTreeInsert(this,rb);
       }
       return 0;
  }

  private RBNode treePosition(RBNode x, double k) {
       RBNode y=x;
       while (x!=NULL) {
          y=x;
          if (x.getKey()==k)
              return x;
          else if (x.getKey()>k)
              x=x.getLeftChild();
          else
              x=x.getRightChild();
       }
       return y;
  }

  private int RBTreeInsert(RBTree t, RBNode z) {
       RBNode y;
       y=treePosition(t.DUMMYROOT,z.getKey());
       if (z.getKey()!=y.getKey()) {
           z.setParent(y);
           z.setLeftChild(NULL);
           z.setRightChild(NULL);
           z.setColor("red");
           if (z.getKey()<y.getKey())
               y.setLeftChild(z);
           else
               y.setRightChild(z);
       }
       return RBTreeInsertFixUp(z,t);
  }


   private int RBTreeInsertFixUp(RBNode node, RBTree t) {

       int counter =0;

       if(this.empty()==true)
               return counter;

       while(node.parent.color.equals("red")){
        if(node.parent == node.parent.parent.leftChild){
            RBNode y = node.parent.parent.rightChild;

            //case 1
            if(y.color.equals("red")){
                counter+=3;
                node.parent.setColor("black");
                y.setColor("black");
                node.parent.parent.setColor("red");
                node = node.parent.parent;
            }

            //case 2
            else {
                if(node == node.parent.rightChild) {
                    node = node.parent;
                    leftRotate(node, t);
                }
            //case 3
                counter+=2;
                node.parent.setColor("black");
                node.parent.parent.setColor("red");
                rightRotate(node.parent.parent, t);
            }

        }

        else {
            RBNode y = node.parent.parent.leftChild;

            //case 1
            if(y.color.equals("red")){
                counter+=3;
                node.parent.setColor("black");
                y.setColor("black");
                node.parent.parent.setColor("red");
                node = node.parent.parent;
            }

            //case 2
            else {
                if (node == node.parent.leftChild) {
                    node = node.parent;
                    rightRotate(node, t);
                }
            //case 3
                counter+=2;
                node.parent.setColor("black");
                node.parent.parent.setColor("red");
                leftRotate(node.parent.parent, t);
            }

        }
    }

    if(!(this.DUMMYROOT.leftChild.color.equals("black"))) {
        this.DUMMYROOT.leftChild.setColor("black");
        counter++;
    }

    return counter;


}

    private void rightRotate(RBNode node, RBTree t) {
            RBNode y = node.leftChild;
            Transplant(node, y);
            leftChild(node, y.rightChild);
            rightChild(y, node);
        }

    private void leftRotate(RBNode node, RBTree t) {
            RBNode y = node.rightChild;
            Transplant(node,y);
            rightChild(node, y.leftChild);
            leftChild(y,node);

            }

    private void Transplant(RBNode node, RBNode y) {
            if(node == node.parent.leftChild)
                leftChild(node.parent, y);
            else
                rightChild(node.parent,y);
        }

    private void rightChild(RBNode node, RBNode y) {
            node.rightChild =y;
            y.parent = node;

    }

    private void leftChild(RBNode node, RBNode y) {
            node.leftChild = y;
            y.parent = node;

        }


  /**
   * public void delete(int i)
   * 
   * deletes the integer i from the binary tree, if it is there;
   * the tree must remain valid (keep its invariants).
   * the function returns the number of color flips, or 0 if i was not in the tree
   * 
   */
   public int delete(int i)
   {
       if (this.search(i)==true) {
           //deletion will be made, so we decrease numOfNodes by 1
           this.numOfNodes--;
           return RBTreeDelete(this.searchNode(i),this);
       }
       return 0;
   }

   public int RBTreeDelete(RBNode deleteNode, RBTree tree){

       RBNode y;
       RBNode x;

       if(this.empty() == true)
           return 0;

       if(deleteNode.getLeftChild() == this.NULL || deleteNode.getRightChild() == this.NULL)
           y = deleteNode;
       else {
           y = TreeSuccessor(deleteNode); 

       }

       if(y.leftChild != NULL)
           x = y.leftChild;
       else
           x = y.rightChild;

       x.parent = y.parent;
       if(y.parent == NULL)
           DUMMYROOT.leftChild = x;
       else if(y == y.parent.leftChild)
           y.parent.leftChild = x;
       else
           y.parent.rightChild = x;

       if(y != deleteNode)
           deleteNode.key = y.key;

       if (y.color.equals("black")==true) 
               return RBDeleteFixUp(tree, x);

       return 0; //counter is 0, no color changes should be made. if me made any - they will be returned by "RBDleteFixUp"
   }

   private int RBDeleteFixUp(RBTree T, RBNode x) {
       //counts color changes
       int counter2= 0;
       boolean b=true;
       RBNode w = new RBNode();

       if(this.empty()==true)
           return counter2;

       while(((x != DUMMYROOT.leftChild)) &&  x.color.equals("black") && b==true){
           if(x == x.parent.leftChild){
               w = x.parent.rightChild;
               //case 1
               if(w.color.equals("red")){
                   System.out.println("1");

                   w.setColor("black");
                   counter2++;
                   x.parent.setColor("red");
                   counter2++;
                   leftRotate(x.parent, T);
                   w = x.parent.rightChild;
               }

               //case2


               if((w.rightChild.color.equals("black")) && (w.leftChild.color.equals("black"))){
                   System.out.println("2");
                   w.setColor("red");
                   counter2++;
                   x = x.parent;
               }

               //case 3
               else {
                   if(w.rightChild.color.equals("black")){
                       System.out.println("3");

                   w.leftChild.setColor("black");
                   counter2++;
                   w.setColor("red");
                   counter2++;
                   rightRotate(w, T);
                   w = x.parent.rightChild;

               }

               //case 4
                   System.out.println("4");
                        w.color = x.parent.color;
                        counter2++;
                        x.parent.setColor("black");
                        counter2++;
                        w.rightChild.setColor("black");
                        counter2++;
                        leftRotate(x.parent, T);
                        x = DUMMYROOT.leftChild;


               }
           }

           else{

               w = x.parent.leftChild;
               //case 1
               if(w.color.equals("red")){
                   System.out.println("5");
                   w.setColor("black");
                   counter2++;
                   x.parent.setColor("red");
                   counter2++;
                   rightRotate(x.parent, T);
                   w = x.parent.leftChild;
               }

               //case2

               if(w.rightChild.color.equals("black") && w.leftChild.color.equals("black")){
                   System.out.println("6");
                   w.setColor("red");
                   counter2++;
                   x = x.parent;
               }

               //case 3
               else {
                   if(w.leftChild.color.equals("black")){
                       System.out.println("7");
                   w.rightChild.setColor("black");
                   counter2++;
                   w.setColor("red");
                   counter2++;
                   leftRotate(w, T);
                   w = x.parent.leftChild;

                   }

               //case 4
               /**
               if(!(w.color == x.parent.color)){
                   w.color = x.parent.color;
                   counter2++;
               }
               **/ 

                   System.out.println("8");

                       w.color = x.parent.color;
                       counter2++;
                       x.parent.setColor("black");
                       counter2++;

                       w.leftChild.setColor("black"); //HERE THERES A NULL EXCEPTION
                       counter2++;             
                       rightRotate(x.parent, T);
                       x = DUMMYROOT.leftChild;

               }
           }
       }

       x.setColor("black");
       counter2++;
       return counter2;

    }

    private RBNode TreeSuccessor(RBNode node) {
        RBNode x = new RBNode();
        RBNode y = new RBNode();
        x=node;

        if (x.getRightChild()!=this.NULL) {
            return minNode(x.getRightChild());
        }
        y=x.getParent();
        while ((y!=this.NULL) && (x==y.getRightChild())) {
            x=y;
            y=x.getParent();
        }
        return y;
    }

       public RBNode minNode(RBNode startNode) {
           RBNode currNode= new RBNode();
           currNode=startNode;
           if (currNode==this.NULL) {
               System.out.println("currNode==this.NULL");
               return currNode;
           }
           else
           {
               while (currNode.leftChild!=this.NULL)
                   currNode=currNode.leftChild;
           }
           return currNode;
       }

   static class RBNode{

       public RBNode(int key) {
           this.key=key;
       }

        private double key;
        private RBNode parent;
        private RBNode rightChild;
        private RBNode leftChild;
        private String info;
        private String color;

       public RBNode() {

          this.key=-1;
          this.leftChild=null;
          this.rightChild=null;
          this.parent=null;
      }

      public RBNode(int key, String color) {
          this.color=color;
          this.key=key;
          this.leftChild=null;
          this.rightChild=null;
          this.parent=null;

      } 

      public RBNode(int key, String color, RBNode left, RBNode right) {
          this.color=color;
          this.key=key;
          this.leftChild=left;
          this.rightChild=right;

      } 

      public double getKey() {
          return this.key;
      }

      public String getColor() {
          return this.color;
      }  

      public RBNode getParent() {
          return this.parent;
      }     

      public RBNode getLeftChild() {
          return this.leftChild;
      }     

      public RBNode getRightChild() {
          return this.rightChild;
      } 

      public void setColor(String color) {
          this.color=color;
      }  

      public void setKey(double key) {
          this.key=key;
      }  

      public void setParent(RBNode parent) {
          this.parent=parent;
      }     

      public void setLeftChild(RBNode leftChild) {
          this.leftChild=leftChild;
      }     

      public void setRightChild(RBNode rightChild) {
          this.rightChild=rightChild;
      } 


}

   public static void main(String[] args) {

        RBTree t = new RBTree();

        t.insert(14);
        t.insert(11);
        t.insert(7);
        t.insert(8);
        t.delete(11);


    }
4

0 回答 0