二叉排序树或二叉搜索树
一、二叉樹基礎
1.1 二叉排序樹定義
二叉排序樹(Binary Sort Tree)又稱二叉查找(搜索)樹(Binary Search Tree)。它是一顆空樹,或者具有下列性質:
- 若它的左子樹不為空,則左子樹上所有結點的值均小于它的根結點的值;
- 若它的右子樹不為空,則右子樹上所有結點的值均大于它的根結點的值;
- 它的左、右子樹分別為二叉排序樹。
上述性質簡稱二叉排序樹性質(BST性質),故二叉排序樹實際上是滿足BST性質的二叉樹。
注意:
當用線性表作為表的組織形式時,可以有三種查找法。其中以二分查找效率最高。但由于二分查找要求表中結點按關鍵字有序,且不能用鏈表作存儲結構,因此,當表的插入或刪除操作頻繁時,為維護表的有序性,勢必要移動表中很多結點。這種由移動結點引起的額外時間開銷,就會抵消二分查找的優點。也就是說,二分查找只適用于靜態查找表。若要對動態查找表進行高效率的查找,可采用下二叉樹或樹作為表的組織形式。不妨將它們統稱為樹表。
1.2 特點
由BST性質可得:
(1) 二叉排序樹中任一結點x,其左(右)子樹中任一結點y(若存在)的關鍵字必小(大)于x的關鍵字。
(2) 二叉排序樹中,各結點關鍵字是惟一的。
注意:
實際應用中,不能保證被查找的數據集中各元素的關鍵字互不相同,所以可將二叉排序樹定義中BST性質(1)里的"小于"改為"大于等于",或將BST性質(2)里的"大于"改為"小于等于",甚至可同時修改這兩個性質。
(3) 按中序遍歷該樹所得到的中序序列是一個遞增有序序列。
【例】下圖所示的兩棵樹均是二叉排序樹,它們的中序序列均為有序序列:2,3,4,5,7,8。
2、二叉樹操作
二叉樹TreeNode節點定義:
class TreeNode{public int data;public TreeNode left;public TreeNode right;TreeNode(int data){this.data=data;} }2.1 二叉樹的插入
2.1.1 遞歸實現
//添加節點(遞歸模式) public static boolean AddTreeNode1(TreeNode root, int data){TreeNode treeNode=new TreeNode(data);//樹為空if(root==null){root=treeNode;return true;}//比根節點小,插入到左子樹if(root.data>data){if(root.left==null){root.left=treeNode;return true;}elsereturn AddTreeNode1(root.left, data);}else if(root.data<data){ //比根節點大,插入到右子樹if(root.right==null){root.right=treeNode;return true;}elsereturn AddTreeNode1(root.right,data);}elsereturn false; }2.1.2 非遞歸模式
//增加節點非遞歸模式 public static boolean AddTreeNode2(TreeNode root, int data){//樹為空if(root==null){root=new TreeNode(data);return true;}TreeNode treeNode=new TreeNode(data);TreeNode currNode=root;while(true){if(currNode.data>data){if(currNode.left!=null)currNode=currNode.left;else{currNode.left=treeNode;return true;}}else if(currNode.data<treeNode.data){if(currNode.right!=null)currNode=currNode.right;else {currNode.right=treeNode;return true;}}elsereturn false;} }2.2 二叉樹的查找
public static boolean search(TreeNode root, int data){if(root==null){return false;}else if(root.data==data){return true;}else if(root.data>data){return search(root.left,data);}else{return search(root.right,data);} }2.3 二叉樹的刪除
刪除可為BST問題最為復雜的一部分,需要考慮一下要刪除的節點的四種情況:
首先,我們知道二叉排序樹經過中序遍歷后得到的是一個遞增有序序列,該節點的前一個即為直接前驅,后一個為直接后繼。我們要得到直接前驅和直接后繼的節點。
方法一:
- 得到該刪除節點的左節點,如果此左節點沒有右節點,則該左節點即為直接前驅;
- 左節點有右節點,則一直沿最右側右節點迭代下去,最后面的那個即為直接前驅;
方法二:
- 得到該刪除節點的右節點,如果此右節點沒有左節點,則該右節點即為直接后繼;
- 右節點有左節點,則一直沿最左側左節點迭代下去,最后面的那個即為直接后繼。
以上四種情況均要考慮要刪除的節點為根節點root的情況。
代碼實現如下:
//刪除public static boolean delete(TreeNode root, int data){//current為查找得到的節點TreeNode current=root;//parent為時刻更新父節點TreeNode parent=root;//tempParent為同時存在左右子樹的迭代臨時父節點TreeNode tempParent=root;//isLeft記錄current節點的左右屬性boolean isLeft=true;while(current.data!=data){parent=current;//到左子樹查找if(current.data>data){isLeft=true;current=current.left;}else if(current.data<data){ //到右子樹查找isLeft=false;current=current.right;}//查不到,返回falseif(current==null)return false;}//第一種情況:刪除節點為葉節點if(current.left==null && current.right==null){if(current==root)root=null;if(isLeft) {parent.left = null;}else{parent.right = null;}return true;}else if(current.right==null){ //第二種情況:刪除節點只有左節點if(current==root)root=current.left;else if(isLeft)parent.left=current.left;elseparent.right=current.left;return true;}else if(current.left==null){ //第三種情況:刪除節點只有右節點if(current==root)root=current.right;else if(isLeft)parent.left=current.right;elseparent.right=current.right;return true;}else{ //第四種情況:刪除節點均存在左節點和右節點if(current==root){root=root.left;}TreeNode tempNode=current.left;//沒有左節點if(tempNode.right==null){if(isLeft)parent.left=tempNode;elseparent.right=tempNode;}else{ //存在左節點,迭代到最右側子節點,即直接前驅while(tempNode.right!=null){tempParent=tempNode;tempNode=tempNode.right;}if(isLeft){ //為左節點,連接parent.left=tempNode;parent.left.left=current.left;}else{ //為右節點,連接parent.right=tempNode;parent.right.left=current.left;}//刪除前驅節點,連接if(tempNode.left==null)tempParent.right=null;elsetempParent.right=tempNode.left;}return true;}}2.4 二叉樹的遍歷
//二叉樹中序遍歷 public static void midSort(TreeNode root){if(root==null){return;}midSort(root.left);System.out.print(root.data+" ");midSort(root.right); }2.5 測試代碼
public static void main(String[] args){int[] a=new int[]{62,88,58,47,35,73,51,99,37,93};TreeNode root=new TreeNode(a[0]);for(int i=1; i<a.length; i++){AddTreeNode1(root, a[i]);}System.out.println("中序遍歷結果為:");midSort(root);System.out.println("47存在:"+SearchTreeNode(root,47));AddTreeNode1(root,100);System.out.println("添加100后,中序遍歷結果為:");midSort(root);System.out.println("添加100后,100存在:"+SearchTreeNode(root,100)); }輸出結果:
中序遍歷結果為: 35 37 47 51 58 62 73 88 93 99 47存在:true 添加100后,中序遍歷結果為: 35 37 47 51 58 62 73 88 93 99 100 添加100后,100存在:true 刪除100后,中序遍歷結果為: 35 37 47 51 58 62 73 88 93 99 刪除100后,100存在:false3、二叉排序樹拓展
平衡二叉排序樹:https://blog.csdn.net/zhaohong_bo/article/details/90311112
總結
以上是生活随笔為你收集整理的二叉排序树或二叉搜索树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字典树(Trie树)的原理与实现
- 下一篇: floquet端口x极化入射波_hfss