Java 红黑树实现空指针异常

Java 红黑树实现空指针异常,java,red-black-tree,Java,Red Black Tree,我试图使用一个伪代码实现一个RBT,但是我得到了一个空指针异常。我尝试添加空值检查,但它只是在更远的地方与另一个空值崩溃。我的猜测是,我不应该一开始就有这么多空检查(否则伪代码会反映出这一点)。无论如何,下面是我的相关部分代码。如果能得到任何帮助,我将不胜感激,至少可以缩小问题的范围: public class RBtree { public static Node root; //root of RBT private class Node{ private

我试图使用一个伪代码实现一个RBT,但是我得到了一个空指针异常。我尝试添加空值检查,但它只是在更远的地方与另一个空值崩溃。我的猜测是,我不应该一开始就有这么多空检查(否则伪代码会反映出这一点)。无论如何,下面是我的相关部分代码。如果能得到任何帮助,我将不胜感激,至少可以缩小问题的范围:

public class RBtree {

    public static Node root; //root of RBT

    private class Node{
        private String key; //an identifying field inducing a total ordering
        private Node left; //left child (may be NULL)
        private Node right; //right child (may be NULL)
        private Node parent; //parent node (NULL for root)
        private String color;

        //constructor 
        public Node(String key){
            this.key = key;
            left = null;
            right = null;
            color = "red";

        }

    }

    public void addNode(String word){
        Node toInsert = new Node(word);
        Node parent = null;
        Node current = root;
        while(current != null){
            //System.out.println("root = " + root + " current = " + current);
            parent = current;
            if(toInsert.key.compareTo(current.key) > 0){
                current = current.left;
            }else{
                current = current.right;
            }
        }
        toInsert.parent = parent;
        if(parent == null){
            root = toInsert;
        }else if(toInsert.key.compareTo(parent.key) > 0){
            parent.left = toInsert;
        }else{
            parent.right = toInsert;
        }
        toInsert.left = null;
        toInsert.right = null;
        toInsert.color = "red";
        RBinsertFixUp(toInsert);

    }

    public void RBinsertFixUp(Node toFix){
        Node parent = null;
        while(toFix.parent.color.equals("red")){ //CRASH NULL POINTER
            if(toFix.parent.equals(toFix.parent.parent.left)){
                parent = toFix.parent.parent.right;     
                if(parent != null){
                    // begin case#1
                    if(parent.color.equals("red")){
                        toFix.parent.color = "black";
                        parent.color = "black";
                        toFix.parent.parent.color = "red";
                        toFix = toFix.parent.parent;
                    } //end case#1
                    else if(toFix.equals(toFix.parent.right)){ 
                        toFix = toFix.parent; //case#2
                        leftRotate(toFix.parent.parent); //case#2
                    }
                    toFix.parent.color = "black"; //case#3
                    toFix.parent.parent.color = "red"; //case#3
                    rightRotate(toFix.parent.parent); //case#3
                }
            }
            else{
                parent = toFix.parent.parent.left;      
                if(parent != null){
                    // begin case#1
                    if(parent.color.equals("red")){
                        toFix.parent.color = "black";
                        parent.color = "black";
                        toFix.parent.parent.color = "red";
                        toFix = toFix.parent.parent;
                    } //end case#1
                    else if(toFix.equals(toFix.parent.left)){ 
                        toFix = toFix.parent; //case#2
                        leftRotate(toFix.parent.parent); //case#2
                    }
                    toFix.parent.color = "black"; //case#3
                    toFix.parent.parent.color = "red"; //case#3
                    rightRotate(toFix.parent.parent); //case#3
                }

            }

        }
        root.color = "black";
    }
    // left rotation
    public void leftRotate(Node toRotate){
        Node parent = toRotate.right; //set parent
        toRotate.right = parent.left; // turn parent's left subtree into toRotate's right subtree
        if(parent.left != null){
            parent.left.parent = toRotate;
        }
        parent.parent = toRotate.parent; // link toRotate's parent to parent
        if(toRotate.parent == null){
            root = parent;
        }
        else if(toRotate.equals(toRotate.parent.left)){
            toRotate.parent.left = parent;
        }
        else{
            toRotate.parent.right = parent;
        }
        parent.left = toRotate; // put toRotate on parent's left
        toRotate.parent = parent;
    }

    // right rotation
    public void rightRotate(Node toRotate){
        Node parent = toRotate.left; //set parent
        toRotate.left = parent.right; // turn parent's right subtree into toRotate's left subtree
        if(parent.right != null){
            parent.right.parent = toRotate;
        }
        parent.parent = toRotate.parent; // link toRotate's parent to parent
        if(toRotate.parent == null){
            root = parent;
        }
        else if(toRotate.equals(toRotate.parent.right)){
            toRotate.parent.right = parent;
        }
        else{
            toRotate.parent.left = parent;
        }
        parent.right = toRotate; // put toRotate on parent's right
        toRotate.parent = parent;
    }

}
主要类别:

public class RBtreeTester {

    static String dictionaryName = "dictionary.txt";

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        RBtree testerTree = new RBtree();

        testerTree.addNode("hello");
        testerTree.addNode("bye");
        testerTree.addNode("hi");
        testerTree.addNode("goodbye");
        testerTree.addNode("goodmorning");
        testerTree.addNode("goodevening");

    }

}
堆栈跟踪:

Exception in thread "main" java.lang.NullPointerException
    at RBtree$Node.access$8(RBtree.java:10)
    at RBtree.RBinsertFixUp(RBtree.java:53)
    at RBtree.addNode(RBtree.java:47)
    at RBtreeTester.main(RBtreeTester.java:13)

仅从堆栈跟踪调试代码比调试添加到堆栈跟踪的代码更难。您只需要记住在提交程序(如果是作业)或发货(如果是工作)之前删除它们

不过,在本例中,我认为堆栈跟踪包含您需要的所有信息。如果插入的节点是新的根节点,则调用
RBinsertFixUp
时,其父节点的
将为
NULL
,并且
RBinsertFixUp
尝试做的第一件事是访问节点父节点的方法。这将导致Java以NullPointerException退出


您是对的,由经验丰富的程序员编写的Java代码往往很少检查
NULL
。这不仅仅是算法的一个特点;这是因为他们已经练习过思考在运行代码时可能遇到的
NULL
,并且知道只在那里放支票。

你能发布你的stacktrace吗please@Will我把它加进去了。有些行号可能无法相加,因为我删掉了一些不相关的代码。另外,如果您想让我将main添加到tester类中,请告诉我。发布真实代码、真实堆栈跟踪,并告诉它所指的行号。@JBNizet好的,我所做的是复制我发布在这里的缩短代码,并在我的环境中运行它,并更新生成的堆栈跟踪(现在应该是逐行匹配的)。我还添加了主类以供参考。我尝试在调用RBinsertFixUp(toInsert)之前添加if(toInsert.parent!=null)检查,但是崩溃发生在第101行,出现了另一个null指针异常。这就是我最初的意思。不管我做了多少空校验,我只是在代码中继续让它们继续,而且它看起来好像太过不正常了,尤其是当从一本书中实现一个算法的时候。有些时候,你需要从方法中返回,例如
,因为一旦你失败了一次,它的其余部分就没有意义了。如果你发布了对该书的引用(即作者网站的链接,或谷歌图书搜索或亚马逊中的书)和算法所在页面的链接,它可能会帮助其他人。我可能没有带着它,但是其他人看着这个问题可能会带着它。但是在它之后就没有其他东西了。。。调用修复是addNode方法所做的最后一件事。其余的崩溃都与空值有关。这是一本准确的书:具体地说,第316页。