1. 程式人生 > 其它 >java二叉樹的查詢(2)

java二叉樹的查詢(2)

一. 遞迴方式

1. 前序查詢

  • 先判斷當前節點是否要查詢的節點
  • 當前節點有左子樹,向左遞迴,如果找到不為空的節點,說明查詢成功
  • 否則向右遞迴,當前節點有右子樹,向右遞迴,如果找到不為空的節點,說明查詢成功
  • 否則返回null
public HeroNode preOrderSearch(int i) {
        System.out.println("進入前序查詢");
        //比較當前結點是不是
        if (this.id == i)
            return this;
        //1.則判斷當前結點的左子節點是否為空,如果不為空,則遞迴前序查詢
        
//2.如果左遞迴前序查詢,找到結點,則返回 HeroNode node = null; if (this.left != null) { node = this.left.preOrderSearch(i); } if (node != null) return node; //2.當前的結點的右子節點是否為空,如果不空,則繼續向右遞迴前序查詢 if (this.right != null) { node = this.right.preOrderSearch(i); }
return node; }

2. 中序查詢

  • 當前節點有左子樹,向左遞迴,如果找到不為空的節點,說明查詢成功
  • 否則判斷當前節點是否要查詢的節點,如果是返回
  • 否則向右遞迴,當前節點有右子樹,向右遞迴,如果找到不為空的節點,說明查詢成功
  • 否則返回null
 public HeroNode infixOrderSearch(int i) {
        HeroNode node = null;
        if (this.left != null) {
            node = this.left.infixOrderSearch(i);
        }
        System.out.println(
"進入中序查詢"); if (node != null) return node; //比較當前結點是不是 if (this.id == i) return this; if (this.right != null) { node = this.right.infixOrderSearch(i); } return node; }

3. 後序查詢

  • 當前節點有左子樹,向左遞迴,如果找到不為空的節點,說明查詢成功
  • 否則向右遞迴,當前節點有右子樹,向右遞迴,如果找到不為空的節點,說明查詢成功
  • 否則判斷當前節點是否要查詢的節點,如果是返回
  • 否則返回null
 public HeroNode postOrderSearch(int i) {
        HeroNode node = null;
        if (this.left != null) {
            node = this.left.postOrderSearch(i);
        }
        if (node != null)
            return node;
        if (this.right != null) {
            node = this.right.postOrderSearch(i);
        }
        if (node != null)
            return node;
        System.out.println("進入後序查詢");
        if (this.id == i)
            return this;
        return node;
    }

二、非遞迴方式查詢

1.前序查詢

  • 用一個棧儲存當前節點
  • 若棧不為空,彈出棧中一個節點,判斷當前節點是否要查詢的節點,如果是返回
    • 否則若當前節點有右子樹,右子樹入棧
    • 若當前節點有左子樹,左子樹入棧
    • 棧為空,結束迴圈
  • 否則返回null
 public HeroNode preOrderSearch1(int i) {
        System.out.println("前序非遞迴查詢~~");
        Stack<HeroNode> stack = new Stack<>();
        stack.push(this);
        while (!stack.isEmpty()) {
            HeroNode node = stack.pop();
            if (node.id == i)
                return node;
            if (node.right != null)
                stack.push(node.right);
            if (node.left != null)
                stack.push(node.left);
        }
        return null;
    }

2.中序查詢

  • 用一個臨時變數代替當前節點,建立一個棧
  • 若棧不為空或者當前節點不為空
    • 若當前節點不為空,則迴圈至最左節點
    • 若當前節點為空,棧彈出一個節點,判斷當前節點是否為查詢的節點,如果是返回
    • 如果不是,若該節點有右節點,令節點等於右節點
  • 否則返回null
 public HeroNode infixOrderSearch1(int i) {
        System.out.println("中序非遞迴查詢~~");
        Stack<HeroNode> stack = new Stack<>();
        HeroNode node = this;
        while (!stack.isEmpty() || node != null) {
            if (node != null) {
                stack.push(node);
                node = node.left;
            } else {
                node = stack.pop();
                if (node.id == i) return node;
                node = node.right;
            }
        }
        return null;
    }

3.後續查詢

  • 用一個臨時變數代替當前節點,建立兩個棧s1,s2,
  • 當前節點入棧S1
  • 若棧s1不為空,則彈出一個節點
    • 將當前節點入棧s2
    • 如果當前節點有左節點,則入棧s1
    • 如果當前節點有右節點,則入棧s1
  • 若棧s2不為空,依次彈出元素判斷是否為查詢值,否則返回null
 public HeroNode postOrderSearch1(int i) {
        System.out.println("後序非遞迴查詢~~");
        Stack<HeroNode> s1 = new Stack<>();
        Stack<HeroNode> s2 = new Stack<>();
        HeroNode node = this;
        s1.push(node);
        while (!s1.isEmpty()){
            node=s1.pop();
            s2.push(node);
            if(node.left!=null){
                s1.push(node.left);
            }
            if(node.right!=null){
                s1.push(node.right);
            }
        }
        while (!s2.isEmpty()){
            node=s2.pop();
            if(node.id==i)
                return node;
        }
        return null;
    }
  • 用一個臨時變數代替當前節點,lastnode代表最右節點;建立1個棧s1
  • 若當前節點不為空,則迴圈至最左節點入棧s1
  • 若棧s1不為空,則彈出一個節點
    • 若當前節點有有右節點,且右節點沒有被訪問過,則當前節點變為右節點,迴圈至右節點的最左節點
    • 否則判斷當前是否為查詢值,將當前節點的值賦給lastnode,標記已訪問
  • 否則返回null
public HeroNode postOrderSearch2(int i) {
        System.out.println("後序非遞迴查詢~~");
        Stack<HeroNode> s1 = new Stack<>();
        HeroNode node = this;
        HeroNode lasrnode = null;
        while (node!=null){
            s1.push(node);
                node=node.left;
        }
        while (!s1.isEmpty()){
            node=s1.pop();
            if(node.right!=null&& node.right!=lasrnode){
                s1.push(node);
                node=node.right;
                while (node!=null){
                    s1.push(node);
                    node=node.left;
                }
            }else {
                if(node.id==i)
                    return node;
                lasrnode=node;
            }
        }
        return null;
    }
}

