彻底理清二叉排序树的插入、查找、删除

二叉排序树的概述

  二叉排序树也被成为二叉查找树或者二叉搜索树。它或者是一棵空的二叉树。它具备以下性质。

  若它的左子树不空,则左子树上所有结点的值均小于根结点的值。

  若它的右子树不空,则右子树上所有结点的值均大于根结点的值。

  它的左右子树也都是二叉排序树。

简述二叉排序树原理与实现

  二叉排序树的建立根基是二叉链表。

//二叉树节点
public class BinaryTreeNode {
    public  int data;
    public BinaryTreeNode left;
    public BinaryTreeNode right;
}

  假设有这样一组数据{11,2,5,7,3,9,4,66,55},那么它将构造这样一棵树结构。

  

  如何对搜索二叉树插入节点,从而构建一颗二叉树?

  根据二叉树的定义,向二叉排序树中插入节点s的过程,用伪代码描述:

    若root是空树,则将节点s作为根结点输入;

    否则,若s.data<root.data,则把节点s插入在root的左子树中;

    否则把结点s插入到root的右子树中;

  //构建搜索二叉树
    public  BinaryTreeNode build(int [] array){
        BinaryTreeNode root =new BinaryTreeNode(array[0]);  
        for( int i = 1 ; i < array.length ; i ++){  
            insertBST(root, array[i]);    
        }
        return root;
    }
    public BinaryTreeNode insertBST(BinaryTreeNode node,int data){
        if(node == null){  
            node = new BinaryTreeNode(data);  
            return node;  
        }else{  
            if(data <= node.data)  
                node.left =  insertBST(node.left, data);  
            else 
                node.right = insertBST(node.right,data);  
            return node;  
        }  
    }

  查找二叉树的指定值。

    若root是空树,则查找失败。

    若k=root.data,则查找成功。

    若k<root.data,则查找二叉树的左子树。

    若k>root.data,则查找二叉树的右子树。

//查找元素
    public BinaryTreeNode serachBST(BinaryTreeNode root,int target){
        if(null==root)
            return null;
        else if(root.getData()==target)
            return root;
        else if(root.getData()>target)
            return serachBST(root.getLeft(), target);
        else
            return serachBST(root.getRight(), target);
    }

  删除二叉树的指定值。删除元素其实并不难,重点是删除要元素以后依然要保持二叉搜索树,不能让它头脚分离变成森林。

  假设要删除结点为p(2),节点分为三种类型,p是叶子节点,p只有一个孩子,p有两个孩子。

  情况一:假设p是叶子节点,只需要把p设为null即可。

  情况二:假设p有一个孩子。假设它有左孩子,那么把p节点等于左孩子;假设它有右孩子,那么把p节点等于右孩子。

   情况三:假设p有两个孩子。

        查找p节点右子树的最左子树节点,也就是p节点的右子树的最小结点s,以及s的双亲节点par;

        将s的数据域替换被删除结点p的数据域;

        若节点p的右孩子无子树,则将s的右子树接到par的右子树上;否则,将s的右子树接到par的左字数上;

  图例原始图

  

  图例情况一:假设删除结点p为9,无孩子节点。

  

  图例情况二:假设删除节点p为3,有右孩子节点。

  

  图例情况三:假设删除节点p为5,有左右孩子。

  

    public BinaryTreeNode deleteBST(BinaryTreeNode root,int key){
        if(root==null){
            return null;
        }
        if(root.data==key){
            return deleteNode(root);
        }else if(root.data<key){
            root.right=deleteBST(root.right, key);
        }else{
            root.left=deleteBST(root.left, key);
        }
        return root;
    }

//删除元素
public BinaryTreeNode deleteNode(BinaryTreeNode p){
if(nullp.left&&nullp.right){
p
=null;//无孩子节点
}else if(p.leftnull){
p
=p.right;//只有右孩子
}else if(p.right
null){
p
=p.left;//只有左孩子
}else{
BinaryTreeNode par
=p;
BinaryTreeNode s
=p.right;
while(s.left!=null){
par
=s;
s
=s.left;
}
p.data
=s.data;
if(par==p){
par.right
=s.right;//处理特殊情况,par节点没有左孩子
}else{
par.left
=s.right;//处理一般情况,p节点替换成par的最左节点。
}
}
return p;
}

发散思考-更进一步

  假设一颗二叉树为是一颗右斜树,二叉搜索树的优势也将荡然无存。那问题出在哪?就是构造二叉树的时候,就是我们改善的着手点。

  那么就引出了平衡二叉树的概念,那什么是平衡二叉树呢?

    平衡二叉树或者是一棵空的二叉树,或者是具有以下性质的二叉树。

    根结点的左子树和右子树的深度最多相差1。

    根结点的左子树和右子树也都是平衡二叉树。

  那如何构建一颗平衡二叉树呢?先对数组进行排序,然后像折半查找一样,向两侧平均构造二叉树。当排序的数值多的时候,它将提高查找效率。

  

