標籤:margin bsp offer 小結 msu iss 面試 父節點 public
二叉尋找樹BST----java實現
1.二叉尋找樹簡單介紹
二叉尋找樹又名二叉搜尋樹和二叉排序樹。性質例如以下:
在二叉尋找樹中:
(01) 若隨意節點的左子樹不空,則左子樹上全部結點的值均小於它的根結點的值。
(02) 隨意節點的右子樹不空,則右子樹上全部結點的值均大於它的根結點的值;
(03) 隨意節點的左、右子樹也分別為二叉尋找樹。
(04) 沒有索引值相等的節點(no duplicate nodes)。
2.二叉尋找樹節點類
class TreeNode{int value;TreeNode parent;TreeNode left;TreeNode right;public TreeNode(int value, TreeNode parent, TreeNode left, TreeNode right) {this.value = value;this.parent = parent;this.left = left;this.right = right;} }
3.遍曆
二叉尋找樹的遍曆同二叉樹的遍曆,遞迴與非遞迴方法詳見《二叉樹的遞迴遍曆和非遞迴遍曆(附具體範例)》
4.最大和最小值
a.BST中的最小值即最左的孩子。
//求BST的最小值public TreeNode getMin(TreeNode root){if(root==null)return null;while(root.left!=null)root=root.left; return root;}
b.BST中的最大值即最右的孩子。
//求BST的最大值public TreeNode getMax(TreeNode root){if(root==null)return null;while(root.right!=null)root=root.right;return root;}
5.前驅和後繼節點
ps:圖片來於網路
a.BST中某節點前驅節點==小於該節點的全部節點中的最大值
前驅easy情形:5尋前驅 4
前驅複雜情形:11尋前驅 10
//尋找BST中某節點的前驅節點.即尋找資料值小於該結點的最大結點。public TreeNode preNode(TreeNode x){if(x==null)return null;// 假設x存在左孩子,則"x的前驅結點"為 "以其左孩子為根的子樹的最大結點"。 if(x.left!=null) return getMax(x.left); // 假設x沒有左孩子。
則x有下面兩種可能: // (01) x是"一個右孩子",則"x的前驅結點"為 "它的父結點"。 // (02) x是"一個左孩子",則 前驅節點為x的某一個祖先節點的父節點,並且該祖先節點是作為其父節點的右兒子 TreeNode p=x.parent; while(p!=null&&p.left==x) { x=p;//父節點置為新的x p=p.parent; //父節點的父節點置為新的父節點 } return p; }
b.BST中某節點後繼節點==大於該節點的全部節點中的最小值
後繼easy情形:5尋後繼 6
複雜情形:9尋後繼 10
//尋找BST中某節點的後繼節點.即尋找資料值大於該結點的最小結點。public TreeNode postNode(TreeNode x){if(x==null)return null;// 假設x存在右孩子,則"x的後繼結點"為 "以其右孩子為根的子樹的最小結點"。 if(x.left!=null) return getMin(x.right); // 假設x沒有右孩子。則x有下面兩種可能: // (01) x是"一個左孩子",則"x的後繼結點"為 "它的父結點"。 // (02) x是"一個右孩子",則 前驅節點為x的某一個祖先節點的父節點,並且該祖先節點是作為其父節點的左兒子 TreeNode p=x.parent; while(p!=null&&p.right==x) { x=p;//父節點置為新的x p=p.parent; //父節點的父節點置為新的父節點 } return p; }
6.尋找
尋找值為val的節點,假設小於根節點在左子樹尋找,反之在右子樹尋找
//尋找值為val的節點 --遞迴版--public TreeNode searchRec(TreeNode root ,int val){if(root==null)return root;if(val<root.value)return searchRec(root.left,val);else if(val>root.value)return searchRec(root.right,val);elsereturn root;}//尋找值為val的節點 --非 遞迴版--public TreeNode search(TreeNode root ,int val){if(root==null)return root;while(root!=null){if(val<root.value)root=root.left;else if(val>root.value)root=root.right;elsereturn root;}return root;}
7.插入
a.若當前的二叉尋找樹為空白,則插入的元素為根節點
b.若插入的元素值小於根節點值。則將元素插入到左子樹中
c.若插入的元素值不小於根節點值,則將元素插入到右子樹中。首先找到插入的位置,要麼向左,要麼向右,直到找到空結點,即為插入位置,假設找到了同樣值的結點,插入失敗。
//BST插入節點 --遞迴版--public TreeNode insertRec(TreeNode root,TreeNode x){if(root==null)root=x;else if(x.value<root.value)root.left=insertRec(root.left, x);else if(x.value>root.value)root.right=insertRec(root.right, x);return root;}//BST插入節點 --非 遞迴版--public TreeNode insert(TreeNode root,TreeNode x){if(root==null)root=x;TreeNode p=null;//須要記錄父節點while(root!=null)//定位插入的位置{p=root;//記錄父節點if(x.value<root.value)root=root.left;elseroot=root.right;}x.parent=p;//定位到合適的頁節點的空白處後。依據和父節點的大小比較插入合適的位置if(x.value<p.value) p.left=x;else if(x.value>p.value)p.right=x;return root;}
8.刪除
二叉尋找樹的刪除,分三種情況進行處理:
1.p為葉子節點。直接刪除該節點,再改動其父節點的指標(注意分是根節點和不是根節點),a。
2.p為單支節點(即僅僅有左子樹或右子樹)。
讓p的子樹與p的父親節點相連,刪除p就可以。(注意分是根節點和不是根節點);b。
3.有兩個孩子的情況,當前結點與左子樹中最大的元素交換。然後刪除當前結點。左子樹最大的元素一定是葉子結點,交換後。當前結點即為葉子結點。刪除參考沒有孩子的情況。還有一種方法是,當前結點與右子樹中最小的元素交換,然後刪除當前結點。c。
ps:圖片來於網路
//BST刪除節點public void delete(TreeNode root,TreeNode x){if(root==null)return ;TreeNode p=null;while(root!=null)//定位到須要刪除的節點{if(x.value<root.value){p=root;//記錄父節點root=root.left;}else if(x.value>root.value){p=root;//記錄父節點root=root.right;}else//找到啦{if(root.left==null&&root.right==null)//①待刪除的是 葉子節點{if(p==null)//待刪除的是根節點root=null;else{if(p.left==root)p.left=null;else if(p.right==root)p.right=null;}}else if(root.left!=null&&root.right==null)//② 待刪除的節點僅僅有左孩子{if(p==null)//待刪除的是根節點root=root.left;else{ if(p.left==root)//待刪除的本身是一個左孩子 p.left=root.left; else if(p.right==root) p.right=root.left;}}else if(root.left==null&&root.right!=null)//② 待刪除的節點僅僅有右孩子{if(p==null)//待刪除的是根節點root=root.right;else{ if(p.left==root)//待刪除的本身是一個左孩子 p.left=root.right; else if(p.right==root) p.right=root.right; }}else//③待刪除的節點即有左孩子又有右孩子 方法:得到待刪除節點右子樹的最小值。 {//該最小值與待刪除節點進行“ 值 ”交換。刪除該最小值位置處的節點TreeNode rMin=root.right; //求待刪除節點的後繼節點,即待刪除節點的右孩子的最小值(找到的後繼節點肯定沒有左孩子!!。)TreeNode rMinP=null;//由於須要刪除後繼節點位置,所以須要記錄父節點while(rMin!=null){rMinP=rMin;rMin=rMin.left;} int rootVtemp=root.value;//值交換 root.value=rMin.value; rMin.value=rootVtemp; //刪除rMin位置的節點,此時此位置的值已是待刪節點的值 if(rMinP.left==rMin) rMinP.left=rMin.right; else if(rMinP.right==rMin) rMinP.right=rMin.right;}}break;//找到後刪了後就跳出while迴圈} }
9.二叉樹尋找樹常見面試題
a.推斷一個數組是不是二叉搜尋樹的後序遍曆
package com.sheepmu;public class Offer24 {public static void main(String[] args){int[] a={5,7,6,9,11,10,8};int len=a.length; System.out.println(isProOfBST(a,len));}public static boolean isProOfBST(int[] a,int len) {if(a==null||len<=0)return false;int root=a[len-1];//後序遍曆的最後一個為根節點int i=0;while(a[i]<root)//找到左樹的個數i++;int j=i;//先看右樹中是否有非法數字,即比根節點小的數字while(j<len-1){if(a[j]<root)return false;j++;}//若左右子樹的數字都合法,即左子樹都比根的值小,右子樹都比根節點大;此時僅僅需遞迴推斷左右子樹是否是二叉搜尋樹的後序遍曆//求左右子樹的數組,到這兒明顯發現用字串非常爽呀直接subString()boolean left=true;if(i>0)//必需要推斷是否存在左樹{int[] aleft=new int[i];for(int x=0;x<i;x++) aleft[x]=a[x]; left=isProOfBST(aleft,i);}boolean right=true;if(i<len-1)//必需要推斷是否存在右樹{int[] aright=new int[len-i-1];//for(int y=i;y<len-1;y++)//粗心啊!!。!//{//aright[y]=a[y];//}for(int y=0;y<len-i-1;y++)aright[y]=a[i+y]; right=isProOfBST(aright,len-i-1);}return left&&right;}}
b.將一顆二叉搜尋樹轉為為排序的雙向鏈表
二叉尋找樹BST----java實現