10.二叉搜索树完整代码

Person类:

package dataStruct.tree.binarySearchTree;

public class Person  {
    private int age;

    public Person(int age){
        this.age = age;
    }


//    @Override
//    public int compareTo(Person p) {
//        return age - p.age;
//    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String toString(){
        return "age:"+age;
    }
}

BinarySearchTree类

package dataStruct.tree.binarySearchTree;


import dataStruct.tree.printer.BinaryTreeInfo;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;

/**
 * 二叉搜索树:
 * Tree定义了要实现哪些方法。
 * @param <E>
 */
public class BinarySearchTree<E > implements BinaryTreeInfo {
    //根节点
    public Node<E> root ;
    //节点数目
    public int size = 0;
    //提供比较器
    public Comparator<E> comparator;

    public BinarySearchTree(){
        this(null);
    }
    public BinarySearchTree(Comparator<E> comparator){
        this.comparator = comparator;
    }



    public int size() {
        return size;
    }


    public boolean isEmpty() {
        return false;
    }


    public void clear() {

    }

    /**
     * 添加节点
     * @param element
     */

    public void add(E element) {
        elementNotNullCheck(element);   //校验element是否不为null
        //添加第一个节点
        if (root == null){
            root = new Node(element,null);
            size++;
            return;
        }
        //添加的不是第一个节点
        //1.先找到父节点parent,以及记录插入节点的方向
        Node<E> node = root;
        Node<E> parent = root;//记录父节点
        int res = 0;//记录方向
        while(node != null){
            parent = node;
            res = compare(element , node.element);
            //res>0 说明在节点的右边
            if (res > 0){
                node = node.right;
            }
            //res <0 说明在节点的左边
            else if(res < 0){
                node = node.left;
            }else{//相等
                node.element = element;
                return;
            }

        }
        //2.通过节点方向,插入新节点
        Node<E> newnode = new Node<>(element,parent);
        if ( res > 0 ){
            parent.right = newnode;
        }else{
            parent.left = newnode;
        }
        size++;
    }

    /**
     * 返回的值>0:e1>e2
     * 返回的值<0:e1<e2
     * 返回的值=0:e1=e2
     * @param e1
     * @param e2
     * @return
     */
    public int compare(E e1, E e2){
        //二叉搜索树一定是可以根据对象来进行比较的
        //如果对象有自己的比较器,则只需传入两个参数即可
        if (comparator != null){
           return comparator.compare(e1,e2);
        }
        //如果没有自己的比较器
        return ((Comparable<E>)e1).compareTo(e2);
    }

    /**
     * 根据元素删除节点
     * @param element
     */
    public void remove(E element) {
        remove(node(element));
    }
    public void remove(Node<E> node){
        if ( node == null ) return;
        //如果node不等于空
        size--;
        //1.先考虑度为2的节点,
        // 因为是用后继节点的值替换跟节点,
        // 并把后继节点删除(而度为2的后继节点的度必为1或0,所以防止逻辑重叠)
        if(node.hasTwoChildren()){
           Node<E> p =  successor(node);//找后继节点
            //用后继节点的值覆盖该节点
            node.element = p.element;
            //删除后继节点,让后继节点替换node节点,后面会考虑删除度为1的节点
            node =  p ;
        }
        //删除节点node
        // 2.到这一步,此时节点的度必为1或0;
        Node<E> child = node.left != null ? node.left : node.right;
        if (child != null ){// node是度为1的节点
            //更改parent
            child.parent = node.parent;
            //更改parent的left、right的指向
            if( node.parent == null ){//node是根节点,并且度为1
                root = child;
            }
            else if( child == node.parent.left ){//child节点是左节点
                node.parent.left = child;
            }else{
                node.parent.right = child;
            }
        }else if( node.parent == null ){//node是叶子节点,并且是根节点
            root = null;
        }else{//节点为叶子节点
            if(node == node.parent.left){
                node.parent.left = null;
            }else{// node == node.parent.right
                node.parent.right = null;
            }
        }
    }



    public boolean contains(E element) {
        return node(element) != null;
    }

    /**
     * 校验element是否为空
     * @param element
     */
    public void elementNotNullCheck(E element){
        if (element == null){
            //非法参数异常
            throw new IllegalArgumentException("element must not is null");
        }
    }

    @Override
    public Object root() {
        return root;
    }

    @Override
    public Object left(Object node) {
        return ((Node<E>)node).left;
    }

    @Override
    public Object right(Object node) {
        return  ((Node<E>)node).right;
    }

    @Override
    public Object string(Object node) {
        return ((Node<E>)node).element;
    }

    /**
     * 内部类:
     * 声明树的结构
     * @param <E>
     */
    public static class Node<E>{
        E element;
        Node<E> left;
        Node<E> right;
        Node<E> parent;

