数据结构和算法

笔记5- 二叉排序树简介。 树和二叉树和森林之间的转换

2018-12-18  本文已影响0人  李星星星星星

二叉排序树(查找树,搜索树)

二叉排序树属于二叉树的一种:
当一个二叉树或者是一颗空树,或者是一颗具有如下性质的树:
1)若左子树不为空,那么左子树上面的所有节点的关键字值都比根节点的关键字值小
2)若右子树不为空,那么右子树上面的所有节点的关键字值都比根节点的关键字值大
3)左右子树都为二叉树
4)没有重复值(这一点在实际中可以忽略)
这棵二叉树可以称为二叉排序树,用二叉排序树可以很快的用来查询和搜索。


image.png

下面简单的介绍一个二叉排序树的增删改查方法:
1.生成一个空树:

public class SearchBinaryTree {
    
    //根节点
    public TreeNode rootNode;
    
    public class TreeNode{
        int data;
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode parent;
        
        public TreeNode(int data){
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
            this.parent = null;
        }
    }
}

image.png

2.添加一个节点:

    // 添加一个节点
    public TreeNode put(int data){
        if(rootNode==null){
            TreeNode node=new TreeNode(data);
            rootNode=node;
            return node;
        }
        TreeNode parent=null;
        TreeNode node=rootNode;
        //找到要放入的位置
        while(node!=null){
            parent=node;
            if(data<node.data){
                node=node.leftChild;
            }else if(data>node.data){
                node=node.rightChild;
            }else{//是重复值 就不理会了
                return node;
            }
        }
        //生成一个节点放入
        TreeNode newNode=new TreeNode(data);
        if(data<parent.data) {
            parent.leftChild = newNode;
        }else{
            parent.rightChild=newNode;
        }
        newNode.parent=parent;

        return newNode;
    }

3.查找一个节点:

    /**
     * 查找一个节点
     */
    public TreeNode searchNode(int data){
        if(rootNode==null){
            return null;
        }
        TreeNode node=rootNode;
        while(node!=null){
            if(node.data==data){
                return node;
            }else if(data>node.data){
                node=node.rightChild;
            }else if(data<node.data){
                node=node.leftChild;
            }
        }
        return null;
    }

4.删除一个节点:

1.节点是叶子 image.png
2.只有左孩子 image.png
3.只有右孩子 image.png
4.左右孩子都有 image.png
    /**
     * 删除节点
     * 要删除的节点在树上是一定存在的才删除
     * 
     * TODO 把一些引用置空
     * 此处删除方法只是为了说清思路,还会有更优化的删除方法,大家可以参考Java中的 TreeMap类
     */
    public void delNode(TreeNode node){
        if(node==null){
            throw new NoSuchElementException();
        }else{
            //先得到父亲,方便后面的操作
            TreeNode parent=node.parent;
            //1.叶子
            if(node.leftChild==null && node.rightChild==null){
                //特别的情况:1.树上只有一个节点或是空树
                if(parent==null){
                    rootNode=null;
                }else if(parent.rightChild==node){
                    parent.rightChild=null;
                }else if(parent.leftChild==node){
                    parent.leftChild=null;
                }
                node.parent=null;
            }else if(node.leftChild!=null && node.rightChild==null){
                //2.只有左孩子
                if(parent==null){//如果要删除的是根
                    node.parent=null;
                    node.leftChild.parent=null;
                    rootNode=node.leftChild;
                }else{
                    if(parent.leftChild==node){//要删除的节点是父亲的左边
                        node.leftChild.parent=parent;
                        parent.leftChild=node.leftChild;

                    }else{//要删除的节点是父亲的右边
                        node.leftChild.parent=parent;
                        parent.rightChild=node.leftChild;
                    }
                    node.parent=null;
                }

            }else if(node.leftChild==null && node.rightChild!=null){
                //3.只有右孩子
                if(parent==null){//如果要删除的是根
                    node.parent=null;
                    node.rightChild.parent=null;
                    rootNode=node.rightChild;
                }else{
                    if(parent.leftChild==node){//要删除的节点是父亲的左边
                        node.rightChild.parent=parent;
                        parent.leftChild=node.rightChild;
                    }else{//要删除的节点是父亲的右边
                        node.rightChild.parent=parent;
                        parent.rightChild=node.rightChild;
                    }
                    node.parent=null;
                }
            }else{//4。有左右两个孩子
                if(node.rightChild.leftChild==null){//1.如果被删除节点的右子树的左子树为空,就直接补上右子树
                    node.rightChild.leftChild=node.leftChild;
                    if(parent==null){
                        rootNode=node.rightChild;
                    }else{
                        if(parent.leftChild==node){
                            parent.leftChild=node.rightChild;
                            //
                        }else{
                            parent.rightChild=node.rightChild;
                            //
                        }
                    }
                    node.parent=null;
                }else{//2.否则就要补上右子树的左子树上最小的一个
                    TreeNode leftNode=getMinLeftTreeNode(node.rightChild);
                    //1
                    leftNode.leftChild=node.leftChild;
                    //2
                    TreeNode leftNodeP=leftNode.parent;
                    leftNodeP.leftChild=leftNode.rightChild;
                    //3
                    leftNode.rightChild=node.rightChild;
                    //4
                    if(parent==null){
                        rootNode=leftNode;
                    }else{
                        if(parent.leftChild==node){
                            parent.leftChild=leftNode;
                            //
                        }else{
                            parent.rightChild=leftNode;
                            //
                        }
                    }
                }
            }
        }
    }

这样就基本完成了一个可以增删查的二叉树:

import java.util.NoSuchElementException;

