一、樹 & 二叉樹
樹 是由節(jié)點(diǎn)和邊構(gòu)成,儲(chǔ)存元素的集合。節(jié)點(diǎn)分根節(jié)點(diǎn)、父節(jié)點(diǎn)和子節(jié)點(diǎn)的概念。 如圖:樹深=4; 5是根節(jié)點(diǎn);同樣8與3的關(guān)系是父子節(jié)點(diǎn)關(guān)系。
二叉樹binary tree ,則加了“二叉”(binary),意思是在樹中作區(qū)分。每個(gè)節(jié)點(diǎn)至多有兩個(gè)子(child),left child & right child。二叉樹在很多例子中使用,比如二叉樹表示算術(shù)表達(dá)式。 如圖:1/8是左節(jié)點(diǎn);2/3是右節(jié)點(diǎn);
二、二叉搜索樹 BST
顧名思義,二叉樹上又加了個(gè)搜索的限制。其要求:每個(gè)節(jié)點(diǎn)比其左子樹元素大,比其右子樹元素小。 如圖:每個(gè)節(jié)點(diǎn)比它左子樹的任意節(jié)點(diǎn)大,而且比它右子樹的任意節(jié)點(diǎn)小
三、BST Java實(shí)現(xiàn)
直接上代碼,對(duì)應(yīng)代碼分享在?Github?主頁 BinarySearchTree.java
package org.algorithm.tree;
/** Copyright [2015] [Jeff Lee]** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*//*** 二叉搜索樹(BST)實(shí)現(xiàn)** Created by bysocket on 16/7/7.*/
public class BinarySearchTree {/*** 根節(jié)點(diǎn)*/public static TreeNode root;public BinarySearchTree() {this.root = null;}/*** 查找* 樹深(N) O(lgN)* 1. 從root節(jié)點(diǎn)開始* 2. 比當(dāng)前節(jié)點(diǎn)值小,則找其左節(jié)點(diǎn)* 3. 比當(dāng)前節(jié)點(diǎn)值大,則找其右節(jié)點(diǎn)* 4. 與當(dāng)前節(jié)點(diǎn)值相等,查找到返回TRUE* 5. 查找完畢未找到,* @param key* @return*/public TreeNode search (int key) {TreeNode current = root;while (current != null&& key != current.value) {if (key < current.value )current = current.left;elsecurrent = current.right;}return current;}/*** 插入* 1. 從root節(jié)點(diǎn)開始* 2. 如果root為空,root為插入值* 循環(huán):* 3. 如果當(dāng)前節(jié)點(diǎn)值大于插入值,找左節(jié)點(diǎn)* 4. 如果當(dāng)前節(jié)點(diǎn)值小于插入值,找右節(jié)點(diǎn)* @param key* @return*/public TreeNode insert (int key) {// 新增節(jié)點(diǎn)TreeNode newNode = new TreeNode(key);// 當(dāng)前節(jié)點(diǎn)TreeNode current = root;// 上個(gè)節(jié)點(diǎn)TreeNode parent = null;// 如果根節(jié)點(diǎn)為空if (current == null) {root = newNode;return newNode;}while (true) {parent = current;if (key < current.value) {current = current.left;if (current == null) {parent.left = newNode;return newNode;}} else {current = current.right;if (current == null) {parent.right = newNode;return newNode;}}}}/*** 刪除節(jié)點(diǎn)* 1.找到刪除節(jié)點(diǎn)* 2.如果刪除節(jié)點(diǎn)左節(jié)點(diǎn)為空 , 右節(jié)點(diǎn)也為空;* 3.如果刪除節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn) 右節(jié)點(diǎn) 或者 左節(jié)點(diǎn)* 4.如果刪除節(jié)點(diǎn)左右子節(jié)點(diǎn)都不為空* @param key* @return*/public TreeNode delete (int key) {TreeNode parent = root;TreeNode current = root;boolean isLeftChild = false;// 找到刪除節(jié)點(diǎn) 及 是否在左子樹while (current.value != key) {parent = current;if (current.value > key) {isLeftChild = true;current = current.left;} else {isLeftChild = false;current = current.right;}if (current == null) {return current;}}// 如果刪除節(jié)點(diǎn)左節(jié)點(diǎn)為空 , 右節(jié)點(diǎn)也為空if (current.left == null && current.right == null) {if (current == root) {root = null;}// 在左子樹if (isLeftChild == true) {parent.left = null;} else {parent.right = null;}}// 如果刪除節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn) 右節(jié)點(diǎn) 或者 左節(jié)點(diǎn)else if (current.right == null) {if (current == root) {root = current.left;} else if (isLeftChild) {parent.left = current.left;} else {parent.right = current.left;}}else if (current.left == null) {if (current == root) {root = current.right;} else if (isLeftChild) {parent.left = current.right;} else {parent.right = current.right;}}// 如果刪除節(jié)點(diǎn)左右子節(jié)點(diǎn)都不為空else if (current.left != null && current.right != null) {// 找到刪除節(jié)點(diǎn)的后繼者TreeNode successor = getDeleteSuccessor(current);if (current == root) {root = successor;} else if (isLeftChild) {parent.left = successor;} else {parent.right = successor;}successor.left = current.left;}return current;}/*** 獲取刪除節(jié)點(diǎn)的后繼者* 刪除節(jié)點(diǎn)的后繼者是在其右節(jié)點(diǎn)樹種最小的節(jié)點(diǎn)* @param deleteNode* @return*/public TreeNode getDeleteSuccessor(TreeNode deleteNode) {// 后繼者TreeNode successor = null;TreeNode successorParent = null;TreeNode current = deleteNode.right;while (current != null) {successorParent = successor;successor = current;current = current.left;}// 檢查后繼者(不可能有左節(jié)點(diǎn)樹)是否有右節(jié)點(diǎn)樹// 如果它有右節(jié)點(diǎn)樹,則替換后繼者位置,加到后繼者父親節(jié)點(diǎn)的左節(jié)點(diǎn).if (successor != deleteNode.right) {successorParent.left = successor.right;successor.right = deleteNode.right;}return successor;}public void toString(TreeNode root) {if (root != null) {toString(root.left);System.out.print("value = " + root.value + " -> ");toString(root.right);}}
}/*** 節(jié)點(diǎn)*/
class TreeNode {/*** 節(jié)點(diǎn)值*/int value;/*** 左節(jié)點(diǎn)*/TreeNode left;/*** 右節(jié)點(diǎn)*/TreeNode right;public TreeNode(int value) {this.value = value;left = null;right = null;}
}
1.?節(jié)點(diǎn)數(shù)據(jù)結(jié)構(gòu) 首先定義了節(jié)點(diǎn)的數(shù)據(jù)接口,節(jié)點(diǎn)分左節(jié)點(diǎn)和右節(jié)點(diǎn)及本身節(jié)點(diǎn)值。如圖
代碼如下:
/*** 節(jié)點(diǎn)*/
class TreeNode {/*** 節(jié)點(diǎn)值*/int value;/*** 左節(jié)點(diǎn)*/TreeNode left;/*** 右節(jié)點(diǎn)*/TreeNode right;public TreeNode(int value) {this.value = value;left = null;right = null;}
}
?
2. 插入 插入,和刪除一樣會(huì)引起二叉搜索樹的動(dòng)態(tài)變化。插入相對(duì)刪處理邏輯相對(duì)簡單些。如圖插入的邏輯:
a. 從root節(jié)點(diǎn)開始 b.如果root為空,root為插入值 c.循環(huán): d.如果當(dāng)前節(jié)點(diǎn)值大于插入值,找左節(jié)點(diǎn) e.如果當(dāng)前節(jié)點(diǎn)值小于插入值,找右節(jié)點(diǎn) 代碼對(duì)應(yīng):
/*** 插入* 1. 從root節(jié)點(diǎn)開始* 2. 如果root為空,root為插入值* 循環(huán):* 3. 如果當(dāng)前節(jié)點(diǎn)值大于插入值,找左節(jié)點(diǎn)* 4. 如果當(dāng)前節(jié)點(diǎn)值小于插入值,找右節(jié)點(diǎn)* @param key* @return*/public TreeNode insert (int key) {// 新增節(jié)點(diǎn)TreeNode newNode = new TreeNode(key);// 當(dāng)前節(jié)點(diǎn)TreeNode current = root;// 上個(gè)節(jié)點(diǎn)TreeNode parent = null;// 如果根節(jié)點(diǎn)為空if (current == null) {root = newNode;return newNode;}while (true) {parent = current;if (key < current.value) {current = current.left;if (current == null) {parent.left = newNode;return newNode;}} else {current = current.right;if (current == null) {parent.right = newNode;return newNode;}}}}
?
3.查找
其算法復(fù)雜度 :?O(lgN),樹深(N)。如圖查找邏輯:
a.從root節(jié)點(diǎn)開始 b.比當(dāng)前節(jié)點(diǎn)值小,則找其左節(jié)點(diǎn) c.比當(dāng)前節(jié)點(diǎn)值大,則找其右節(jié)點(diǎn) d.與當(dāng)前節(jié)點(diǎn)值相等,查找到返回TRUE e.查找完畢未找到 代碼對(duì)應(yīng):
/*** 查找* 樹深(N) O(lgN)* 1. 從root節(jié)點(diǎn)開始* 2. 比當(dāng)前節(jié)點(diǎn)值小,則找其左節(jié)點(diǎn)* 3. 比當(dāng)前節(jié)點(diǎn)值大,則找其右節(jié)點(diǎn)* 4. 與當(dāng)前節(jié)點(diǎn)值相等,查找到返回TRUE* 5. 查找完畢未找到,* @param key* @return*/public TreeNode search (int key) {TreeNode current = root;while (current != null&& key != current.value) {if (key < current.value )current = current.left;elsecurrent = current.right;}return current;}
4. 刪除 首先找到刪除節(jié)點(diǎn),其尋找方法:刪除節(jié)點(diǎn)的后繼者是在其右節(jié)點(diǎn)樹種最小的節(jié)點(diǎn)。如圖刪除對(duì)應(yīng)邏輯:
結(jié)果為:
a.找到刪除節(jié)點(diǎn) b.如果刪除節(jié)點(diǎn)左節(jié)點(diǎn)為空 , 右節(jié)點(diǎn)也為空; c.如果刪除節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn) 右節(jié)點(diǎn) 或者 左節(jié)點(diǎn) d.如果刪除節(jié)點(diǎn)左右子節(jié)點(diǎn)都不為空 代碼對(duì)應(yīng)見上面完整代碼。
?
案例測試代碼如下,BinarySearchTreeTest.java
package org.algorithm.tree;
/** Copyright [2015] [Jeff Lee]** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*//*** 二叉搜索樹(BST)測試案例 {@link BinarySearchTree}** Created by bysocket on 16/7/10.*/
public class BinarySearchTreeTest {public static void main(String[] args) {BinarySearchTree b = new BinarySearchTree();b.insert(3);b.insert(8);b.insert(1);b.insert(4);b.insert(6);b.insert(2);b.insert(10);b.insert(9);b.insert(20);b.insert(25);// 打印二叉樹b.toString(b.root);System.out.println();// 是否存在節(jié)點(diǎn)值10TreeNode node01 = b.search(10);System.out.println("是否存在節(jié)點(diǎn)值為10 => " + node01.value);// 是否存在節(jié)點(diǎn)值11TreeNode node02 = b.search(11);System.out.println("是否存在節(jié)點(diǎn)值為11 => " + node02);// 刪除節(jié)點(diǎn)8TreeNode node03 = b.delete(8);System.out.println("刪除節(jié)點(diǎn)8 => " + node03.value);b.toString(b.root);}
}
運(yùn)行結(jié)果如下:
value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 8 -> value = 9 -> value = 10 -> value = 20 -> value = 25 ->
是否存在節(jié)點(diǎn)值為10 => 10
是否存在節(jié)點(diǎn)值為11 => null
刪除節(jié)點(diǎn)8 => 8
value = 1 -> value = 2 -> value = 3 -> value = 4 -> value = 6 -> value = 9 -> value = 10 -> value = 20 -> value = 25 ->
四、小結(jié)
與偶爾吃一碗“老壇酸菜牛肉面”一樣的味道,品味一個(gè)算法,比如BST,的時(shí)候,總是那種說不出的味道。
樹,二叉樹的概念
BST算法
相關(guān)代碼分享在?Github?主頁
轉(zhuǎn)載自 并發(fā)編程網(wǎng) – ifeve.com本文鏈接地址: ? Java實(shí)現(xiàn) 二叉搜索樹算法(BST)
總結(jié)
以上是生活随笔 為你收集整理的Java实现 二叉搜索树算法(BST) 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔 推薦給好友。