Java二叉樹(shù)查詢(xún)?cè)砩钊敕治鲋v解
二叉查詢(xún)樹(shù)

概述
二叉樹(shù)(Binary tree)是樹(shù)形結(jié)構(gòu)的一個(gè)重要類(lèi)型。許多實(shí)際問(wèn)題抽象出來(lái)的數(shù)據(jù)結(jié)構(gòu)往往是二叉樹(shù)形式,即使是一般的樹(shù)也能簡(jiǎn)單地轉(zhuǎn)換為二叉樹(shù),而且二叉樹(shù)的存儲(chǔ)結(jié)構(gòu)及其算法都較為簡(jiǎn)單,因此二叉樹(shù)顯得特別重要。二叉樹(shù)特點(diǎn)是每個(gè)節(jié)點(diǎn)最多只能有兩棵子樹(shù),且有左右之分
特點(diǎn)
樹(shù)同時(shí)具有數(shù)組查詢(xún)的效率、鏈表增刪、改的性能
右子樹(shù)的結(jié)點(diǎn)比左子樹(shù)的節(jié)點(diǎn)大
查找法
搜索的數(shù)字如果比節(jié)點(diǎn)大則往右搜索,搜索的數(shù)字如果比節(jié)點(diǎn)小則往左搜索
結(jié)點(diǎn)實(shí)現(xiàn)原理
插入實(shí)現(xiàn)原理

int[] arrs = {5,2,1,4,3,9,7,6,8};如果樹(shù)是空樹(shù),插入節(jié)點(diǎn)就直接放入到根結(jié)點(diǎn)
如果樹(shù)不是空樹(shù),則插入的數(shù)字于根結(jié)點(diǎn)的數(shù)字進(jìn)行比較
如果插入的值小于于結(jié)點(diǎn)的數(shù)字,則往左子樹(shù)插入
- 如果左子結(jié)點(diǎn)沒(méi)有元素就插入到左子結(jié)點(diǎn)中
- 如果左子結(jié)點(diǎn)有元素,就可以設(shè)計(jì)一個(gè)引用(游標(biāo))指向左子節(jié)點(diǎn),并且再次和待插入的執(zhí)行左子結(jié)點(diǎn)進(jìn)行比較,直到找到插入的位置
如果插入的值大于結(jié)點(diǎn)的數(shù)字,則往右子樹(shù)插入
- 判斷右子結(jié)點(diǎn)是否存在值,如果不存在則直接插入
- 判斷右子結(jié)點(diǎn)是否存在值,如果存在則通過(guò)一個(gè)引用指向右子結(jié)點(diǎn)繼續(xù)和待插入的值進(jìn)行比較,直到找到插入的位置
總結(jié):
- 小往左,大往右
- 左子數(shù)永遠(yuǎn)小于右子樹(shù)
遍歷實(shí)現(xiàn)原理

