二叉排序树
基本介绍
二叉排序树:BST:(Binary Sort(Search) Tree),对于二叉排序树的任何一个非叶子节点,要求左子树的值比当前节点的值小,右子节点的值比当前节点的值大。
特别说明:如果有相同的值,可以将该节点放在左子节点或右子节点。
二叉排序树的创建和遍历
代码
//添加节点的方法
//递归的形式添加节点,注意需要满足二叉排序树的要求
public void add (Node node){
if(node==null){
return;
}
//判断传入节点的值和我们当前子树的跟节点值的关系
//待添加节点小于当前节点
if(node.value<this.value){
//当前节点左子节点为空
if(this.left==null){
this.left = node;
}else{
this.left.add(node);//递归的向左子树添加
}
}else{//添加节点的值大于当前节点的值
//右子节点为空
if(this.right==null){
this.right=node;
}else{
//递归的向右子树添加
this.right.add(node);
}
}
}
二叉排序树的删除
- 删除叶子节点 比如 (2,5,9,12)
- 删除只有一颗子树的节点 (1)
- 删除有两颗子树的节点 (7,3,10)
删除叶子节点
-
需要先去找到要删除的节点是存在的,targetNode
-
确定目标节点targetNode的父节点 parentNode(还需要考虑是否有父节点)
-
判断targetNode是parent的左子节点还是右子节点
-
根据前面的情况来对应的删除
4.1、如果是左子节点:parent.left = null
4.2、如果是右子节点:parent.right = null
删除只有一颗子树的节点
-
需要先去找到要删除的节点是存在的,targetNode
-
确定目标节点targetNode的父节点 parentNode(还需要考虑是否有父节点)
-
确定targetNode的子节点是左子节点还是右子节点
-
targetNode是parentNode的左子节点还是右子节点
-
根据前面的情况来对应的删除 ~~5.1、targetNode是parent的左子节点,targetNode的子节点是子节点; ==parent.left = targetNode.left==~
5.2、targetNode是parent的左子节点,targetNode的子节点是右节点 : parent.left = targetNode.right~~~5.3、targetNode是parent的右子节点,targetNode的子节点是右子节点; ==parent.right = targetNode.right==~~
5.4 如果targetNode有左子节点
5.1、如果targetNode是parentNode的左子节点:parentNode.left = taregetNode.left
5.2、如果targetNode是parentNode的右子节点:parentNode.right = taregetNode.left
如果targetNode有右子节点
5.3、如果targetNode是parentNode的左子节点:parentNode.left=taregetNode.right
5.4、如果targetNode是parentNode的右子节点:parentNode.right=taregetNode.right
删除有两颗子树的节点
-
需要先去找到要删除的节点是存在的,targetNode
-
确定目标节点targetNode的父节点 parentNode(还需要考虑是否有父节点)
-
从targetNode的右子树最小的节点
-
用临时变量,将最小节点的值保存temp
-
删除该最小节点
-
targetNode.value = temp
/**
* @param node 待传入的节点(当做一颗排序树的根节点)
* @return 以node为跟节点的二叉排序树最小节点的值
* //1、返回以node为跟节点的二叉排序树最小节点的值
* //2、删除 以node为跟节点的二叉排序树最小节点的值
* */
public int deleteRightMin(Node node){
Node temp= node;
//循环的查找左节点,直到找到最小值
while(temp.left!=null){
temp = temp.left;
}
//这时target就指向了最小的值
//删除最小节点
deleteNode(temp.value);
return temp.value;
}
//删除节点
public void deleteNode(int value){
if(this.root==null){
return;
}else{
//1、先根据需求查找要删除的节点 targetNode
Node targetNode = Search(value);
//如果没有找到要删除的节点
if(targetNode==null){
return;
}
//如果发现当前二叉排序树只有一个节点
if(root.left==null && root.right==null){
root = null;
}
//去查找targetNode的父节点
Node parent = searchParent(value);
//如果要删除的节点是叶子节点
if(targetNode.left==null&&targetNode.right==null){
//判断targetNode是parentNode的左子节点还是右子节点
if(parent.left!=null&&parent.left==targetNode){
parent.left=null;
}
if(parent.right!=null&&parent.right==targetNode){
parent.right=null;
}
//要删除的节点有两个子节点
}else if(targetNode.left!=null&&targetNode.right!=null){
//从右子树找最小的 取待待删除的节点
int minValue = deleteRightMin(targetNode.right);
targetNode.value = minValue;
}else{//要删除的节点有一个子节点
//要删除的节点有一个右子节点
if(targetNode.right!=null){
//要删除的节点是parent的左子节点
if( parent.left==targetNode){
parent.left = targetNode.right;
//要删除的节点是parent的右子节点
}else if( parent.right==targetNode){
parent.right=targetNode.right;
}
}else{//要删除的节点有一个左子节点
//要删除的节点是parent的左子节点
if(parent.left==targetNode){
parent.left = targetNode.left;
//要删除的节点是parent的右子节点
}else if(parent.right==targetNode){
parent.right=targetNode.left;
}
}
}
}
}
}
代码
package J树的提高.binarysortTree;
/**
* @Author Zhou jian
* @Date 2020 ${month} 2020/1/12 0012 20:46
*/
public class BinarySortTreeDemo {
public static void main(String[] args) {
int[] arr = {7,3,10,12,5,1,9,2};
BinarySortTree binarySortTree = new BinarySortTree();
//循环的添加节点到二叉排序树
for(int i =0;i<arr.length;i++){
binarySortTree.add(new Node(arr[i]));
}
//中序遍历 二叉排序树
System.out.println("中序遍历二叉排序与树");
binarySortTree.infixOrder(); //1 3 5 7 9 10 12
//测试删除叶子节点
// binarySortTree.deleteNode(9);
// System.out.println("删除节点后中序遍历二叉排序与树");
// binarySortTree.infixOrder(); //1 3 5 7 9 10 12
// //测试删除只有一个子节点的节点
// binarySortTree.deleteNode(1);
// System.out.println("删除只有一个节点的节点");
// binarySortTree.infixOrder(); //1 3 5 7 9 10 12
//删除有两个子树的节点
System.out.println("删除you2个节点的节点");
binarySortTree.deleteNode(7);
binarySortTree.infixOrder(); //1 3 5 7 9 10 12
}
}
//创建二叉排序树
class BinarySortTree{
//头结点
private Node root;
//添加节点的方法
public void add(Node node){
//如果root为空,则直接赋值root怪
if(root==null){
root = node;
}else{
root.add(node);
}
}
//中序遍历
public void infixOrder(){
if(root!=null){
root.infixOrder();
}else{
System.out.println("当前二叉排序树为空不能遍历");
}
}
//查找节点
public Node Search(int value){
if(root==null){
return null;
}else{
return root.Search(value);
}
}
//查找父节点
public Node searchParent(int value){
if(root==null){
return null;
}else{
return root.searchParent(value);
}
}
/**
* @param node 待传入的节点(当做一颗排序树的根节点)
* @return 以node为跟节点的二叉排序树最小节点的值
* //1、返回以node为跟节点的二叉排序树最小节点的值
* //2、删除 以node为跟节点的二叉排序树最小节点的值
* */
public int deleteRightMin(Node node){
Node temp= node;
//循环的查找左节点,直到找到最小值
while(temp.left!=null){
temp = temp.left;
}
//这时target就指向了最小的值
//删除最小节点
deleteNode(temp.value);
return temp.value;
}
//删除节点
public void deleteNode(int value){
if(this.root==null){
return;
}else{
//1、先根据需求查找要删除的节点 targetNode
Node targetNode = Search(value);
//如果没有找到要删除的节点
if(targetNode==null){
return;
}
//如果发现当前二叉排序树只有一个节点
if(root.left==null && root.right==null){
root = null;
}
//去查找targetNode的父节点
Node parent = searchParent(value);
//如果要删除的节点是叶子节点
if(targetNode.left==null&&targetNode.right==null){
//判断targetNode是parentNode的左子节点还是右子节点
if(parent.left!=null&&parent.left==targetNode){
parent.left=null;
}
if(parent.right!=null&&parent.right==targetNode){
parent.right=null;
}
//要删除的节点有两个子节点
}else if(targetNode.left!=null&&targetNode.right!=null){
//从右子树找最小的 取待待删除的节点
int minValue = deleteRightMin(targetNode.right);
targetNode.value = minValue;
}else{//要删除的节点有一个子节点
//要删除的节点有一个右子节点
if(targetNode.right!=null){
//要删除的节点是parent的左子节点
if( parent.left==targetNode){
parent.left = targetNode.right;
//要删除的节点是parent的右子节点
}else if( parent.right==targetNode){
parent.right=targetNode.right;
}
}else{//要删除的节点有一个左子节点
//要删除的节点是parent的左子节点
if(parent.left==targetNode){
parent.left = targetNode.left;
//要删除的节点是parent的右子节点
}else if(parent.right==targetNode){
parent.right=targetNode.left;
}
}
}
}
}
}
//创建Node节点
class Node{
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node{" +
"value=" + value +
'}';
}
//添加节点的方法
//递归的形式添加节点,注意需要满足二叉排序树的要求
public void add (Node node){
if(node==null){
return;
}
//判断传入节点的值和我们当前子树的跟节点值的关系
//待添加节点小于当前节点
if(node.value<this.value){
//当前节点左子节点为空
if(this.left==null){
this.left = node;
}else{
this.left.add(node);//递归的向左子树添加
}
}else{//添加节点的值大于当前节点的值
//右子节点为空
if(this.right==null){
this.right=node;
}else{
//递归的向右子树添加
this.right.add(node);
}
}
}
//中序遍历
public void infixOrder(){
if(this.left!=null){
this.left.infixOrder();
}
System.out.println(this);
if(this.right!=null){
this.right.infixOrder();
}
}
//查找要删除的节点
/**
* @param value 希望删除节点的值
*/
public Node Search(int value){
if(value==this.value){//找到就是该节点
return this;
}else if(value<this.value){ //如果查找的值小于当前节点。向左子树递归查找
//如果左子节点为空,就不再找
if(this.left==null){
return null;
}
return this.left.Search(value);
}else{
if(this.right==null){
return null;
}
return this.right.Search(value);
}
}
//查找要删除节点的父亲节点
/**
*
* @param value
* @return 返回的是要删除节点的父节点
*/
public Node searchParent(int value){
//如果当前节点就是要删除节点的父节点就返回
if(((this.left!=null) &(this.left.value==value))||((this.right!=null) &(this.right.value==value))){
return this;
}else {
//如果查找的值小于当前节点的值并且当前节点的左子节点不为空
//递归向左子节点删除
if((this.left!=null)&&(value<this.value)){
return this.left.searchParent(value);
} else if((this.right!=null)&&(value>this.value)){//向右子树递归查找
return this.right.searchParent(value);
}else{
return null;//没有找到父节点
}
}
}
}