三、二叉樹刪除節點

  • 因為我們的二叉樹是單向的,所以我們是判斷當前結點的子結點是否需要刪除結點,而不能去判斷當前這個結點是不是需要刪除結點.
  • 如果當前結點的左子結點不為空,並且左子結點 就是要刪除結點,就將this.left = null; 並且就返回(結束遞迴刪除)
  • 如果當前結點的右子結點不為空,並且右子結點 就是要刪除結點,就將this.right= null ;並且就返回(結束遞迴刪除)
  • 如果第2和第3步沒有刪除結點,那麼我們就需要向左子樹進行遞迴刪除
  • 如果第4步也沒有刪除結點,則應當向右子樹進行遞迴刪除.
 public void delNode(int i) {
        if(root==null) return;
        if(root.id==i)
            root=null;
        else root.delNode(i);

    } 

public void delNode(int i) {
        if(this.left!=null&&this.left.id==i){
            this.left=null;
            return;
        }
        if(this.right!=null&&this.right.id==i){
            this.right=null;
            return;
        }
        if(this.left!=null)
            this.left.delNode(i);
        if(this.right!=null)
            this.right.delNode(i);
    }
  • 找到該值,如果該節點為葉子節點或者該節點只有左節點,返回該節點的左子樹
  • 如果用該節點的右節點的最左節點與該節點進行值交換
  • 遞迴得到總樹
 public HeroNode delNode1(HeroNode root,int i) {
        if (root == null) return root;
        if (root.id == i) {
            if (root.right == null) { // 這裡第二次操作目標值:最終刪除的作用
                return root.left;
            }
            HeroNode cur = root.right;
            while (cur.left!=null) {
                cur = cur.left;
            }
            HeroNode node = new HeroNode(root.id, root.name);
            root.id=cur.id;
            root.name=cur.name;
            cur.id=node.id;
            cur.name=node.name;// 這裡第一次操作目標值:交換目標值其右子樹最左面節點。僅僅是值替換,引用沒有交換
        }
        root.left = delNode1(root.left, i);
        root.right = delNode1(root.right, i);
        return root;
    }