/**
 * 二叉排序树
 * @author LiXin
 *
 */
public class SearchBinaryTree {
    
    //根节点
    public TreeNode rootNode;
    
    // 添加一个节点
    public TreeNode put(int data){
        if(rootNode==null){
            TreeNode node=new TreeNode(data);
            rootNode=node;
            return node;
        }
        TreeNode parent=null;
        TreeNode node=rootNode;
        //找到要放入的位置
        while(node!=null){
            parent=node;
            if(data<node.data){
                node=node.leftChild;
            }else if(data>node.data){
                node=node.rightChild;
            }else{//是重复值 就不理会了
                return node;
            }
        }
        //生成一个节点放入
        TreeNode newNode=new TreeNode(data);
        if(data<parent.data) {
            parent.leftChild = newNode;
        }else{
            parent.rightChild=newNode;
        }
        newNode.parent=parent;

        return newNode;
    }
    
    /**
     * 中序遍历
     * @param rootNode
     */
    public void midOrderTraverse(TreeNode rootNode){
        if(rootNode == null){
            return;
        }
        midOrderTraverse(rootNode.leftChild);
        System.out.print(rootNode.data);
        midOrderTraverse(rootNode.rightChild);
    }
    
    /**
     * 查找一个节点
     */
    public TreeNode searchNode(int data){
        if(rootNode==null){
            return null;
        }
        TreeNode node=rootNode;
        while(node!=null){
            if(node.data==data){
                return node;
            }else if(data>node.data){
                node=node.rightChild;
            }else if(data<node.data){
                node=node.leftChild;
            }
        }
        return null;
    }


    /**
     * 删除节点
     * 要删除的节点在树上是一定存在的才删除
     * 
     * TODO 把一些应用置空
     */
    public void delNode(TreeNode node){
        if(node==null){
            throw new NoSuchElementException();
        }else{
            //先得到父亲,方便后面的操作
            TreeNode parent=node.parent;
            //1.叶子
            if(node.leftChild==null && node.rightChild==null){
                //特别的情况:1.树上只有一个节点或是空树
                if(parent==null){
                    rootNode=null;
                }else if(parent.rightChild==node){
                    parent.rightChild=null;
                }else if(parent.leftChild==node){
                    parent.leftChild=null;
                }
                node.parent=null;
            }else if(node.leftChild!=null && node.rightChild==null){
                //2.只有左孩子
                if(parent==null){//如果要删除的是根
                    node.parent=null;
                    node.leftChild.parent=null;
                    rootNode=node.leftChild;
                }else{
                    if(parent.leftChild==node){//要删除的节点是父亲的左边
                        node.leftChild.parent=parent;
                        parent.leftChild=node.leftChild;

                    }else{//要删除的节点是父亲的右边
                        node.leftChild.parent=parent;
                        parent.rightChild=node.leftChild;
                    }
                    node.parent=null;
                }

            }else if(node.leftChild==null && node.rightChild!=null){
                //3.只有右孩子
                if(parent==null){//如果要删除的是根
                    node.parent=null;
                    node.rightChild.parent=null;
                    rootNode=node.rightChild;
                }else{
                    if(parent.leftChild==node){//要删除的节点是父亲的左边
                        node.rightChild.parent=parent;
                        parent.leftChild=node.rightChild;
                    }else{//要删除的节点是父亲的右边
                        node.rightChild.parent=parent;
                        parent.rightChild=node.rightChild;
                    }
                    node.parent=null;
                }
            }else{//4。有左右两个孩子
                if(node.rightChild.leftChild==null){//1.如果被删除节点的右子树的左子树为空,就直接补上右子树
                    node.rightChild.leftChild=node.leftChild;
                    if(parent==null){
                        rootNode=node.rightChild;
                    }else{
                        if(parent.leftChild==node){
                            parent.leftChild=node.rightChild;
                            //此处要删除引用...
                        }else{
                            parent.rightChild=node.rightChild;
                            //此处要删除引用...
                        }
                    }
                    node.parent=null;
                }else{//2.否则就要补上右子树的左子树上最小的一个
                    TreeNode leftNode=getMinLeftTreeNode(node.rightChild);
                    //1
                    leftNode.leftChild=node.leftChild;
                    //2
                    TreeNode leftNodeP=leftNode.parent;
                    leftNodeP.leftChild=leftNode.rightChild;
                    //3
                    leftNode.rightChild=node.rightChild;
                    //4
                    if(parent==null){
                        rootNode=leftNode;
                    }else{
                        if(parent.leftChild==node){
                            parent.leftChild=leftNode;
                            //此处要删除引用...
                        }else{
                            parent.rightChild=leftNode;
                           //此处要删除引用...
                        }
                    }
                }
            }
        }
    }
    /**
     * 获取左子树上最小的一个
     * @param node
     * @return
     */
    private TreeNode getMinLeftTreeNode(TreeNode node) {
        TreeNode currootNode=null;
        if(node==null){
            return null;
        }else{
            currootNode=node;
            while(currootNode.leftChild!=null){
                currootNode=currootNode.leftChild;
            }
        }
        return currootNode;
    }
    
    
    public class TreeNode{
        int data;
        TreeNode leftChild;
        TreeNode rightChild;
        TreeNode parent;
        
        public TreeNode(int data){
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
            this.parent = null;
        }
    }
}

树 森林 二叉树的转化

1.树转化成二叉树:


image.png image.png

2.森林转化成二叉树:

image.png
image.png

3.二叉树转成树:


image.png image.png

4.二叉树转化成森林:

image.png image.png
上一篇 下一篇

猜你喜欢

热点阅读