        /**
         * 构造函数没有左、右孩子节点
         * 因为节点可能是叶子节点
         * @param element
         * @param parent
         */
        public Node(E element, Node<E> parent){
            this.element = element;
            this.parent = parent;
        }

        /**
         * 判断节点的度是否为2;
         * @return
         */
        public boolean hasTwoChildren(){
            return left == null && right == null;
        }
        /**
         * 判断是否为叶子节点
         * @return
         */
        public boolean isLeaf(){
            return left == null && right == null;
        }

        /**
         * 判断是否存在左右孩子节点
         * @return
         */
        public  boolean isHasTwoNode(){
            return  left != null && right != null;
        }

    }

    /**
     * 判断是否为完全二叉树
     * @return
     */
    public boolean isComplete(){
        if ( root == null ) return false;
        Queue<Node<E>> queue =new LinkedList<>();
        queue.offer(root);
        boolean leaf = false;
        while(!queue.isEmpty()){
           Node<E> node =  queue.poll();
           if (leaf && !node.isLeaf()){
               return  false;
           }
           if (node.isHasTwoNode()){
                queue.offer(node.left);
                queue.offer(node.right);
           }
           else if (node.left == null && node.right != null){
               return  false;
           }else{
               leaf = true;
               if (node.left != null){
                   queue.offer(node.left);
               }
           }
        }
        return  true;
    }

    public boolean completeBinaryTree(){
        if ( root == null ) return false;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);
        boolean flag = false;
        while(!queue.isEmpty()){
            Node<E> node =  queue.poll();
            if (flag && !node.isLeaf()){
                return  false;
            }
            if (node.left != null){
                queue.offer(node.left);
            }else if(node.right != null){
                return false;//这说明node.left == null && node.right != null
            }
            if (node.right != null){
               queue.offer(node.right);
            }else{
                //2种情况
                // node.left != null && node.right == null
                // node.left == null && node.right == null
                //总结:后面遍历的节点必须是叶子节点
                flag = true;
            }

        }
        return true;
    }

    /**
	 * 前序遍历
	 */
	public void preorderTraversal() {
		preorderTraversal(root);
	}
    public void preorderTraversal(Node<E> node){
        if (node == null ) return;
        System.out.println(node.element);
        preorderTraversal(node.left);
        preorderTraversal(node.right);
    }
    //后序遍历
    public void postOrderTraversal(){
        postOrderTraversal(root);
    }
    public void postOrderTraversal(Node<E> node){
        if (node == null ) return;
        postOrderTraversal(node.left);
        postOrderTraversal(node.right);
        System.out.println(node.element);
    }

    /**
     * 中跟遍历
     */
    public void middleOrderTraversal(){middleOrderTraversal(root);}
    public void middleOrderTraversal(Node<E> node){
        if (node == null ) return;
        middleOrderTraversal(node.left);
        System.out.println(node.element);
        middleOrderTraversal(node.right);
    }
    //层次遍历
    public void levelOrderTraversal(){
        if (root == null) return;
        Queue<Node<E>> queue = new LinkedList<>();
        queue.offer(root);//根节点入队
        while(!queue.isEmpty()){
            Node<E> node =  queue.poll();
            System.out.println(node.element);//输出节点元素
            if ( node.left != null ){
                queue.offer(node.left);
            }
            if ( node.right != null ){
                queue.offer(node.right);
            }
        }
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();
        toString(root,sb,"");
        return sb.toString();
    }
    public void toString(Node<E> node,StringBuilder sb,String prefix){
        if (node == null) return;
        sb.append(prefix).append("---").append(node.element).append("\n");
        toString(node.left,sb,prefix+"---L");
        toString(node.right,sb,prefix+"---R");
    }

    /**
     * 递归求解:
     * 求二叉树的高度
     */
    public int height(){
        return height(root);
    }
    public int height(Node<E> node){
        if (node == null) return 0;
        return 1 + Math.max(height(node.left),height(node.right));
    }
    /**
     * 非递归求树的高度
     * 层序遍历
     */
    public int getTreeHeight(){
        if (root == null ) return 0;
        Queue<Node<E>> queue = new LinkedList();
        queue.offer(root);
        int levelNum = 1;   //存取 层的节点数
        int height = 0;
        while(!queue.isEmpty()){
            Node<E> node =  queue.poll();//出队
            levelNum--;
            if (node.left != null){
                queue.offer(node.left);
            }
            if (node.right != null){
                queue.offer(node.right);
            }
            if (levelNum == 0){
                levelNum = queue.size();
                height++;
            }
        }
        return height;
    }

    /**
     * 根据元素查找node
     * @param element
     * @return
     */
    public Node<E> node(E element){
        Node<E>  node = root;
        while( node != null ){
            int res = compare(element, node.element);
            if (res == 0) return node;
            else if( res > 0 ){
                node = node.right;
            }else{
                node = node.left;
            }
        }
        return null;
    }

    /**
     * 寻找当前节点的前驱节点
     * @param node
     * @return
     */
    public Node<E> predecessor(Node<E> node){
        if ( node == null ) return null;
        Node<E> p =node.left;
        if ( p != null ){
            //1.当前节点的左子树不为空
            while(p.right != null){
                p = p.right;
            }
            return p;
        }
        //2.当前节点的左子树为空
        // 从父节点、祖父节点中寻找前驱节点
        while(node.parent != null && node == node.parent.left){
            node = node.parent;
        }
        //3.循环到这有两种情况
        //3.1 node.parent == null;-->即前驱节点为null(也可以是node.parent)
        //3.2 node = node.parent.right;-->即前驱节点为node.parent
        return node.parent;
    }

    /**
     * 寻找后驱节点
     * @param node
     * @return
     */
    public Node<E> successor(Node<E> node){
        if (node == null ) return null;
        Node<E> p = node.right;
        if (p != null ){
            // 1.前驱节点在左子树当中(right.left.left.left....)
            while( p.left != null){
                p = p.left;
            }
            return  p;
        }
        //2.从父节点,祖父节点寻找前驱节点
        while(node.parent != null && node == node.parent.right){
            node = node.parent;
        }

        return node.parent;
    }

}

