死磕数据结构与算法——二叉排序树(java实现)。才疏学浅,如有错误,及时指正!

死磕数据结构与算法——二叉排序树(java实现)。才疏学浅,如有错误,及时指正!

  • 1. 基本概念
    • 1.1 什么是二叉排序树
    • 1.2 二叉排序树的示例(图)
  • 2. 功能详解
    • 2.1 创建和遍历
    • 2.2 二叉排序树的删除:
      • 三种情况
        • 1. 删除叶子节点
        • 2. 删除只有一棵子树的节点
        • 3. 删除有两棵子树的节点
  • 3. 示例代码
  • 总结

1. 基本概念

1.1 什么是二叉排序树

二叉排序树(Binary Sort Tree),又称为二叉查找树,或者二叉搜索树。对于二叉排序树的任何一个非叶子节点,它的左子节点的值比当前节点的值小,右子节点的值比当前节点的值大。
所以,二叉排序树有以下性质:

  1. 若左子树不为空,则左子树上所有节点的值均小于它的根节点的值。
  2. 若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值。
  3. 其左右子树也分别为二叉排序树。

1.2 二叉排序树的示例(图)

死磕数据结构与算法——二叉排序树(java实现)。才疏学浅,如有错误,及时指正!_第1张图片

2. 功能详解

2.1 创建和遍历

步骤
准备
树的节点的 TreeNode 类class
二叉排序树 类class
添加节点

  1. 判断要添加节点是否为空,如果为空,结束添加操作。如果不为空,进行步骤2。
  2. 判断要添加节点的值与当前节点值的关系。如果当前节点的值大于要添加节点的值,则判断当前节点左子树的情况。
    a. 如果当前节点的左子节点为空,则把要添加节点的值添加到当前节点的左边。
    b. 如果当前节点的左子节点不为空,则递归当前节点的左子树。找到左子节点为空的那个节点。
  3. 如果当前节点的值小于等于要添加节点的值,则判断当前节点右子树的情况。
    a. 如果当前节点的右子节点为空,则把要添加节点的值添加到当前节点的右边。
    b. 如果当前节点的右子节点不为空,则递归当前节点的右树。找到右子节点为空的那个节点。

二叉树的遍历: (中序遍历)

if(this.left != null) {
    this.left.midOrder();
}
System.out.println(this);
if(this.right != null) {
    this.right.midOrder();
}

2.2 二叉排序树的删除:

三种情况

准备:
我们要找到要删除的那个节点以及要删除的那个节点的父节点

1. 删除叶子节点

判断要删除的节点是父节点的左子节点还是右子节点,然后直接把parent的左子节点或者右子节点置空。

2. 删除只有一棵子树的节点

先判断父节点是否为空,如果为空,则直接可以把根节点指向目标节点的下一个节点
如果父节点不为空,判断目标节点是父节点的左子节点还是右子节点。然后再进行删除操作

if (targetNode.left != null) {
    if (parent != null) {
        // 如果 targetNode 是 parent 的左子节点
        if (parent.left.val == val) {
            parent.left = targetNode.left;  // 把目标节点的left指向父节点的left,达到删除的目的
        } else {
            // targetNode 是 parent 的右子节点
            parent.right = targetNode.left; // 把目标节点的left指向父节点的right
        }
    } else {
        root = targetNode.left;
    }
} else { //如果要删除的节点有右子节点
    if (parent != null) {
        if (parent.left.val == val) {
            // 如果 targetNode 是 parent 的左子节点
            parent.left = targetNode.right;
        } else {
            // 如果 targetNode 是 parent 的右子节点
            parent.right = targetNode.right;
        }
    } else {
        root = targetNode.right;
    }
}

3. 删除有两棵子树的节点

找到删除节点子树中的最小值,删除这个最小节点,然后把最小节点的值赋值给目标节点。

3. 示例代码

package BinarySortTree;

import java.math.BigInteger;

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 TreeNode(arr[i]));
        }

        // 中序遍历二叉排序树
        System.out.println("中序遍历:");
        binarySortTree.midOreder();  // 1,3,5,7,9,10,12

        // 测试删除叶子节点
        // binarySortTree.delNode( 2 );
        /*binarySortTree.delNode( 5 );
        binarySortTree.delNode( 9 );
        binarySortTree.delNode( 12 );*/

        //binarySortTree.delNode( 1 );
        binarySortTree.delNode( 10 );

        System.out.println("删除节点吼");
        binarySortTree.midOreder();
    }
}

/**
 * 创建二叉排序树
 */
class BinarySortTree {
    private TreeNode root;

    // 添加节点的方法
    public void add(TreeNode node) {
        if(root == null) {
            // 如果root为空,直接所加节点就是根节点
            root = node;
        } else {
            root.add(node);
        }
    }

    // 中序遍历
    public void midOreder() {
        if(root != null) {
            root.midOrder();
        } else {
            System.out.println("二叉排序树为空,不能遍历");
        }
    }

    // 查找要删除的节点
    public TreeNode search(int val) {
        if(root == null) {
            return null;
        } else {
            return root.search( val );
        }
    }

