數據結構-二叉搜索樹Java實現


1,Node.java

生成基礎二叉樹的結構

 1 package com.cnblogs.mufasa.searchTree;
 2 
 3 /**
 4  * 節點配置父+左+右
 5  */
 6 public class Node{
 7     Node parent;
 8     Node leftChild;
 9     Node rightChild;
10     int val;
11     public Node(Node parent, Node leftChild, Node rightChild,int val) {
12         super();
13         this.parent = parent;
14         this.leftChild = leftChild;
15         this.rightChild = rightChild;
16         this.val = val;
17     }
18 
19     public Node(int val){
20         this(null,null,null,val);
21     }
22 
23     public Node(Node node,int val){
24         this(node,null,null,val);
25     }
26 }
View Code

圖1 Node.java結構

 

2,SearchBinaryTree.java

在原有二叉樹的結構上,進行搜索二叉樹的功能擴充:

①數據增加:遞歸版本插入、迭代版本

②數據刪除:

③數據查找:

④數據遍歷:前中后

  1 package com.cnblogs.mufasa.searchTree;
  2 
  3 
  4 
  5 public class SearchBinaryTree {
  6 
  7     private Node root;
  8     private int size;
  9     public SearchBinaryTree() {
 10         super();
 11     }
 12 
 13     /**
 14      * 增加節點
 15      * @param val
 16      * @return
 17      */
 18     public boolean add(int val) {
 19         if(root == null){//初始節點為空
 20             root = new Node(val);
 21             size++;
 22             return true;
 23         }
 24         //初始節點不為空
 25         Node node = getAdapterNode(root, val);
 26         Node newNode = new Node(val);
 27         if(node.val > val){
 28             node.leftChild = newNode;
 29             newNode.parent = node;
 30         }else if(node.val < val){
 31             node.rightChild = newNode;
 32             newNode.parent = node;
 33         }else{
 34             return false;//增加數據和搜索二叉樹中原有數據相同不符合基本限定條件
 35         }
 36         size++;
 37         return true;
 38     }
 39 
 40     /**
 41      * 獲取最合適的插入節點
 42      * @param node
 43      * @param val
 44      * @return
 45      */
 46     private Node getAdapterNode(Node node,int val){
 47         //該節點為空
 48         if(node == null){
 49             return node;
 50         }
 51 
 52         // 往左子樹中插入,但沒左子樹,則返回
 53         if(node.val > val && node.leftChild == null){
 54             return node;
 55         }
 56 
 57         // 往右子樹中插入,但沒右子樹,也返回
 58         if(node.val < val && node.rightChild == null){
 59             return node;
 60         }
 61 
 62         // 該節點是葉子節點,則返回
 63         if(node.leftChild == null && node.rightChild == null){
 64             return node;
 65         }
 66 
 67         //節點可以繼續向下,直接遞歸調用
 68         if(node.val > val && node.leftChild != null){
 69             return getAdapterNode(node.leftChild, val);
 70         }else if(node.val < val && node.rightChild != null){
 71             return getAdapterNode(node.rightChild, val);
 72         }else{
 73             return node;
 74         }
 75     }
 76 
 77     /**
 78      * 進行迭代增加元素
 79      * @param val
 80      * @return
 81      */
 82     public boolean put(int val){
 83         return putVal(root,val);
 84     }
 85 
 86     /**
 87      *直接循環搜索目標節點進行數據增加
 88      * @param node
 89      * @param val
 90      * @return
 91      */
 92     private boolean putVal(Node node,int val){
 93         if(node == null){// 初始化根節點
 94             node = new Node(val);
 95             root = node;
 96             size++;
 97             return true;
 98         }
 99         //節點非空
100         Node temp = node;
101         Node p;
102         int t;
103         /**
104          * 通過do while循環迭代獲取最佳節點,
105          */
106         do{
107             p = temp;
108             t = temp.val-val;
109             if(t > 0){
110                 temp = temp.leftChild;
111             }else if(t < 0){
112                 temp = temp.rightChild;
113             }else{
114                 temp.val = val;//增加數據和搜索二叉樹中原有數據相同不符合基本限定條件
115                 return false;
116             }
117         }while(temp != null);
118 
119         Node newNode = new Node(p, val);
120         if(t > 0){
121             p.leftChild = newNode;
122         }else if(t < 0){
123             p.rightChild = newNode;
124         }
125         size++;
126         return true;
127     }
128 
129     /**
130      * 節點刪除
131      * @param val
132      * @return
133      */
134     public boolean delete(int val){
135         Node node = getNode(val);
136         if(node == null){//沒有該節點
137             return false;
138         }
139         Node parent = node.parent;
140         Node leftChild = node.leftChild;
141         Node rightChild = node.rightChild;
142 
143         //以下所有子節點為空的情況,則表明刪除的節點是【葉節點】
144         if(leftChild == null && rightChild == null){//沒有子節點
145             if(parent != null){
146                 if(parent.leftChild == node){
147                     parent.leftChild = null;
148                 }else if(parent.rightChild == node){
149                     parent.rightChild = null;
150                 }
151             }else{//不存在父節點,則表明刪除節點為【根節點】,直接返回空
152                 root = null;
153             }
154             node = null;
155             return true;
156 
157         }else if(leftChild == null && rightChild != null){// 只有右節點
158             if(parent != null && parent.val > val){// 存在父節點,且node位置為父節點的左邊
159                 parent.leftChild = rightChild;
160             }else if(parent != null && parent.val < val){// 存在父節點,且node位置為父節點的右邊
161                 parent.rightChild = rightChild;
162             }else{//父節點不存在!!!
163                 root = rightChild;
164             }
165             node = null;
166             return true;
167 
168         }else if(leftChild != null && rightChild == null){// 只有左節點
169             if(parent != null && parent.val > val){// 存在父節點,且node位置為父節點的左邊
170                 parent.leftChild = leftChild;
171             }else if(parent != null && parent.val < val){// 存在父節點,且node位置為父節點的右邊
172                 parent.rightChild = leftChild;
173             }else{//父節點不存在!!!
174                 root = leftChild;
175             }
176             node = null;
177             return true;
178 
179         }else if(leftChild != null && rightChild != null){// 兩個子節點都存在,相當於直接替換節點
180             Node successor = getSuccessor(node);// 這種情況,一定存在后繼節點
181             int temp = successor.val;
182             boolean delete = delete(temp);
183             if(delete){
184                 node.val = temp;
185             }
186             successor = null;
187             return true;
188         }
189         return false;
190     }
191 
192     /**
193      *
194      * @param node
195      * @return
196      */
197     private Node getSuccessor(Node node){
198         if(node.rightChild != null){//肯定不為空
199             Node rightChild = node.rightChild;
200             while(rightChild.leftChild != null){//不斷的向左轉向搜索數值
201                 rightChild = rightChild.leftChild;
202             }
203             return rightChild;
204         }
205         //右節點為空這個不存在啊!!!
206         Node parent = node.parent;
207         while(parent != null && (node == parent.rightChild)){
208             node = parent;
209             parent = parent.parent;
210         }
211         return parent;
212     }
213 
214 
215     /**
216      * 搜索節點
217      * @param val
218      * @return
219      */
220     public Node getNode(int val){
221         Node temp = root;
222         int t;
223         do{//直接使用循環遍歷的方法
224             t = temp.val-val;
225             if(t > 0){
226                 temp = temp.leftChild;
227             }else if(t < 0){
228                 temp = temp.rightChild;
229             }else{
230                 return temp;
231             }
232         }while(temp != null);
233         return null;
234     }
235 
236     /**
237      * 節點刪除
238      * @param val
239      * @return
240      */
241     public boolean remove(int val){
242         Node node = getNode(val);
243         if(node == null){
244             return false;
245         }
246 
247         if(node.leftChild == null){// 1、左節點不存在,右節點可能存在,包含兩種情況  ,兩個節點都不存在和只存在右節點
248             transplant(node, node.rightChild);
249         }else if(node.rightChild == null){//2、左孩子存在,右節點不存在
250             transplant(node, node.leftChild);
251         }else{// 3、兩個節點都存在
252             Node successor = getSuccessor(node);// 得到node后繼節點
253             if(successor.parent != node){// 后繼節點存在node的右子樹中。
254                 transplant(successor, successor.rightChild);// 用后繼節點的右子節點替換該后繼節點
255                 successor.rightChild = node.rightChild;// 將node節點的右子樹賦給后繼節點的右節點,即類似后繼與node節點調換位置
256                 successor.rightChild.parent = successor;// 接着上一步  給接過來的右節點的父引用復制
257             }
258             transplant(node, successor);
259             successor.leftChild = node.leftChild;
260             successor.leftChild.parent = successor;
261         }
262         return true;
263     }
264     /**
265      * 將child節點替換node節點
266      * @param node    要刪除的節點
267      * @param child   node節點的子節點
268      */
269     private void transplant(Node node,Node child){
270         /**
271          * 1、先判斷 node是否存在父節點
272          *    1、不存在,則child替換為根節點
273          *    2、存在,則繼續下一步
274          * 2、判斷node節點是父節點的那個孩子(即判斷出 node是右節點還是左節點),
275          *    得出結果后,將child節點替換node節點 ,即若node節點是左節點 則child替換后 也為左節點,否則為右節點
276          * 3、將node節點的父節點置為child節點的父節點
277          */
278 
279         if(node.parent == null){
280             this.root = child;
281         }else if(node.parent.leftChild == node){
282             node.parent.leftChild = child;
283         }else if(node.parent.rightChild == node){
284             node.parent.rightChild = child;
285         }
286         if(child != null){
287             child.parent = node.parent;
288         }
289     }
290 
291     public void print(int type){//方法的重載
292         if(type==0){//前序
293             printPre(root);
294         }else if(type==1){
295             printMid(root);
296         }else if(type==2){
297             printEnd(root);
298         }
299     }
300 
301     private void printPre(Node root){//前序遍歷
302         if(root != null){
303             System.out.println(root.val);// 位置在中間,則中序,若在前面,則為先序,否則為后續
304             printPre(root.leftChild);
305             printPre(root.rightChild);
306         }
307     }
308 
309     private void printMid(Node root){//中序遍歷
310         if(root != null){
311             printMid(root.leftChild);
312             System.out.println(root.val);// 位置在中間,則中序,若在前面,則為先序,否則為后續
313             printMid(root.rightChild);
314         }
315     }
316 
317     private void printEnd(Node root){//后序遍歷
318         if(root != null){
319             printEnd(root.leftChild);
320             printEnd(root.rightChild);
321             System.out.println(root.val);// 位置在中間,則中序,若在前面,則為先序,否則為后續
322         }
323     }
324 
325 }
View Code

 

圖2 SearchBinaryTree.java結構

 

3,JavaDemo.java

 1 package com.cnblogs.mufasa.searchTree;
 2 
 3 public class JavaDemo {
 4     public static void main(String[] args) {
 5         SearchBinaryTree tree=new SearchBinaryTree();
 6         tree.add(5);
 7         tree.add(1);
 8         tree.add(100);
 9         tree.add(50);
10         tree.add(22);
11         tree.add(48);
12         tree.print(2);
13     }
14 }
View Code

 

4,特別鳴謝

https://www.cnblogs.com/qm-article/p/9279655.html


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com