二叉搜索树特点:左孩子结点值比当前结点值小,右孩子结点值比当前值大或等于当前值。
本文假设树中的结点值不存在相同的两项或多项。
一、二叉搜索树的创建
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