    // 查找要删除节点的父节点
    public TreeNode searchParent(int val) {
        if(root == null) {
            return null;
        } else {
            return root.searchParent( val );
        }
    }

    /**
     *
     * @param node 传入的节点(当做一棵二叉排序树的根节点)
     * @return 以node为根节点的二叉排序树的最小节点的值
     */
    public int delRigthTreeMin(TreeNode node) {
        TreeNode target = node;
        // 循环的查找左节点,找到最小的那个值
        while(target.left != null) {
            target = target.left;
        }
        // 这是target指向最小的节点
        // 删除最小节点
        delNode( target.val );
        return target.val;
    }

    // 删除节点
    public void delNode(int val) {
        if(root == null) {
            return;
        } else {
            // 1. 先找到要删除的节点 targetNode
            TreeNode targetNode = search( val );
            // 如果没有要删除的节点
            if(targetNode == null) {
                return;
            }
            // 如果二叉排序树只有一个节点
            if(root.left == null && root.right == null ){
                root = null;
                return;
            }
            // 2.找到 targetNode 的父节点
            TreeNode parent = searchParent( val );

            // 如果要删除的节点是叶子节点
            if(targetNode.left == null && targetNode.right == null) {
                // 说明targetNode为叶子节点
                // 判断targetNode 是父节点的左子节点还是右子节点
                if(parent.left != null && parent.left.val == val) {
                    // 左子节点
                    parent.left = null;
                } else if(parent.right != null && parent.right.val == val) {
                    // 右子节点
                    parent.right = null;
                }
            } else if(targetNode.left != null && targetNode.right != null) {
                int minVal = delRigthTreeMin( targetNode.right );
                targetNode.val = minVal;
            } else { //删除只有一棵子树的节点
                // 如果要删除的节点有左子节点
                if (targetNode.left != null) {
                    if (parent != null) {
                        // 如果 targetNode 是 parent 的左子节点
                        if (parent.left.val == val) {
                            parent.left = targetNode.left;
                        } else {
                            // targetNode 是 parent 的右子节点
                            parent.right = targetNode.left;
                        }
                    } else {
                        root = targetNode.left;
                    }
                } else { //如果要删除的节点有右子节点
                    if (parent != null) {
                        if (parent.left.val == val) {
                            // 如果 targetNode 是 parent 的左子节点
                            parent.left = targetNode.right;
                        } else {
                            // 如果 targetNode 是 parent 的右子节点
                            parent.right = targetNode.right;
                        }
                    } else {
                        root = targetNode.right;
                    }
                }
            }
        }
    }

}

/**
* 创建Node节点
 */
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    public TreeNode(int val) {
        this.val = val;
    }

    @Override
    public String toString () {
        return "TreeNode [value = " + val + "]";
    }


    /**
     * 查找要删除的节点
     * @param val 希望删除节点的值
     * @return  如果找到返回该节点,没找到返回null
     */
    public TreeNode search(int val) {
        if(val == this.val) {
            // 找到该节点
            return this;
        } else if (val < this.val) {
            // 如果查找的值小于当前节点的值, 则向左子树递归查找
            // 如果左子节点为空,不能再找了
            if(this.left == null) {
                return null;
            }
            return this.left.search(val);
        } else {
            // 如果查找的值大于等于当前节点的值, 则向右子树递归查找
            if(this.right == null) {
                return null;
            }
            return this.right.search( val );
        }
    }

    /**
     * 查找要删除节点的父节点
     * @param val 要查找的节点的值
     * @return 返回的是要删除节点的父节点,如果没有返回null。
     */
    public TreeNode searchParent(int val) {
        // 如果当前节点就是要删除节点的父节点,直接返回
        if((this.left != null && this.left.val == val) || (this.right != null && this.right.val == val)) {
            return this;
        } else {
            if(val < this.val && this.left != null) {
                // 如果要查找的节点的值小于当前节点的值,并且当前节点的左子节点不为空
                // 向左子树递归查找
                return this.left.searchParent( val );
            } else if(val >= this.val && this.left != null) {
                // 如果要查找的节点的值大于等于当前节点的值,并且当前节点的右子节点不为空
                return this.right.searchParent( val );
            } else {
                // 没有找到父节点
                return null;
            }
        }
    }

    // 添加节点的方法 —— 递归完成
    public void add (TreeNode node) {
        if(node == null ) {
            return;
        }
        // 判断要添加节点的值于当前节点值的关系
        // 如果当前节点的值大于要添加节点的值,判断当前节点的左子树的情况
        if(node.val < this.val) {
            // 如果当前节点的左子节点为null
            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 midOrder() {
        if(this.left != null) {
            this.left.midOrder();
        }
        System.out.println(this);
        if(this.right != null) {
            this.right.midOrder();
        }
    }
}

总结

本文对二叉排序树作了基本的介绍。使用代码完成了二叉排序树的创建,遍历,删除等功能。

你可能感兴趣的:(数据结构与算法,算法,数据结构,二叉树,java,树结构)