测试类

package dataStruct.tree.binarySearchTree;

import dataStruct.tree.printer.BinaryTrees;

import java.util.Comparator;
import java.util.Scanner;

public class BinarySearchTreeTest<E> {
    public static class Mycompare implements Comparator<Person>{

        @Override
        public int compare(Person p1, Person p2) {
            return p1.getAge() - p2.getAge();
        }
    }
    public static void test1(){
        int [] arr = new int[]{7,4,9,2,5,8,11,3};
        BinarySearchTree<Integer> bst = new BinarySearchTree<>();
        for (int i = 0 ; i < arr.length ; i++){
            bst.add(arr[i]);
        }
        BinaryTrees.println(bst);
    }

    public static void test2(){
        //1.匿名内部类实现Comparator接口
        BinarySearchTree<Person> bst2 = new BinarySearchTree(new Comparator<Person>() {
            @Override
            public int compare(Person p1, Person p2) {
                return p1.getAge() - p2.getAge();
            }
        });
        bst2.add(new Person(7));
        bst2.add(new Person(4));
        bst2.add(new Person(2));
        bst2.add(new Person(1));
        bst2.add(new Person(3));
        bst2.add(new Person(5));
        bst2.add(new Person(9));
        bst2.add(new Person(8));
        bst2.add(new Person(11));
        bst2.add(new Person(12));
        BinaryTrees.println(bst2);
//        bst2.preorderTraversal();//先根遍历
//        bst2.middleOrderTraversal();//中须遍历
//        bst2.postOrderTraversal();//后序遍历
//         bst2.levelOrderTraversal();
    }
    public static void test3(){
        BinarySearchTree<Integer> bst3 = new BinarySearchTree();
        bst3.add(7);
        bst3.add(4);
        bst3.add(2);
        bst3.add(1);
        bst3.add(3);
        bst3.add(5);
        bst3.add(9);
        bst3.add(8);
        bst3.add(11);
//        bst3.add(12);
//        System.out.println(bst3);
        BinaryTrees.println(bst3);
//        System.out.println(bst3.height());
        boolean flag = bst3.completeBinaryTree();
        System.out.println("是否为完全二叉树:"+flag);

        System.out.println("请输入要删除的节点:");
        Scanner sc = new Scanner(System.in);
        int delNum = sc.nextInt();
        bst3.remove(delNum);
        BinaryTrees.println(bst3);
    }
    public static void test4(){
        BinarySearchTree<Integer> bst4 = new BinarySearchTree();
        bst4.add(7);
        bst4.add(4);
        bst4.add(2);
        bst4.add(1);
        bst4.add(3);
        bst4.add(5);
        bst4.add(9);
        bst4.add(8);
        bst4.add(11);
        BinaryTrees.println(bst4);
        System.out.println("请输入要查找前驱节点的节点值:");
        Scanner sc = new Scanner(System.in);
        int findNum = sc.nextInt();
        System.out.println(bst4.predecessor(bst4.node(findNum)).element);
        System.out.println("请输入要删除的节点");
        int delNum = sc.nextInt();
        bst4.remove(delNum);
        BinaryTrees.println(bst4);
    }
    public static void main(String[] args) {
        test4();

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员阿红

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值