1. 程式人生 > >二叉查詢樹(查詢、插入、遍歷、刪除)--Java實現

二叉查詢樹(查詢、插入、遍歷、刪除)--Java實現

搜尋樹資料結構支援許多動態集合操作,包括search、insert、delete、maximum、minimum等。因此,我們使用一棵搜尋樹既可以作為一個字典又可以作為一個優先佇列。
二叉搜尋樹上的基本操作所花費的時間與這棵樹的高度成正比。對於有n個結點的一棵完全二叉樹來說,這些操作的最壞執行時間為O(logn)。然而,如果這棵樹是一條n個結點組成的線性鏈,那麼同樣的操作就要花費O(n)的最壞的執行時間。

一、什麼是二叉搜尋樹

一棵二叉搜尋樹是以一棵二叉樹來組織的,這樣的一棵樹可以使用一個連結串列資料結構來表示,其中每個結點就是一個物件。最重要的特性就是:對任何結點x,其左子樹的關鍵字最大不超過x.value,其右子樹中的關鍵字最小不低於x.value。不同二叉搜尋樹可以代表同一組值的集合,大部分搜尋樹的最壞執行時間與樹的高度成正比。下圖為一棵包含11個結點、高度為4的二叉搜尋樹。
image

二、二叉查詢樹的操作(查詢、插入、遍歷、刪除)

定義結點

 public class TreeNode{
        public int keyValue;    //關鍵字值
        public TreeNode leftNode;//左節點
        public TreeNode rightNode;//右節點

        public TreeNode(){}
        public TreeNode(int Key){
            this.keyValue = Key;
        }
    }

(1)查詢二叉搜尋樹的結點

//查詢結點
public TreeNode BSTsearch(TreeNode root, int Key){ TreeNode node=root; //當節點值不等於要查詢的結點值就迴圈,如果沒有找到則返回null while(node.keyValue!=Key){ if(Key<node.keyValue){ node=node.leftNode; }else{ node=node.rightNode; } if
(node==null){ return null; } } return node; }

(2)插入二叉搜尋樹的結點

//插入結點,插入結點的過程就是先查詢再插入
    public void BSTinsert(TreeNode root, int Key){
        TreeNode node=new TreeNode(Key);
        //插入結點之前先找到要插入的位置,這樣就要記住插入結點的父節點
        //讓父節點的左右指標指向要新增的結點
        if(root== null){
            root=node;
        }else{
            TreeNode currentNode = root;//定義當前節點為根節點
            TreeNode parentNode;
            while(true){
                parentNode=currentNode;
                if(Key<currentNode.keyValue){
                    currentNode=currentNode.leftNode;
                    if(currentNode==null){
                        parentNode.leftNode=node;
                        return;
                    }
                }else{
                    currentNode=currentNode.rightNode;
                    if(currentNode==null){
                        parentNode.rightNode=node;
                        return;
                    }
                }
            }
        }
    }

(3)遍歷二叉樹的結點

//遍歷樹,主要分為中序遍歷、前序遍歷和後序遍歷
    //下面以中序遍歷做例子
    public void BSTdisplay(TreeNode node){
        if(node!=null){
            BSTdisplay(node.leftNode);
            System.out.println(node.keyValue+",");
            BSTdisplay(node.rightNode);
        }
    }

(4)查詢二叉查詢樹中的最大結點

 //最大值
    public int BSTmax(TreeNode root){
        TreeNode node=root;
        TreeNode parent=null;
        while(node!=null){
            parent=node;
            node=node.rightNode;
        }
        return parent.keyValue;

    }

(5)查詢二叉查詢樹中的最小結點

  //最小值
    public int BSTmin(TreeNode root){
        TreeNode node=root;
        TreeNode parent=null;
        while(node!=null){
            parent=node;
            node=node.leftNode;
        }
        return parent.keyValue;

    }

(6)刪除二叉搜尋樹的結點
二叉樹的結點刪除要分成三類:
刪除沒有子結點的結點;
刪除只有一個子結點的結點;
刪除有兩個子結點的結點。

 // 刪除節點分三種方式刪除節點
    // 1、刪除沒有子節點的節點,直接讓該節點的父節點的左節點或右節點指向空
    // 2、刪除有一個子節點的節點,直接讓該節點的父節點指向被刪除節點的剩餘節點
    // 3、刪除有三個節點的子節點,找到要刪除節點的後繼節點, 用該節點替代刪除的節點
    public boolean BSTdelete(TreeNode root,int Key) {
        // 首先查詢節點,並記錄該節點的父節點引用
        TreeNode current = root;
        TreeNode parent = root;
        boolean isLeftNode = true;
        while (current.keyValue != Key) {
            parent = current;
            if (Key < current.keyValue) {
                isLeftNode = true;
                current = current.leftNode;
            } else {
                isLeftNode = false;
                current = current.rightNode;
            }
        }
        if (current == null) {
            System.out.println("沒有找到要刪除的節點!");
            return false;
        }
        // 下面分三種情況刪除節點
        if (current.leftNode == null && current.rightNode == null) {  //要刪除的節點沒有子節點
            if (current == root) { // 根節點就刪除整棵樹
                root = null;
            } else if (isLeftNode) { // 如果是左節點,做節點指向空
                parent.leftNode = null;
            } else { // 如果是右節點,右節點指向空
                parent.rightNode = null;
            }
        } else if (current.leftNode == null) {                         //要刪除的節點只有右節點
            if (current == root) {
                root = current.rightNode;
            } else if (isLeftNode) {
                parent.leftNode = current.rightNode;
            } else {
                parent.rightNode = current.rightNode;
            }
        } else if (current.rightNode == null) {                         //要刪除的節點只有左節點
            if (current == root) {
                root = current.leftNode;
            } else if (isLeftNode) {
                parent.leftNode = current.leftNode;
            } else {
                parent.rightNode = current.leftNode;
            }
        } else {                                                         //要刪除的節點有兩個節點
            TreeNode successor = findSuccessor(current);
            if(current == root){
                root = successor;
            }else if(isLeftNode){
                parent.leftNode = successor;
            }else{
                parent.rightNode = successor;
            }
            successor.leftNode = current.leftNode;
        }
        return true;
    }

    private TreeNode findSuccessor(TreeNode delNode){
        TreeNode parent = delNode;
        TreeNode successor = delNode;
        TreeNode current = delNode.rightNode;
        while(current != null){
            parent = successor;
            successor = current;
            current = current.leftNode;
        }

        if(successor != delNode.rightNode){
            parent.leftNode = successor.rightNode;
            successor.rightNode = delNode.rightNode;
        }
        return successor;
    }