java二叉樹的查詢(2)
阿新 • • 發佈:2021-12-08
一. 遞迴方式
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; }