Java 实现二叉搜索树的创建、查找、插入、删除结点

本文介绍了如何使用Java实现二叉搜索树的基本操作,包括创建结点、查找、插入和删除。删除结点时,针对结点的左右子结点为空、左子结点为空、右子结点为空以及左右子结点均不为空的四种情况进行了详细讨论,涉及到根结点、父结点的孩子结点等不同场景的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

二叉搜索树特点:左孩子结点值比当前结点值小,右孩子结点值比当前值大或等于当前值。
本文假设树中的结点值不存在相同的两项或多项。

一、二叉搜索树的创建

 1、首先定义结点类

    代码如下:

class TreeNode{
	public int iData;          //结点的数据项
	public TreeNode leftChild; //结点指向左孩子的引用
	public TreeNode rightChild;//结点指向右孩子的引用
	
	public TreeNode(int iData){//构造方法,初始化结点数据项
		this.iData = iData;
	}
	public void displayNode(){ //输出结点值
		System.out.print(" "+this.iData);
	}
}
2、定义二叉搜索树类

代码如下:

public class BinarySearchTree {//二叉搜索树特点:左孩子结点值比当前结点值小,右孩子结点值比当前值大或等于当前值;
	public TreeNode root;  //定义树的根结点
	
	public BinarySearchTree(int iData){//构造方法用以初始化根结点值;
		root = new TreeNode(iData);
	}
	public TreeNode find(int iData){}         //查找指定结点方法
	public TreeNode getParentNode(int iData){}//获取当前值结点的父结点方法
	public TreeNode findMin(TreeNode root){}  //查找树的最小值结点
	public TreeNode findMax(TreeNode root){}  //查找树的最大值结点
	public TreeNode findInorderSuccessor(TreeNode node){}//查找当前结点的-右子树的-后继中序结点[即当前结点的右子树按照中序遍历获取的第一个结点]
	public void deleteNode(int key){}                    //删除指定值的结点
	public void insert(int iData){}                      //插入指定值的结点
	public void inOrder(TreeNode node){}                 //中序遍历二叉搜索树的递归实现;
	public void preOrder(TreeNode node){}                //先序遍历二叉搜索树的递归实现;
	public void postOrder(TreeNode node){}               //后序遍历二叉搜索树的递归实现;
}
3、实现insert方法进行树的创建

	public void insert(int iData){
		TreeNode node = new TreeNode(iData);
		TreeNode current ;
		if(root == null){
			root = node;
			return;
		}
		else{
			current = root;
			while(true){
				if(iData >= current.iData){
					if(current.rightChild == null){
						current.rightChild = node;
						return;/找到插入位置就插入,并且返回不再执行
					}else{
						current = current.rightChild;
					}
				}else{
					if(current.leftChild == null){
						current.leftChild = node;
						return;找到插入位置就插入,并且返回不再执行
					}else{
						current = current.leftChild;
					}
				}// end if
			}// end while
		}// end root is not null
	}
二、删除树中的指定结点

删除结点操作是最复杂的,总体上分为四种情况:1.该结点的左右子结点均为空;2.该结点的左子结点不为空,右子结点为空;3.该结点的右子结点不为空,左子结点为空;4.该结点的左右子结点均不为空。下面分别对上述情况进行讨论。

1.该结点的左右子结点均为空;

这种情况细分,又分为3种情况:A:该结点的父结点为空,说明该结点为根结点,这种情况直接将根结点置空即可。B:该结点是父结点的左孩子结点。C:该结点是父结点的右孩子结点。

代码实现:

	if(keyNode.leftChild == null && keyNode.rightChild == null){//若该结点是叶子结点
		if(parent == null){//若该结点是根结点
			this.root = null;
			return;
		}
		if(parent.leftChild == keyNode){
			parent.leftChild = null;
		}else{
			parent.rightChild = null;
		}
		return;
	}
2.该结点的左子结点不为空,右子结点为空;

这种情况也比较简单,只需要同上,类似地判定该结点是其父结点的左子结点还是右子结点进行处理即可。

else if(keyNode.rightChild == null ){   //若该结点的左子树不空
	if(parent.leftChild == keyNode){
		parent.leftChild = keyNode.leftChild;
	}else{
	        parent.rightChild = keyNode.leftChild;
	}
	return;
}
3.该结点的右子结点不为空,左子结点为空;

类似地,同上:

else if(keyNode.leftChild == null ){  //若该结点的右子树不空
	if(parent.leftChild == keyNode){
		parent.leftChild = keyNode.rightChild;
	}else{
		parent.rightChild = keyNode.rightChild;
	}
	return;
 }
4.该结点的左右子结点均不为空。

这种情况最为复杂,又细分为两种情况:A、该结点右子树中的中序后继结点是该结点的右子结点;B、该结点的右子树中的中序后继结点是该结点的右子树的左孙子结点。所谓中序后继结点:

即当前结点的右子树按照中序遍历获取的第一个结点。也就是第一个比该结点大的结点,我们用这个结点来代替被删除的结点,以保证对指定结点删除后树的有序性。
A种情况:

	if(inorderSuccessor == keyNode.rightChild){            //若该结点右子树中的中序后继结点是该结点的右子结点;
		inorderSuccessor.leftChild = keyNode.leftChild;//将后继结点的左孩子指向被删除结点的左孩子结点;
		if(parent.leftChild == keyNode){               //判断被删除结点是其父结点的左孩子还是右孩子;
			parent.leftChild = inorderSuccessor;   //将父结点的左孩子指向后继结点
		}else{
			parent.rightChild = inorderSuccessor;
		}
	}
B种情况,分四步:
	if(parent.leftChild == keyNode){
		parentSuccessor.leftChild = inorderSuccessor.rightChild;//将后继结点的父结点的左孩子结点指向后继结点的右孩子结点;
		inorderSuccessor.rightChild = keyNode.rightChild;       //将后继结点的右孩子结点指向被删除结点的右孩子结点
		parent.leftChild = inorderSuccessor;                    //将被删除结点的父结点的左孩子结点指向后继结点
		inorderSuccessor.leftChild = keyNode.leftChild;         //将后继结点的左孩子结点指向被删除结点的左孩子结点
	}else{
		parentSuccessor.leftChild = inorderSuccessor.rightChild;
		inorderSuccessor.rightChild = keyNode.rightChild;
		parent.rightChild = inorderSuccessor;
		inorderSuccessor.leftChild = keyNode.leftChild;
	}
以上是对二叉搜索树的简单操作介绍,下面是完整代码和运行结果:

package test2;
class TreeNode{
	public int iData;
	public TreeNode leftChild;
	public TreeNode rightChild;
	
	public TreeNode(int iData){
		this.iData = iData;
	}
	public void displayNode(){
		System.out.print(" "+this.iData);
	}
}
public class BinarySearchTree {//二叉搜索树:左孩子结点值比当前结点值小,右孩子结点值比当前值大或等于当前值;
	public TreeNode root;
	