中序遍歷:左—根—右
通過(guò)中序遍歷就可以將二叉樹(shù)查找樹(shù)的進(jìn)行順序輸出
總結(jié):
始終貫徹左—根—右的原則、由內(nèi)層向外層拆分
int[] arrs = {1,2,3,4,5,6,7,8,9};刪除實(shí)現(xiàn)原理
提供一個(gè)待刪除的結(jié)點(diǎn)的值,根據(jù)值從二叉查找樹(shù)找到需要?jiǎng)h除的結(jié)點(diǎn)
找到待刪除結(jié)點(diǎn)的父類(lèi)結(jié)點(diǎn),并且要根據(jù)待刪除結(jié)點(diǎn)在父類(lèi)結(jié)點(diǎn)的左右子樹(shù)的位置,設(shè)置為null進(jìn)行刪除
需要考慮結(jié)點(diǎn)的三種情況
情況1:待刪除的結(jié)點(diǎn)沒(méi)有子結(jié)點(diǎn)
直接讓父類(lèi)結(jié)點(diǎn)的對(duì)應(yīng)目標(biāo)結(jié)點(diǎn)引用設(shè)置為null即可
情況2:待刪除的結(jié)點(diǎn)有一個(gè)子節(jié)點(diǎn)
將待刪除的父類(lèi)結(jié)點(diǎn)對(duì)應(yīng)子節(jié)點(diǎn)的引用指向待刪除結(jié)點(diǎn)的子節(jié)點(diǎn)
情況3:待刪除的結(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn) 從左子樹(shù)中找到最大的結(jié)點(diǎn)進(jìn)行刪除,并且將最大的結(jié)點(diǎn)的值放入到待刪除結(jié)點(diǎn)從右子樹(shù)中找到最小的結(jié)點(diǎn)進(jìn)行刪除,并且將最小的結(jié)點(diǎn)的值放入(替換)到待刪除結(jié)點(diǎn)
(上述兩種刪除方法:需要將待刪除結(jié)點(diǎn)指向新創(chuàng)建(替換后的)的結(jié)點(diǎn),并且將新的結(jié)點(diǎn)(替換后的)的左右結(jié)點(diǎn)指向待刪除的左右子樹(shù)的結(jié)點(diǎn))
刪除的結(jié)點(diǎn)是根節(jié)點(diǎn)的情況
情況1:根節(jié)點(diǎn)沒(méi)有子節(jié)點(diǎn),直接將根結(jié)點(diǎn)指向null
情況2:根結(jié)點(diǎn)有一個(gè)子節(jié)點(diǎn),則根結(jié)點(diǎn)直接指向子節(jié)點(diǎn)
情況3:根結(jié)點(diǎn)有兩個(gè)子節(jié)點(diǎn)
可以從左子樹(shù)中找到最大值刪除結(jié)點(diǎn),然后將最大值覆蓋(替換)根節(jié)點(diǎn)
可以從右子樹(shù)中找到最小值刪除結(jié)點(diǎn),然后將最小值覆蓋(替換)根節(jié)點(diǎn)
結(jié)點(diǎn)插入與遍歷案例
BinarySearchTree類(lèi)
package Algorithm;
public class BinarySearchTree {
Node root; //定義根節(jié)點(diǎn)
//結(jié)點(diǎn)插入方法
public void insert(int value) {
if (root == null) { //1.如果樹(shù)是空樹(shù),插入節(jié)點(diǎn)就直接放入到根結(jié)點(diǎn)
root = new Node(value);
} else { //如果樹(shù)不是空樹(shù),則插入的數(shù)字于根結(jié)點(diǎn)的數(shù)字進(jìn)行比較
//2.如果插入的值小于于結(jié)點(diǎn)的數(shù)字,則往左子樹(shù)插入
Node node = root; //聲明一個(gè)游標(biāo)結(jié)點(diǎn),開(kāi)始指向根節(jié)點(diǎn)
while (true) { //并且再次和待插入的執(zhí)行左子結(jié)點(diǎn)進(jìn)行比較,直到找到插入的位置
if (value < node.value) { //如果插入的值小于于結(jié)點(diǎn)的數(shù)字,則往左子樹(shù)插入
//2.1如果左子結(jié)點(diǎn)沒(méi)有元素就插入到左子結(jié)點(diǎn)中
if (node.left == null) {
node.left = new Node(value);
break; //如果找到插入的位置,則跳出while循環(huán)
} else { //如果左子結(jié)點(diǎn)有元素,就可以設(shè)計(jì)一個(gè)引用(游標(biāo))指向左子節(jié)點(diǎn),并且再次和待插入的執(zhí)行左子結(jié)點(diǎn)進(jìn)行比較,直到找到插入的位置
//游標(biāo)指向左子節(jié)點(diǎn)
node = node.left;
}
} else { //如果插入的值大于結(jié)點(diǎn)的數(shù)字,則往右子樹(shù)插入
//判斷右子結(jié)點(diǎn)是否存在值,如果不存在則直接插入
if (node.right == null) {
node.right = new Node(value);
break;
} else { //判斷右子結(jié)點(diǎn)是否存在值,如果存在則通過(guò)一個(gè)引用指向右子結(jié)點(diǎn)繼續(xù)和待插入的值進(jìn)行比較,直到找到插入的位置
//游標(biāo)指向右子節(jié)點(diǎn)
node = node.right;
}
}
}
}
}
//定義左右結(jié)點(diǎn)常量
public static final int LEFT = 0; //左子節(jié)點(diǎn)
public static final int RIGHT = 1; //右子節(jié)點(diǎn)
//結(jié)點(diǎn)查找方法
public void deleteNode(int value) {
//定義游標(biāo)從根節(jié)點(diǎn)開(kāi)始查詢(xún)
Node node = root;
//定義目標(biāo)結(jié)點(diǎn)
Node target = null;
//定義目標(biāo)結(jié)點(diǎn)的父類(lèi)結(jié)點(diǎn)
Node parent = null;
//目標(biāo)結(jié)點(diǎn)的類(lèi)型為,左子節(jié)點(diǎn)或者右子節(jié)點(diǎn)
int nodeType = 0; //0代表左子節(jié)點(diǎn) 1代表右子節(jié)點(diǎn)
while (node != null) { //游標(biāo)不為空,如果為空則沒(méi)有子節(jié)點(diǎn),無(wú)法刪除
if (node.value == value) { //如果目標(biāo)結(jié)點(diǎn)的值和需要?jiǎng)h除結(jié)點(diǎn)的值相同
//找到結(jié)點(diǎn)
target = node;
break;
} else if (value < node.value) { //如果值不同,則判斷目標(biāo)結(jié)點(diǎn)值是否小于node結(jié)點(diǎn)
//保存父類(lèi)結(jié)點(diǎn)
parent = node;
//游標(biāo)指向左子節(jié)點(diǎn)
node = node.left;
nodeType = LEFT;
} else { //如果值不同,且目標(biāo)結(jié)點(diǎn)值大于node結(jié)點(diǎn)
//保存父類(lèi)結(jié)點(diǎn)
parent = node;
//游標(biāo)指向右子節(jié)點(diǎn)
node = node.right;
nodeType = RIGHT;
}
}
//如果沒(méi)找到需要?jiǎng)h除的目標(biāo)結(jié)點(diǎn)
if (target==null){
System.out.println("沒(méi)有找到要?jiǎng)h除的結(jié)點(diǎn)");
return;
}
//刪除結(jié)點(diǎn)的三種情況
if (target.left == null && target.right == null) { //情況1:待刪除的結(jié)點(diǎn)沒(méi)有子結(jié)點(diǎn)
if (parent==null){ //刪除的結(jié)點(diǎn)沒(méi)有子結(jié)點(diǎn)
//將root設(shè)置為null即可
root=null;
return;
}
//判斷目標(biāo)的結(jié)點(diǎn)是左子節(jié)點(diǎn)還是右子節(jié)點(diǎn)
if (nodeType == LEFT) {
//將父類(lèi)的左子節(jié)點(diǎn)設(shè)置為null
parent.left = null;
} else {
//將父類(lèi)的右子節(jié)點(diǎn)設(shè)置為null
parent.right = null;
}
} else if (target.left != null && target.right != null) { //情況2:待刪除的結(jié)點(diǎn)有2個(gè)子節(jié)點(diǎn)
//兩個(gè)子節(jié)點(diǎn),從target右子樹(shù)查找最小的值
Node min=target.right;
//遍歷左子樹(shù)
while (min.left!=null){
min = min.left;
}
//將最小的結(jié)點(diǎn)進(jìn)行刪除
deleteNode(min.value);
//將待刪除的結(jié)點(diǎn)替換成最小的結(jié)點(diǎn)的值
target.value= min.value;
}else { //情況3:待刪除的結(jié)點(diǎn)有1個(gè)子節(jié)點(diǎn)
//刪除結(jié)點(diǎn)是根節(jié)點(diǎn)
if (parent==null){
if (target.left!=null){ //判斷是左子節(jié)點(diǎn)還是右子節(jié)點(diǎn)有值
root=target.left; //根節(jié)點(diǎn)=目標(biāo)左子結(jié)點(diǎn)
}else {
root=target.right; //根節(jié)點(diǎn)=目標(biāo)右子結(jié)點(diǎn)
}
}
//只有一個(gè)子節(jié)點(diǎn)
if (nodeType==LEFT){ //如果是左子節(jié)點(diǎn)
if (target.left!=null){
//將父類(lèi)的左子節(jié)點(diǎn),指向待刪除結(jié)點(diǎn)的左子節(jié)點(diǎn)
parent.left=target.left;
}else { //如果是右子節(jié)點(diǎn)
//將父類(lèi)的左子節(jié)點(diǎn),指向待刪除結(jié)點(diǎn)的右子節(jié)點(diǎn)
parent.left=target.right;
}
}else {
if (target.right!=null){
//將父類(lèi)的右子節(jié)點(diǎn),指向待刪除結(jié)點(diǎn)的左子節(jié)點(diǎn)
parent.right=target.left;
}else { //如果是右子節(jié)點(diǎn)
//將父類(lèi)的右子節(jié)點(diǎn),指向待刪除結(jié)點(diǎn)的右子節(jié)點(diǎn)
parent.right=target.right;
}
}
}
}
//實(shí)現(xiàn)中序遍歷
public void midTraversal(Node node) {
if (node == null) { //進(jìn)行判斷結(jié)點(diǎn)不能為空,如果為空則退出
return;
} else { //如果結(jié)點(diǎn)不為null,則執(zhí)行下列遍歷語(yǔ)句
//首先,遍歷左節(jié)點(diǎn)
midTraversal(node.left);
//打印根節(jié)點(diǎn)
System.out.print(node.value + ",");
//最后遍歷右子結(jié)點(diǎn)
midTraversal(node.right);
}
}
//創(chuàng)建一個(gè)結(jié)點(diǎn)類(lèi)
public static class Node {
int value; //存儲(chǔ)值
Node left; //左子樹(shù)
Node right; //右子樹(shù)
// 帶參構(gòu)造方法,傳入value賦值
public Node(int value) {
this.value = value;
}
}
}TestBST測(cè)試類(lèi)
package Algorithm;
public class TestBST {
public static void main(String[] args) {
int[] arrs = {5, 2, 1, 4, 3, 9, 7, 6, 8};
//創(chuàng)建二叉查詢(xún)樹(shù)
BinarySearchTree tree = new BinarySearchTree();
//將數(shù)組中的元素構(gòu)造成二叉查詢(xún)樹(shù)
for (int i = 0; i < arrs.length; i++) {
tree.insert(arrs[i]);
}
//刪除結(jié)點(diǎn)
tree.deleteNode(20);
//中序遍歷根結(jié)點(diǎn)
tree.midTraversal(tree.root);
}
}到此這篇關(guān)于Java二叉樹(shù)查詢(xún)?cè)砩钊敕治鲋v解的文章就介紹到這了,更多相關(guān)Java二叉樹(shù)查詢(xún)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java8新特性之空指針異常的克星Optional類(lèi)的實(shí)現(xiàn)
這篇文章主要介紹了Java8新特性之空指針異常的克星Optional類(lèi)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Java中instanceof關(guān)鍵字的用法總結(jié)
instanceof是Java的一個(gè)二元操作符,和==,>,<是同一類(lèi)東東。由于它是由字母組成的,所以也是Java的保留關(guān)鍵字。它的作用是測(cè)試它左邊的對(duì)象是否是它右邊的類(lèi)的實(shí)例,返回boolean類(lèi)型的數(shù)據(jù)2013-10-10
Springboot使用@Cacheable注解實(shí)現(xiàn)數(shù)據(jù)緩存
本文介紹如何在Springboot中通過(guò)@Cacheable注解實(shí)現(xiàn)數(shù)據(jù)緩存,在每次調(diào)用添加了@Cacheable注解的方法時(shí),Spring 會(huì)檢查指定參數(shù)的指定目標(biāo)方法是否已經(jīng)被調(diào)用過(guò),文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-10-10
解決spring boot 1.5.4 配置多數(shù)據(jù)源的問(wèn)題
下面小編就為大家?guī)?lái)一篇解決spring boot 1.5.4 配置多數(shù)據(jù)源的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06
Intellij Idea插件開(kāi)發(fā)之創(chuàng)建項(xiàng)目層級(jí)的右鍵菜單
這篇文章主要介紹了Intellij Idea插件開(kāi)發(fā)之創(chuàng)建項(xiàng)目層級(jí)的右鍵菜單,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
用Java產(chǎn)生100個(gè)1-150間不重復(fù)數(shù)字
這篇文章主要介紹了用Java產(chǎn)生100個(gè)1-150間不重復(fù)數(shù)字,需要的朋友可以參考下2017-02-02
Java中的Semaphore信號(hào)量使用方法代碼實(shí)例
這篇文章主要介紹了Java中的Semaphore信號(hào)量使用方法代碼實(shí)例,Semaphore是一種基于計(jì)數(shù)的信號(hào)量,它可以設(shè)定一個(gè)閾值,基于此,多個(gè)線(xiàn)程競(jìng)爭(zhēng)獲取許可信號(hào),做自己的申請(qǐng)后歸還,超過(guò)閾值后,線(xiàn)程申請(qǐng)?jiān)S可信號(hào)將會(huì)被阻塞,需要的朋友可以參考下2023-11-11
Spring Boot定制type Formatters實(shí)例詳解
在本篇文章里小編給大家整理的是關(guān)于Spring Boot定制type Formatters實(shí)例知識(shí)點(diǎn),需要的朋友們學(xué)習(xí)下。2019-11-11
java使用Socket實(shí)現(xiàn)文件上傳功能
這篇文章主要為大家詳細(xì)介紹了java使用Socket實(shí)現(xiàn)文件上傳功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02

