搜索二叉樹

定義:

二叉查找樹(Binary Search Tree),(又:二叉搜索樹,二叉排序樹)它或者是一棵空樹,或者是具有下列性質的[二叉樹]: 若它的左子樹不空,則左子樹上所有結點的值均小于它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大于它的根結點的值; 它的左、右子樹也分別為[二叉排序樹]

結點的結構代碼:

public Node root;
protect int size;
public static class Node {
        public Node(Integer value, Node parent, Node left, Node right) {
            super();
            this.value = value;
            this.parent = parent;
            this.left = left;
            this.right = right;
        }

        public Integer value;
        public Node parent;
        public Node left;
        public Node right;

        public boolean isLeaf() {
            return left == null && right == null;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((value == null) ? 0 : value.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Node other = (Node) obj;
            if (value == null) {
                if (other.value != null)
                    return false;
            } else if (!value.equals(other.value))
                return false;
            return true;
        }

    }
查詢:

#######原理:
如果插入的值比當前結點小,就繼續向其左子樹繼續查找,大就繼續向其右子樹繼續查找,相等就返回當前結點
#######代碼:

public Node search(int element) {
        Node node = root;
        while (node != null && node.value != null && node.value != element) {
            if (element < node.value) {
                node = node.left;
            } else {
                node = node.right;
            }
        }
        return node;
    }
插入:

#######原理:
如果root是空,則直接插入當前結點到root,否則
定義兩個變量,一個searchNode賦值root,一個是insertParent賦值為空,先查詢要插入的值,查詢過程即搜索二叉樹的查詢過程,在搜索到結點為空時跳出循環,而insertParent存儲每次循環查詢前serathNode的值,跳出循環說明,要插入的結點不是在insertParent的左孩子就是右孩子,然后比較大小,大右孩子,小左孩子。
#######代碼:

    public Node insert(int element) {
        if (root == null) {
            root = createNode(element, null, null, null);
            size++;
            return root;
        }

        Node insertParentNode = null;
        Node searchTempNode = root;
        while (searchTempNode != null && searchTempNode.value != null) {
            insertParentNode = searchTempNode;
            if (element < searchTempNode.value) {
                searchTempNode = searchTempNode.left;
            } else {
                searchTempNode = searchTempNode.right;
            }
        }

        Node newNode = createNode(element, insertParentNode, null, null);
        if (insertParentNode.value > newNode.value) {
            insertParentNode.left = newNode;
        } else {
            insertParentNode.right = newNode;
        }

        size++;
        return newNode;
    }


刪除:

#######原理:
看代碼注釋,總體原理是刪除分情況
第一種,要刪除結點,他只有左孩子或者右孩子,那么就讓他的唯一那個孩子來代替他的環境即可
第二種,要刪除的結點他既有左孩子又有右孩子,那么就要選要刪除結點的后繼節點來替代他的環境,因為他的后繼結點就是要刪除節點的右子樹中最左邊的結點,這個結點是他整個右子樹的做小的樹,而且他還比要刪除的結點大,所以選這個結點。在替換環境的時候,要注意全方位替換,即刪除結點的左子樹環境,右子樹環境,父環境都要替換,具體看代碼
#######代碼:

public Node delete(int element) {
        //先查找要刪除的結點是否存在
        Node deleteNode = search(element);
        if (deleteNode != null) {
            return delete(deleteNode);
        } else {
            return null;
        }
    }
protected Node delete(Node deleteNode) {
        if (deleteNode != null) {
            Node nodeToReturn = null;
            if (deleteNode != null) {
                //如果要刪除結點的左孩子為空,直接用刪除結點的右孩子代替他的位置即可
                if (deleteNode.left == null) {
                    //transplant的作用就是用后面的參數代替前面參數的父環境
                    nodeToReturn = transplant(deleteNode, deleteNode.right);
                } else if (deleteNode.right == null) {
                    nodeToReturn = transplant(deleteNode, deleteNode.left);
                } else {
                    //獲取要刪除結點的后繼節點,也就是刪除結點右孩子的左子樹最左的結點,他比要刪除的檢點大,他是要刪除結點右子樹的最小值
                    //所以用它來代替要刪除結點的位置
                    Node successorNode = getMinimum(deleteNode.right);
                    //又分兩中情況,如果要刪除結點右孩子的左子樹最左的結點就是他自己,就直接用這個節點代替刪除結點的環境即可
                    //否則如下
                    if (successorNode.parent != deleteNode) {
                        //用succ結點的右孩子先代替suss結點的父環境
                        transplant(successorNode, successorNode.right);
                        //安排要刪除結點的右邊的子環境,即讓刪除結點的后繼結點succ的右孩子是刪除結點的右孩子
                        successorNode.right = deleteNode.right;
                        //雙向處理,上面一行處理的是讓父指向右,這一步是讓右指向父
                        successorNode.right.parent = successorNode;
                    }
                    //讓succ代替刪除節點的父環境
                    transplant(deleteNode, successorNode);
                    //讓succ代替刪除結點的左孩子環境
                    successorNode.left = deleteNode.left;
                    successorNode.left.parent = successorNode;
                    nodeToReturn = successorNode;
                }
                size--;
            }

            return nodeToReturn;
        }
        return null;
    }
private Node transplant(Node nodeToReplace, Node newNode) {
        if (nodeToReplace.parent == null) {
            this.root = newNode;
            //要替代結點是他父節點的左孩子
        } else if (nodeToReplace == nodeToReplace.parent.left) {
            //新節點就變成他父節點新的左孩子
            nodeToReplace.parent.left = newNode;
        } else {
            nodeToReplace.parent.right = newNode;
        }
        //雙向處理
        if (newNode != null) {
            newNode.parent = nodeToReplace.parent;
        }
        return newNode;
    }
    protected Node getMinimum(Node node) {
        while (node.left != null) {
            node = node.left;
        }
        return node;
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。