	public BinarySearchTree(int iData){
		root = new TreeNode(iData);
	}
	public TreeNode find(int iData){
		TreeNode current;
		current = root;
		while(current != null){
			if(iData < current.iData){
				current = current.leftChild;
			}else if(iData > current.iData){
				current = current.rightChild;
			}else{
				return current;
			}
		}
		return null;
	}
	public TreeNode getParentNode(int iData){
		TreeNode current;
		current = root;
		TreeNode parent = root;
		while(current != null){
			if(iData < current.iData){
				parent = current;
				current = current.leftChild;
			}else if(iData > current.iData){
				parent = current;
				current = current.rightChild;
			}else{
				if(current == root){
					return null;
				}
				else
					return parent;
			}
		}
		return null;
	}
	public TreeNode findMin(TreeNode root){
		TreeNode  node;
		node = root;
		while(node != null){
			if(node.leftChild != null){
				node = node.leftChild;
			}else{
				System.out.println("min:"+node.iData);
				return node;
			}
		}
		System.out.println("tree is null");
		return null;
	}
	public TreeNode findMax(TreeNode root){
		TreeNode  node;
		node = root;
		while(node != null){
			if(node.rightChild != null){
				node = node.rightChild;
			}else{
				System.out.println("max:"+node.iData);
				return node;
			}
		}
		System.out.println("tree is null");
		return null;
	}
	public TreeNode findInorderSuccessor(TreeNode node){
		TreeNode current = node.rightChild;
		while(current != null){
			if(current.leftChild != null){
				current = current.leftChild;
			}else
				return current;
		}
		return current;
	}
	public void deleteNode(int key){
		TreeNode keyNode = find(key);
		TreeNode parent = getParentNode(key);
		if(keyNode != null){//如果找到了要删除的结点
			if(keyNode.leftChild == null && keyNode.rightChild == null){//若该结点是叶子结点
				if(parent == null){//若该结点是根结点
					this.root = null;
					return;
				}
				if(parent.leftChild == keyNode){
					parent.leftChild = null;
				}else{
					parent.rightChild = null;
				}
				return;
			}else if(keyNode.rightChild == null ){   //若该结点的左子树不空
				if(parent.leftChild == keyNode){
					parent.leftChild = keyNode.leftChild;
				}else{
					parent.rightChild = keyNode.leftChild;
				}
				return;
			}else if(keyNode.leftChild == null ){  //若该结点的右子树不空
				if(parent.leftChild == keyNode){
					parent.leftChild = keyNode.rightChild;
				}else{
					parent.rightChild = keyNode.rightChild;
				}
				return;
			}else{				//若该结点的左右子结点都不空:1、该结点右子树中的中序后继结点是该结点的右子结点;2、该结点的右子树中的中序后继结点是该结点的右子树的左孙子结点;
				TreeNode inorderSuccessor = findInorderSuccessor(keyNode);
				TreeNode parentSuccessor = getParentNode(inorderSuccessor.iData);
				if(inorderSuccessor == keyNode.rightChild){//若该结点右子树中的中序后继结点是该结点的右子结点;
					inorderSuccessor.leftChild = keyNode.leftChild;
					if(parent.leftChild == keyNode){
						parent.leftChild = inorderSuccessor;
					}else{
						parent.rightChild = inorderSuccessor;
					}
				}else{										//若该结点的右子树中的中序后继结点是该结点的右子树的左孙子结点;
					if(parent.leftChild == keyNode){
						parentSuccessor.leftChild = inorderSuccessor.rightChild;
						inorderSuccessor.rightChild = keyNode.rightChild;
						parent.leftChild = inorderSuccessor;
						inorderSuccessor.leftChild = keyNode.leftChild;
						//parent.leftChild = inorderSuccessor;
					}else{
						//parent.rightChild = inorderSuccessor;
						parentSuccessor.leftChild = inorderSuccessor.rightChild;
						inorderSuccessor.rightChild = keyNode.rightChild;
						parent.rightChild = inorderSuccessor;
						inorderSuccessor.leftChild = keyNode.leftChild;
					}
				}// end else
			}//end else:both is not null
		}//end if find keyNode
	}//end method
	public void insert(int iData){
		TreeNode node = new TreeNode(iData);
		TreeNode current ;
		if(root == null){
			root = node;
			return;
		}
		else{
			current = root;
			while(true){
				if(iData >= current.iData){
					if(current.rightChild == null){
						current.rightChild = node;
						return;/
					}else{
						current = current.rightChild;
					}
				}else{
					if(current.leftChild == null){
						current.leftChild = node;
						return;
					}else{
						current = current.leftChild;
					}
				}// end if
			}// end while
		}// end root is not null
	}
	public void inOrder(TreeNode node){//中序遍历二叉搜索树的递归实现;
		if(node != null){
			inOrder(node.leftChild);
			System.out.print(" "+node.iData);
			inOrder(node.rightChild);
		}
	}
	public void preOrder(TreeNode node){
		if(node != null){
			System.out.print(" "+node.iData);
			preOrder(node.leftChild);
			preOrder(node.rightChild);
		}
	}
	public void postOrder(TreeNode node){
		if(node != null){
			postOrder(node.leftChild);
			postOrder(node.rightChild);
			System.out.print(" "+node.iData);
		}
	}

}

class theTreeApp{
	public static void main(String args[]){
		BinarySearchTree tree = new BinarySearchTree(-1);
		tree.insert(-2);
		tree.insert(1);
		tree.insert(0);
		tree.insert(4);
		tree.insert(2);
		tree.insert(5);
		tree.insert(3);
		
		tree.preOrder(tree.root);
		System.out.print("\n");
		
		tree.inOrder(tree.root);
		System.out.print("\n");
		
		tree.postOrder(tree.root);
		System.out.print("\n");
		
		tree.findMin(tree.root);
		tree.findMax(tree.root);
		
		tree.deleteNode(1);
		
		tree.preOrder(tree.root);
		System.out.print("\n");
		
		tree.inOrder(tree.root);
		System.out.print("\n");
	}
}
运行结果:

-1 -2 1 0 4 2 3 5
-2 -1 0 1 2 3 4 5
-2 0 3 2 5 4 1 -1
min:-2
max:5
-1 -2 2 0 4 3 5
-2 -1 0 2 3 4 5



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值