//构建平衡搜索二叉树
    public BinaryTreeNode buildBlanceTree(int [] array,int start,int end){
        if(start>end)
            return null;
        int mid=(start+end)/2;
        BinaryTreeNode node=new BinaryTreeNode(array[mid]);
        if(start==end){
            return node;
        }
        node.left=buildBlanceTree(array, start,mid-1);
        node.right=buildBlanceTree(array, mid+1,end);
        return node;
    }

  善于思考的大佬们又脑洞大开了,直接删除节点、插入节点的时候,若产生不平衡,重构平衡二叉树岂不是难上加难?具体代码又读者自行思考完成。

  平衡二叉树分为四种类型:LL型、RR型、LR型、RL型。

  

  LR型:不平衡点的左子树左转,以不平衡点为基点向右转。RL型:不平衡点的右子树右转,以补平衡点为基点向左转。

  

public class BinaryTreeNode {
    public  int data;
    public BinaryTreeNode left;
    public BinaryTreeNode right;

public BinaryTreeNode() {}

public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right) {
super();
this.data = data;
this.left = left;
this.right = right;
}

public BinaryTreeNode(int data) {
this(data,null,null);
}

public int getData() {
return data;
}

public void setData(int data) {
this.data = data;
}

public BinaryTreeNode getLeft() {
return left;
}

public void setLeft(BinaryTreeNode left) {
this.left = left;
}

public BinaryTreeNode getRight() {
return right;
}

public void setRight(BinaryTreeNode right) {
this.right = right;
}
}

public class BinarySortTree {

public BinarySortTree(){}

//构建搜索二叉树
public BinaryTreeNode build(int [] array){
BinaryTreeNode root
=new BinaryTreeNode(array[0]);
for( int i = 1 ; i < array.length ; i ++){
insertBST(root, array[i]);
}
return root;
}

//构建平衡搜索二叉树
public BinaryTreeNode buildBlanceTree(int [] array,int start,int end){
if(start>end)
return null;
int mid=(start+end)/2;
BinaryTreeNode node
=new BinaryTreeNode(array[mid]);
if(start==end){
return node;
}
node.left
=buildBlanceTree(array, start,mid-1);
node.right
=buildBlanceTree(array, mid+1,end);
return node;
}

public BinaryTreeNode insertBST(BinaryTreeNode node,int data){
if(node == null){
node
= new BinaryTreeNode(data);
return node;
}
else{
if(data <= node.data)
node.left
= insertBST(node.left, data);
else
node.right
= insertBST(node.right,data);
return node;
}
}

//层序遍历
public void levelOrder(BinaryTreeNode root){
BinaryTreeNode temp;
Queue
<BinaryTreeNode> queue=new LinkedList<BinaryTreeNode>();
queue.offer(root);
while(!queue.isEmpty()){
temp
=queue.poll();
System.out.print(temp.getData()
+"\t");
if(null!=temp.getLeft())
queue.offer(temp.getLeft());
if(null!=temp.getRight()){
queue.offer(temp.getRight());
}
}
}

public BinaryTreeNode deleteBST(BinaryTreeNode root,int key){
if(rootnull){
return null;
}
if(root.data
key){
return deleteNode(root);
}
else if(root.data<key){
root.right
=deleteBST(root.right, key);
}
else{
root.left
=deleteBST(root.left, key);
}
return root;
}

//删除元素
public BinaryTreeNode deleteNode(BinaryTreeNode p){
if(nullp.left&&nullp.right){
p
=null;//无孩子节点
}else if(p.leftnull){
p
=p.right;//只有右孩子
}else if(p.right
null){
p
=p.left;//只有左孩子
}else{
BinaryTreeNode par
=p;
BinaryTreeNode s
=p.right;
while(s.left!=null){
par
=s;
s
=s.left;
}
p.data
=s.data;
if(par==p){
par.right
=s.right;//处理特殊情况,par节点没有左孩子
}else{
par.left
=s.right;//处理一般情况,p节点替换成par的最左节点。
}
}
return p;
}

//查找元素
public BinaryTreeNode serachBST(BinaryTreeNode root,int target){
if(nullroot)
return null;
else if(root.getData()
target)
return root;
else if(root.getData()>target)
return serachBST(root.getLeft(), target);
else
return serachBST(root.getRight(), target);

}

public static void main(String[] args) {
int [] array=new int[]{11,2,5,7,3,9,4,66,55};
BinarySortTree bst
=new BinarySortTree();
//构建一颗搜索二叉树
BinaryTreeNode root=bst.build(array);
System.out.println(bst.serachBST(root,
9).getData());
bst.levelOrder(root);
System.out.println();

//构建一颗平衡搜索二叉树
Arrays.sort(array);
BinaryTreeNode node
=bst.buildBlanceTree(array, 0,array.length-1);
System.out.println(bst.serachBST(root,
11).getData());
bst.levelOrder(node);
System.out.println();

BinaryTreeNode n=bst.deleteBST(root,2);
bst.levelOrder(n);
System.out.println();
}

}

搜索二叉树整体代码
posted @ 2017-05-11 19:39  码农皮邱  阅读(1203)  评论(0)    收藏  举报