Java實(shí)現(xiàn)二分搜索樹的示例代碼
1.概念
a.是個(gè)二叉樹(每個(gè)節(jié)點(diǎn)最多有兩個(gè)子節(jié)點(diǎn))
b.對(duì)于這棵樹中的節(jié)點(diǎn)的節(jié)點(diǎn)值
左子樹中的所有節(jié)點(diǎn)值 < 根節(jié)點(diǎn) < 右子樹的所有節(jié)點(diǎn)值
二分搜索樹中一般不考慮值相等的情況(元素不重復(fù))JDK中的搜索樹就不存在相同的值(TreeMap-key)
最大特點(diǎn):也是判斷是否是搜索樹的方法
對(duì)該樹進(jìn)行中序遍歷,就可以得到一個(gè)升序集合0 1 2 3 4 5 6 7 8 9
在一個(gè)有序區(qū)間上進(jìn)行二分查找的時(shí)間復(fù)雜度? logn不斷將集合/2/2 / 2 ==1為止logN
logN =》聯(lián)想到"樹"
2.重點(diǎn)操作
當(dāng)刪除58時(shí),此節(jié)點(diǎn)左右子樹都不為空
Hibbard Deletion 1962
在BST中刪除一個(gè)左右子樹都存在的節(jié)點(diǎn)
找到當(dāng)前以58為根節(jié)點(diǎn)的前驅(qū)或者后繼節(jié)點(diǎn)作為刪除后的新節(jié)點(diǎn)
前驅(qū):在以58為根的BST中最后一個(gè)小于58的節(jié)點(diǎn)->53
后繼:在以58為根的BST中第一個(gè)大于58的節(jié)點(diǎn)->59
當(dāng)我們使用后繼節(jié)點(diǎn)時(shí),先連removeMin(root.right),在連root.left
TreeNode successor = findMin(root.right); successor.right = removeMin(root.right); successor.left = root.left;
3.完整代碼
import java.util.NoSuchElementException; /** * 基于整型的 * 普通的二分搜索樹 */ public class BST { private class TreeNode{ private int val; private TreeNode left; private TreeNode right; public TreeNode(int val) { this.val = val; } } private int size; private TreeNode root; /** * 向以root為根的BST中插入一個(gè)新的結(jié)點(diǎn)val * @param val */ public void add(int val){ root = add(root,val); } private TreeNode add(TreeNode root, int val) { if(root == null){ //創(chuàng)建一個(gè)新節(jié)點(diǎn) TreeNode newNode = new TreeNode(val); size++; return newNode; } //左子樹插入 if(val < root.val){ root.left = add(root.left,val); } //右子樹插入 if(val > root.val){ root.right = add(root.right,val); } return root; } /** * 判斷當(dāng)前以root為根的BST中是否包含了val * @param val * @return */ public boolean contains(int val){ return contains(root,val); } private boolean contains(TreeNode root, int val) { if(root == null){ return false; } if(val == root.val){ //找到了 return true; }else if(val < root.val){ //遞歸左子樹查找 return contains(root.left,val); }else{ //遞歸右子樹查找 return contains(root.right,val); } } /** * 找到最小值 * @return */ public int findMin(){ //判空 if(root == null){ //拋出一個(gè)空指針異常 throw new NoSuchElementException("root is empty! cannot find min"); } TreeNode minNode = findMin(root); return minNode.val; } private TreeNode findMin(TreeNode root) { //當(dāng)此節(jié)點(diǎn)左子樹為空,說明此節(jié)點(diǎn)是最小值 if(root.left == null){ return root; } //遞歸訪問左子樹 return findMin(root.left); } /** * 找到最大值 * @return */ public int findMax(){ //判空 if(root == null){ throw new NoSuchElementException("root is empty! cannot find max"); } TreeNode maxNode = findMax(root); return maxNode.val; } private TreeNode findMax(TreeNode root) { //當(dāng)此節(jié)點(diǎn)右子樹為空,說明此節(jié)點(diǎn)是最大值 if(root.right == null){ return root; } //遞歸訪問右子樹 return findMax(root.right); } /** * 在當(dāng)前BST中刪除最小值節(jié)點(diǎn),返回刪除的最小值 * @return */ public int removeMin(){ int min =findMin(); root = removeMin(root); return min; } private TreeNode removeMin(TreeNode root) { if(root.left == null){ TreeNode right = root.right; //找到最小值,刪除節(jié)點(diǎn) root = root.left = null; size--; return right; } root.left = removeMin(root.left); return root; } /** * 在當(dāng)前BST中刪除最大值節(jié)點(diǎn),返回刪除的最大值 * @return */ public int removeMax(){ int max = findMax(); root = removeMax(root); return max; } //在當(dāng)前以root為根的BST中刪除最小值所在的節(jié)點(diǎn),返回刪除后的樹根 private TreeNode removeMax(TreeNode root) { if(root.right == null){ TreeNode right = root.right; //找到最大值,刪除節(jié)點(diǎn) root = root.right = null; size--; return right; } root.right = findMax(root.right); return root; } /** * 在當(dāng)前以root為根節(jié)點(diǎn)的BST中刪除值為val的節(jié)點(diǎn) * 返回刪除后的新的根節(jié)點(diǎn) * @return */ public void removeValue(int value){ root = removeValue(root,value); } private TreeNode removeValue(TreeNode root, int value) { if(root == null){ throw new NoSuchElementException("root is empty! cannot find remove"); }else if(value < root.val){ root.left = removeValue(root.left,value); return root; }else if(value > root.val){ root.right = removeValue(root.right,value); return root; }else { //此時(shí)value == root.value if(root.left == null){ //刪除最小數(shù) TreeNode right = root.right; root = root.right = null; size--; return right; } if(root.right == null){ //刪除最大數(shù) TreeNode left = root.left; root = root.left =null; size--; return left; } //找到當(dāng)前該刪除節(jié)點(diǎn)的前驅(qū)或者后繼節(jié)點(diǎn)作為刪除后的新節(jié)點(diǎn) //當(dāng)我們使用后繼節(jié)點(diǎn)時(shí),先連removeMin(root.right),在連root.left TreeNode successor = findMin(root.right); successor.right = removeMin(root.right); successor.left = root.left; return successor; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); generateBSTString(root,0,sb); return sb.toString(); } //直觀打印,可以看到樹的深度 private void generateBSTString(TreeNode root, int height, StringBuilder sb) { if(root == null){ sb.append(generateHeightString(height)).append("NULL\n"); return; } sb.append(generateHeightString(height)).append(root.val).append("\n"); generateBSTString(root.left,height+1,sb); generateBSTString(root.right,height+1,sb); } private String generateHeightString(int height) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < height; i++) { sb.append("--"); } return sb.toString(); } }
到此這篇關(guān)于Java實(shí)現(xiàn)二分搜索樹的示例代碼的文章就介紹到這了,更多相關(guān)Java二分搜索樹內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Thread多線程開發(fā)中Object類詳細(xì)講解
這篇文章主要介紹了Java Thread多線程開發(fā)中Object類,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2023-03-03Flowable數(shù)據(jù)庫表分類及數(shù)據(jù)字典解析
這篇文章主要介紹了Flowable數(shù)據(jù)庫表分類及數(shù)據(jù)字典解析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11Spring Boot多數(shù)據(jù)源及其事務(wù)管理配置方法
本篇文章主要介紹了Spring Boot多數(shù)據(jù)源及其事務(wù)管理配置方法,具有一定的參考價(jià)值,有興趣的可以了解一下。2017-04-04MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL的實(shí)現(xiàn)方法
這篇文章主要介紹了MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12SpringBoot+RabbitMq具體使用的幾種姿勢(shì)
這篇文章主要介紹了SpringBoot+RabbitMq具體使用的幾種姿勢(shì),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05Java中動(dòng)態(tài)地改變數(shù)組長(zhǎng)度及數(shù)組轉(zhuǎn)Map的代碼實(shí)例分享
這篇文章主要介紹了Java中動(dòng)態(tài)地改變數(shù)組長(zhǎng)度及數(shù)組轉(zhuǎn)map的代碼分享,其中轉(zhuǎn)Map利用到了java.util.Map接口,需要的朋友可以參考下2016-03-03