跳到主要内容

13、数据结构与算法 - 实战:树

0. 遍历二叉树

方式

前序遍历:根 → 左子树 → 右子树

中序遍历:左子树 → 根 → 右子树

后序遍历:左子数 → 右子树 → 根

层次遍历:顶层开始琢层进行遍历,每层从左到右遍历

 

图中的完全二叉树四大遍历形式的结果:

1、 *前序遍历:*93046584979;

2、 *中序遍历:*46305897949;

3、 *后续遍历:*46583079499;

4、 *层次遍历:*93049465879;

1. 基本类 - Student、TreeEnumeration

Student.java

public class Student {
   
     

    Integer id;
    String name;
    Integer year;

    public Student() {
   
     
    }

    public Student(Integer id, String name, Integer year) {
   
     
        this.id = id;
        this.name = name;
        this.year = year;
    }

    public Integer getId() {
   
     
        return id;
    }

    public void setId(Integer id) {
   
     
        this.id = id;
    }

    public String getName() {
   
     
        return name;
    }

    public void setName(String name) {
   
     
        this.name = name;
    }

    public Integer getYear() {
   
     
        return year;
    }

    public void setYear(Integer year) {
   
     
        this.year = year;
    }
    @Override
    public String toString() {
   
     
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
    public static void main(String[] args) throws Exception {
   
     

        OrderType orderType = null;

        orderType = OrderType.POST_ORDER;

        switch(orderType) {
   
     
            case POST_ORDER:
                System.out.println(1);
        }

    }

}

TreeEnumeration.java

public enum TreeEnumeration {
   
     

    POST_ORDER, IN_ORDER, PRE_ORDER, POST_CLUE_ORDER,IN_CLUE_ORDER, PRE_CLUE_ORDER,
    POST_SEARCH, IN_SEARCH, PRE_SEARCH,
    REMOVE_SON_TREE, REMOVE_SINGLE_NODE,
    PRE_ORDER_CLUE, IN_ORDER_CLUE, POST_ORDER_CLUE

}

2. 二叉排序(查找)树

满足下列条件 - (中序遍历元素是升序排列)

1、 左节点小于父节点;

2、 右节点大于父节点;

3、 所有节点的左右子树都需满足1、2条件;

 

BinarySortTree.java

/**
 * @Classname BinarySortTree
 * @Description
 * @Date 2022/4/11 23:50
 * @Created by lrc
 */
public class BinarySortTree<T> {
   
     

    Node<T> root;
    private Integer curNodeNum = 0;

    private List<T> orderList;

    //二叉树构造函数
    BinarySortTree(T... datas) {
   
     
        for(T data: datas ) {
   
     
            add(data);
        }
    }

    //添加二叉树节点
    public boolean add(T data) {
   
     

        Node<T> newNode = new Node<T>();
        newNode.setData(data);

        if(root == null) {
   
     
            root = newNode;
        }else {
   
     
            Node<T> curNode = root;
            Integer newId = newNode.getId();

            //添加节点阶段
            while(true) {
   
     
                // 获取当前遍历到的节点的ID号
                Integer curId = curNode.getId();

                // 如果添加节点ID号与当前节点ID号小,则当前节点的左子节点进行遍历
                if(newId < curId) {
   
     
                    if(curNode.getLeftNode() == null) {
   
     
                        curNode.setLeftNode(newNode);
                        break;
                    }
                    curNode = curNode.getLeftNode();
                    // 如果添加节点ID号与当前节点ID号大,则当前节点的右子节点进行遍历
                }else if(newId > curId) {
   
     
                    if(curNode.getRightNode() == null) {
   
     
                        curNode.setRightNode(newNode);
                        break;
                    }
                    curNode = curNode.getRightNode();
                    //如果添加节点ID号与当前节点ID号等于,则直接抛出异常
                }else {
   
     
                    throw  new RuntimeException("不可添加重复ID号的节点");
                }
            }

        }
        ++this.curNodeNum;
        return true;
    }
    //前序遍历 
    private void preOrder(Node<T> node) {
   
     

        if(node != null ) {
   
     
            orderList.add(node.getData());
        }
        if(node.leftNode != null) {
   
     
            preOrder(node.getLeftNode());
        }

        if(node.rightNode != null) {
   
     
            preOrder(node.getRightNode());
        }

    }

    //中序遍历
    private void inOrder(Node<T> node) {
   
     

        if(node != null ) {
   
     

            if(node.getLeftNode() != null) {
   
     
                inOrder(node.getLeftNode());
            }

            orderList.add(node.getData());

            if(node.getRightNode() != null) {
   
     
                inOrder(node.getRightNode());
            }
        }

    }

    //后序遍历
    private void postOrder(Node<T> node) {
   
     
        if(node != null ) {
   
     

            if(node.getLeftNode() != null) {
   
     
                postOrder(node.getLeftNode());
            }

            if(node.getRightNode() != null) {
   
     
                postOrder(node.getRightNode());
            }

            orderList.add(node.getData());

        }
    }

    // 遍历树
    public List<T> order(TreeEnumeration treeEnumeration) {
   
     

        if(orderList == null) {
   
     
            orderList = new ArrayList<>(curNodeNum);
        }else {
   
     
            orderList.clear();
        }
        switch (treeEnumeration) {
   
     
            case PRE_ORDER: {
   
      preOrder(root);break;}
            case IN_ORDER: {
   
      inOrder(root);break;}
            case POST_ORDER: {
   
      postOrder(root);break;}
            default: throw new RuntimeException("请输入合法的排序枚举常量");
        }
        return orderList;
    }
    //前序遍历查找
    public T preOrderSearch(Node<T> node, int id) {
   
     

        T t = null;

        if(node != null) {
   
     

            Integer curId = node.getId();

            if(curId == id) {
   
     
                t =  node.getData();
            }else if( node.getLeftNode() != null && curId > id ){
   
     
                t = preOrderSearch(node.getLeftNode(), id);
            }else if(node.getRightNode() != null && curId < id) {
   
     
                t = preOrderSearch(node.getRightNode(), id);
            }
        }

        return t;
    }
    //中序遍历查找
    public T inOrderSearch(Node<T> node, int id) {
   
     

        T t = null;

        if(node != null) {
   
     

            Integer curId = node.getId();

            if(node.getLeftNode() != null && curId > id) {
   
     
                t = preOrderSearch(node.getLeftNode(), id);
            }else if( curId == id ){
   
     
                t =  node.getData();
            }else if(node.getRightNode() != null && curId < id) {
   
     
                t = preOrderSearch(node.getRightNode(), id);
            }
        }

        return t;
    }

    //后序遍历查找
    public T postOrderSearch(Node<T> node, int id) {
   
     

        T t = null;

        if(node != null) {
   
     

            Integer curId = node.getId();

            if(node.getLeftNode() != null && curId > id) {
   
     
                t = preOrderSearch(node.getLeftNode(), id);
            }else if(node.getRightNode() != null && curId < id) {
   
     
                t = preOrderSearch(node.getRightNode(), id);
            }else if( curId == id ){
   
     
                t =  node.getData();
            }
        }

        return t;
    }

    // 遍历树通过ID号查找元素并返回 -
    public T search(int id, TreeEnumeration treeEnumeration) {
   
     

        T t = null;
        switch (treeEnumeration) {
   
     
            case PRE_SEARCH: {
   
      t = preOrderSearch(root,id);break;}
            case IN_SEARCH: {
   
      t = inOrderSearch(root,id);break;}
            case POST_SEARCH: {
   
      t = postOrderSearch(root,id);break;}
            default: throw new RuntimeException("请输入合法的查找枚举常量");
        }
        return t;
    }

    //把当前子树一同删除,而不是单纯只删一个节点
    private boolean removeSonTree(int id) {
   
     

        boolean isDeleted = false;

        if(root == null) {
   
     
            isDeleted = false;
        }else {
   
     

            Node<T> fatherNode = null;
            Node<T> curNode = root;

            while(true) {
   
     

                Integer curId = curNode.getId();

                //当前节点
                if(curId == id) {
   
     

                    if(fatherNode == null) {
   
     
                        root = null;
                    }else {
   
     
                        if(fatherNode.getLeftNode() == curNode) {
   
     
                            fatherNode.setLeftNode(null);
                        }

                        if(fatherNode.getRightNode() == curNode) {
   
     
                            fatherNode.setRightNode(null);
                        }
                    }
                    isDeleted = true;
                    break;
                }

                Node<T> nextNode;
                //左节点
                if(curId < id) {
   
     
                    nextNode = curNode.getRightNode();
                    if(nextNode == null) {
   
     
                        break;
                    }
                    fatherNode = curNode;
                    curNode = nextNode;
                }

                //右节点
                if(curId > id) {
   
     

                    nextNode = curNode.getLeftNode();
                    if(nextNode == null) {
   
     
                        break;
                    }
                    fatherNode = curNode;
                    curNode = nextNode;
                }
            }

        }

        return isDeleted;
    }
    //只删除当前节点 - 优先左节点代替被删除节点
    private boolean removeSignleNode(int id) {
   
     

        boolean isDeleted = false;

        if(root == null) {
   
     
            isDeleted = false;
        }else {
   
     

            Node<T> fatherNode = null;
            Node<T> curNode = root;

            while(true) {
   
     

                Integer curId = curNode.getId();

                //当前节点
                if(curId == id) {
   
     

                    if(fatherNode == null) {
   
     
                        root = null;
                    }else {
   
     

                        //标记删除的节点是父节点的左节点还是右节点 0左节点  1右节点
                        int flagLeftOrRight = 0;
                        if(fatherNode.getLeftNode() == curNode) {
   
     
                            fatherNode.setLeftNode(null);
                            flagLeftOrRight = 0;
                        }

                        if(fatherNode.getRightNode() == curNode) {
   
     
                            fatherNode.setRightNode(null);
                            flagLeftOrRight = 1;
                        }

                        //将取代被删除节点的节点
                        Node<T> replaceDeleteNode;

                        //遍历curNode右节点的节点
                        Node<T> traverseNode;
                        replaceDeleteNode = curNode.getLeftNode();
                        //当前节点存在左节点
                        if(replaceDeleteNode != null) {
   
     

                            if(flagLeftOrRight == 0) {
   
     
                                fatherNode.leftNode = replaceDeleteNode;
                            }else {
   
     
                                fatherNode.rightNode = replaceDeleteNode;
                            }

                            当前节点存在右节点
                            if(curNode.getRightNode() != null) {
   
     

                                traverseNode = curNode;
                                while(true) {
   
     
                                    if(traverseNode.getRightNode() == null) {
   
     
                                        traverseNode.setRightNode(curNode.getRightNode());
                                        break;
                                    }
                                    traverseNode = traverseNode.getRightNode();
                                }
                            }
                        }else {
   
     
                            replaceDeleteNode = curNode.getRightNode();
                            if(flagLeftOrRight == 0) {
   
     
                                fatherNode.leftNode = replaceDeleteNode;
                            }else {
   
     
                                fatherNode.rightNode = replaceDeleteNode;
                            }

                        }

                    }
                    isDeleted = true;
                    break;
                }

                Node<T> nextNode;
                //左节点
                if(curId < id) {
   
     
                    nextNode = curNode.getRightNode();
                    if(nextNode == null) {
   
     
                        break;
                    }
                    fatherNode = curNode;
                    curNode = nextNode;
                }

                //右节点
                if(curId > id) {
   
     

                    nextNode = curNode.getLeftNode();
                    if(nextNode == null) {
   
     
                        break;
                    }
                    fatherNode = curNode;
                    curNode = nextNode;
                }
            }

        }

        return isDeleted;
    }
    public boolean remove(int id, TreeEnumeration treeEnumeration) {
   
     

        boolean flag =false;

        switch(treeEnumeration) {
   
     
            case REMOVE_SON_TREE: {
   
     flag =  removeSonTree(id);break;}
            case REMOVE_SINGLE_NODE: {
   
     flag = removeSignleNode(id);break;}
            default:new RuntimeException("请输入合法的删除操作");
        }

        return flag;

    }

    // 重写toString方法 -其实就是中序遍历输出
    @Override
    public String toString() {
   
     
        order(TreeEnumeration.IN_ORDER);
        return orderList.toString();
    }

    private class Node<T> {
   
     

        T data;
        Node<T> leftNode;
        Node<T> rightNode;

        public Integer getId() {
   
     
            Integer id = null;
            try {
   
     
                Field field = data.getClass().getDeclaredField("id");
                field.setAccessible(true);
                id = (Integer) field.get(data);
            }catch(Exception e) {
   
     
                e.printStackTrace();
            }
            return id;
        }

        public T getData() {
   
     
            return data;
        }

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

        public Node<T> getLeftNode() {
   
     
            return leftNode;
        }

        public void setLeftNode(Node<T> leftNode) {
   
     
            this.leftNode = leftNode;
        }

        public Node<T> getRightNode() {
   
     
            return rightNode;
        }

        public void setRightNode(Node<T> rightNode) {
   
     
            this.rightNode = rightNode;
        }
    }
    public static void main(String[] args) {
   
     

        //数据准备
        Student student1 = new Student(1, "lrc", 23);
        Student student2 = new Student(2, "tyr", 21);
        Student student3 = new Student(3, "smis", 30);
        Student student4 = new Student(4, "tony", 43);
        Student student5 = new Student(5, "ghy", 18);
        Student student6 = new Student(5, "ghy", 18);
        Student student7 = new Student(7, "ert", 35);

        Student[] students1 = {
   
     student3,student1,student2,student4,student5};
        Student[] students2 = {
   
     student3,student1,student2,student4,student5,student6};

        //构造二叉排序树1
        BinarySortTree<Student> tree1 = new BinarySortTree<>(students1);
        System.out.printf("tree1前序遍历:%s\n",tree1.order(TreeEnumeration.PRE_ORDER));
        System.out.printf("tree1中序遍历:%s\n",tree1.order(TreeEnumeration.IN_ORDER));
        System.out.printf("tree1后序遍历:%s\n\n",tree1.order(TreeEnumeration.POST_ORDER));

        tree1.add(student7);
        System.out.printf("tree1添加节点后前序遍历:%s\n",tree1.order(TreeEnumeration.PRE_ORDER));
        System.out.printf("tree1添加节点后中序遍历:%s\n",tree1.order(TreeEnumeration.IN_ORDER));
        System.out.printf("tree1添加节点后后序遍历:%s\n\n",tree1.order(TreeEnumeration.POST_ORDER));

        Student searchStu = null;
        searchStu = tree1.search(4, TreeEnumeration.PRE_SEARCH);
        System.out.printf("Tree1前序遍历查找ID为4的节点:%s\n", searchStu);

        searchStu = tree1.search(4, TreeEnumeration.IN_SEARCH);
        System.out.printf("Tree1中序遍历查找ID为4的节点:%s\n", searchStu);

        searchStu = tree1.search(4, TreeEnumeration.POST_SEARCH);
        System.out.printf("Tree1后序遍历查找ID为4的节点:%s\n\n", searchStu);
        tree1.remove(4, TreeEnumeration.REMOVE_SINGLE_NODE);
        System.out.printf("Tree1仅删除ID为4的节点后前序遍历:%s\n",tree1.order(TreeEnumeration.PRE_ORDER));
        tree1.add(student4);
        System.out.printf("Tree1添加ID为4的节点后前序遍历:%s\n",tree1.order(TreeEnumeration.PRE_ORDER));
        tree1.remove(4, TreeEnumeration.REMOVE_SON_TREE);
        System.out.printf("Tree1删除以ID为4的根节点的子树后前序遍历:%s\n\n", tree1.order(TreeEnumeration.IN_ORDER));


        //构造二叉排序树2 - 构造异常,因为有相同ID号
        BinarySortTree<Student> tree2 = new BinarySortTree<>(students2);

    }

}

 

3. 顺序存储二叉树 - 完全二叉树结构

特点:N从0开始

  1. 第N个数组索引的左节点的数组索引是:2 * N + 1
  2. 第N个数组索引的右节点的数组索引是:2 * N + 2
  3. 第N个数组索引的父节点的数组索引是:(N-1)/2

 

SequentialStorageTree.java

/**
 * @Classname SequentialStorageTree
 * @Description
 * @Date 2022/4/12 13:32
 * @Created by lrc
 */
public class SequentialStorageTree<T> {
   
     

    private T[] datas;
    private StringBuilder orderStr = new StringBuilder();

    SequentialStorageTree(T... datas) {
   
     
        this.datas = datas;
    }
    //遍历顺序存储树
    public String order(TreeEnumeration treeEnumeration) {
   
     

        //清空之前的遍历结果
        orderStr.delete(0,orderStr.length());

        orderStr.append("[");
        switch(treeEnumeration) {
   
     
            case PRE_ORDER: {
   
      preOrder(0); break;}
            case IN_ORDER:{
   
      inOrder(0); break;}
            case POST_ORDER: {
   
      postOrder(0); break;}
            default: new RuntimeException("请输入合法的排序枚举常量");
        }
        orderStr.replace(orderStr.lastIndexOf(", "), orderStr.length(), "");
        orderStr.append("]");

        return orderStr.toString();

    }

    //递归 - 前序遍历通过index进行查询节点
    public void preOrder(int index) {
   
     

        if(index < datas.length && datas[index] != null) {
   
     
            orderStr.append(datas[index] + ", ");
        }

        int nextIndex = 2*index + 1;
        if(nextIndex < datas.length) {
   
     
            preOrder(nextIndex);
        }

        nextIndex = 2*index + 2;
        if(nextIndex < datas.length) {
   
     
            preOrder(nextIndex);
        }

    }

    //递归 - 中序遍历通过index进行查询节点
    public void inOrder(int index) {
   
     

        int nextIndex = 2*index + 1;
        if(nextIndex < datas.length) {
   
     
            inOrder(nextIndex);
        }
        if(index < datas.length && datas[index] != null) {
   
     
            orderStr.append(datas[index] + ", ");
        }
        nextIndex = 2*index + 2;
        if(nextIndex < datas.length) {
   
     
            inOrder(nextIndex);
        }

    }
    //递归 - 中序遍历通过index进行查询节点
    public void postOrder(int index) {
   
     

        int nextIndex = 2*index + 1;
        if(nextIndex < datas.length) {
   
     
            postOrder(nextIndex);
        }

        nextIndex = 2*index + 2;
        if(nextIndex < datas.length) {
   
     
            postOrder(nextIndex);
        }
        if(index < datas.length && datas[index] != null) {
   
     
            orderStr.append(datas[index] + ", ");
        }

    }
    public static void main(String[] args) {
   
     

        //数据准备
        Student student1 = new Student(1, "lrc", 23);
        Student student2 = new Student(2, "tyr", 21);
        Student student3 = new Student(3, "smis", 30);
        Student student4 = new Student(4, "tony", 43);
        Student student5 = new Student(5, "ghy", 18);
        Student[] students1 = {
   
     student3,student1,student2,student4,student5};

        SequentialStorageTree<Student> tree = new SequentialStorageTree(students1);

        System.out.printf("前序遍历:%s\n" ,tree.order(TreeEnumeration.PRE_ORDER));
        System.out.printf("中序遍历:%s\n" ,tree.order(TreeEnumeration.IN_ORDER));
        System.out.printf("后序遍历:%s\n" ,tree.order(TreeEnumeration.POST_ORDER));

    }

}

 

4. 线索化二叉排序树

思路:将二叉排序树的Null左右指针利用起来

指针

左Null指针:前驱节点指针

右Null指针:后继节点指针

线索化二叉排序树

前序线索二叉树

中序线索二叉树

后序线索二叉树

粗的箭头线即是线索
 

 

 

ThreadedBinaryTree.java

/**
 * @Classname ThreadedBinaryTree
 * @Description
 * @Date 2022/4/12 15:42
 * @Created by lrc
 */
public class ThreadedBinaryTree<T> {
   
     
    Node<T> root;

    //当前遍历接节点的前驱节点
    Node<T> pre = null;

    private Integer curNodeNum = 0;

    private List<T> orderList;

    //二叉树构造函数 - 默认前序线索二叉树
    ThreadedBinaryTree(T... datas) {
   
     
        for (T data : datas) {
   
     
            add(data);
        }
        clues(TreeEnumeration.PRE_ORDER_CLUE);
    }

    public static void main(String[] args) {
   
     
        //数据准备
        Student student1 = new Student(1, "lrc", 23);
        Student student2 = new Student(2, "tyr", 21);
        Student student3 = new Student(3, "smis", 30);
        Student student4 = new Student(4, "tony", 43);
        Student student5 = new Student(5, "ghy", 18);

        Student[] students = {
   
     student3, student1, student2, student4, student5};

        //前序线索二叉排序树
        ThreadedBinaryTree<Student> tree = new ThreadedBinaryTree<>(students);

        //前序线索二叉排序树 - 前序、中序、后序遍历 - 不依赖线索
        System.out.println("\n前序线索二叉排序树 - 前序、中序、后序遍历 - 不依赖线索------------------");
        System.out.println(tree.order(TreeEnumeration.PRE_ORDER));
        System.out.println(tree.order(TreeEnumeration.IN_ORDER));
        System.out.println(tree.order(TreeEnumeration.POST_ORDER));

        //寻找id为2、3的元素
        System.out.println("\n寻找元素--------------------");
        System.out.println(tree.preOrderSearch(2));
        System.out.println(tree.preOrderSearch(3));
        //修改二叉树的排序线索时,必须先清空原来的线索
        tree.clearClues();
        System.out.println("\n中序线索二叉排序树 - 依赖线索遍历以及节点的信息----------------------");
        tree.clues(TreeEnumeration.IN_ORDER_CLUE);
        System.out.println(tree.order(TreeEnumeration.IN_CLUE_ORDER));
        System.out.println(tree.preOrderSearch(1));
        System.out.println(tree.preOrderSearch(2));
        System.out.println(tree.preOrderSearch(4));
        System.out.println(tree.preOrderSearch(5));
        tree.clearClues();
        System.out.println("\n后序线索二叉排序树 - 依赖线索遍历以及节点的信息----------------------");
        tree.clues(TreeEnumeration.POST_ORDER_CLUE);
        System.out.println(tree.order(TreeEnumeration.POST_CLUE_ORDER));
        System.out.println(tree.preOrderSearch(1));
        System.out.println(tree.preOrderSearch(2));
        System.out.println(tree.preOrderSearch(4));
        System.out.println(tree.preOrderSearch(5));
        tree.clearClues();
        System.out.println("\n前序线索二叉排序树 - 依赖线索遍历以及节点的信息----------------------");
        tree.clues(TreeEnumeration.PRE_ORDER_CLUE);
        System.out.println(tree.order(TreeEnumeration.PRE_CLUE_ORDER));
        System.out.println(tree.preOrderSearch(1));
        System.out.println(tree.preOrderSearch(2));
        System.out.println(tree.preOrderSearch(4));
        System.out.println(tree.preOrderSearch(5));
    }

    //添加二叉树节点
    public boolean add(T data) {
   
     

        Node<T> newNode = new Node<T>();
        newNode.setData(data);

        if (root == null) {
   
     
            root = newNode;
        } else {
   
     
            Node<T> curNode = root;
            Integer newId = newNode.getId();

            //添加节点阶段
            while (true) {
   
     
                // 获取当前遍历到的节点的ID号
                Integer curId = curNode.getId();

                // 如果添加节点ID号与当前节点ID号小,则当前节点的左子节点进行遍历
                if (newId < curId) {
   
     
                    if (curNode.getLeftNode() == null) {
   
     
                        curNode.setLeftNode(newNode);
                        break;
                    }
                    curNode = curNode.getLeftNode();
                    // 如果添加节点ID号与当前节点ID号大,则当前节点的右子节点进行遍历
                } else if (newId > curId) {
   
     
                    if (curNode.getRightNode() == null) {
   
     
                        curNode.setRightNode(newNode);
                        break;
                    }
                    curNode = curNode.getRightNode();
                    //如果添加节点ID号与当前节点ID号等于,则直接抛出异常
                } else {
   
     
                    throw new RuntimeException("不可添加重复ID号的节点");
                }
            }

        }
        ++this.curNodeNum;
        return true;
    }

    //前序遍历
    private void preOrder(Node<T> node) {
   
     

        if (node != null) {
   
     
            orderList.add(node.getData());
        }
        if (node.leftNode != null && node.flagLeftNode == 0) {
   
     
            preOrder(node.getLeftNode());
        }

        if (node.rightNode != null && node.flagRightNode == 0) {
   
     
            preOrder(node.getRightNode());
        }

    }

    //中序遍历
    private void inOrder(Node<T> node) {
   
     

        if (node != null) {
   
     

            if (node.getLeftNode() != null && node.flagLeftNode == 0) {
   
     
                inOrder(node.getLeftNode());
            }

            orderList.add(node.getData());

            if (node.getRightNode() != null && node.flagRightNode == 0) {
   
     
                inOrder(node.getRightNode());
            }
        }

    }

    //中序线索遍历
    private void inClueOrder() {
   
     

        Node<T> curNode = root;

        while (curNode != null) {
   
     

            //先找最左节点
            while (curNode.flagLeftNode == 0) {
   
     
                curNode = curNode.leftNode;
            }
            orderList.add(curNode.getData());
            //根据线索找到下一个节点
            while (curNode.flagRightNode == 1) {
   
     
                curNode = curNode.rightNode;
                orderList.add(curNode.getData());
            }

            curNode = curNode.rightNode;

        }

    }

    //前序线索遍历
    private void preClueOrder() {
   
     

        Node<T> curNode = root;

        while (curNode != null) {
   
     

            //一来就直接读取
            orderList.add(curNode.getData());

            //根据线索找到下一个节点
            while (curNode.flagRightNode == 1) {
   
     

                if (curNode.rightNode == null) {
   
     
                    break;
                }

                curNode = curNode.rightNode;
                orderList.add(curNode.getData());
            }

            while (curNode.flagLeftNode == 0) {
   
     
                curNode = curNode.leftNode;
                orderList.add(curNode.getData());
            }

            curNode = curNode.rightNode;

        }

    }

    //后序线索遍历
    private void postClueOrder() {
   
     
        Node<T> curNode = root;

        //判断是否有遍历根节点的右子树
        boolean flag = false;

        //循环
        while(curNode != null) {
   
     

            //找最左节点
            while (curNode.flagLeftNode == 0 && curNode.leftNode != null) {
   
     
                curNode = curNode.leftNode;
            }

            //如果当前节点含有右节点 - 则说明还不是最左节点
            if(curNode.rightNode != null && curNode.flagRightNode == 0) {
   
     
                curNode = curNode.rightNode;
                continue;
            }

            //已经判断了这肯定是最左节点 - 故添加
            orderList.add(curNode.getData());
            //根据线索找到下一个节点
            while (curNode.flagRightNode == 1) {
   
     

                curNode = curNode.rightNode;
                orderList.add(curNode.getData());

                //如果刚好有线索到根节点 -- 添加完直接退出遍历即可
                if(curNode == root) {
   
     
                    return;
                }

            }

            //已经遍历完右节点,然而还是没有线索到根节点 - 只能手动添加根节点信息
            if(flag) {
   
     
                orderList.add(root.getData());
                break;
            }

            curNode = root.rightNode;

            //准备遍历根节点的右子树
            flag = true;

        }

    }

    //后序遍历
    private void postOrder(Node<T> node) {
   
     
        if (node != null) {
   
     

            if (node.getLeftNode() != null && node.flagLeftNode == 0) {
   
     
                postOrder(node.getLeftNode());
            }

            if (node.getRightNode() != null && node.flagRightNode == 0) {
   
     
                postOrder(node.getRightNode());
            }

            orderList.add(node.getData());

        }
    }

    // 遍历树
    public List<T> order(TreeEnumeration treeEnumeration) {
   
     

        if (orderList == null) {
   
     
            orderList = new ArrayList<>(curNodeNum);
        } else {
   
     
            orderList.clear();
        }
        switch (treeEnumeration) {
   
     
            case PRE_ORDER: {
   
     
                preOrder(root);
                break;
            }
            case IN_ORDER: {
   
     
                inOrder(root);
                break;
            }
            case POST_ORDER: {
   
     
                postOrder(root);
                break;
            }
            case PRE_CLUE_ORDER: {
   
     
                preClueOrder();
                break;
            }
            case IN_CLUE_ORDER: {
   
     
                inClueOrder();
                break;
            }
            case POST_CLUE_ORDER: {
   
     
                postClueOrder();
                break;
            }
            default:
                throw new RuntimeException("请输入合法的排序枚举常量");
        }
        return orderList;
    }

    //前序遍历查找
    private Node<T> preOrderSearch(Node<T> node, int id) {
   
     

        Node<T> resultNode = null;

        if (node != null) {
   
     

            Integer curId = node.getId();

            if (curId == id) {
   
     
                resultNode = node;
            } else if (node.getLeftNode() != null && curId > id && node.flagLeftNode != 1) {
   
     
                resultNode = preOrderSearch(node.getLeftNode(), id);
            } else if (node.getRightNode() != null && curId < id && node.flagRightNode != 1) {
   
     
                resultNode = preOrderSearch(node.getRightNode(), id);
            }
        }

        return resultNode;
    }

    public Node<T> preOrderSearch(int id) {
   
     
        return preOrderSearch(root, id);
    }

    //把排序树的所有线索去掉,返回原来的普通二叉排序树
    public boolean clearClues() {
   
     

        if (root != null) {
   
     
            root.clearClue(root);
            return true;
        } else {
   
     
            return false;
        }

    }

    //给二叉排序树进行添加线索 - 前序、后序、中序
    private void clues(TreeEnumeration treeEnumeration) {
   
     

        switch (treeEnumeration) {
   
     

            //pre.flagRightNode = 1;这句话特别关键,因为在节点中后继节点的更改需要等下一个元素进行变更
            case PRE_ORDER_CLUE: {
   
     
                root.preClues(root);
                pre.flagRightNode = 1;
                break;
            }
            case IN_ORDER_CLUE: {
   
     
                root.inClues(root);
                break;
            }
            case POST_ORDER_CLUE: {
   
     
                root.postClues(root);
                break;
            }
            default:
                throw new RuntimeException("请选择合适的树线索");
        }

        //将pre置空
        pre = null;

    }

    // 重写toString方法 -其实就是中序遍历输出
    @Override
    public String toString() {
   
     
        order(TreeEnumeration.IN_ORDER);
        return orderList.toString();
    }

    private class Node<T> {
   
     

        T data;
        Node<T> leftNode;
        Node<T> rightNode;

        //用于标记左节点是子树还是前驱节点 - 0表示是子树 1表示前驱节点
        int flagLeftNode = 0;

        //用于标记右节点是子树还是后继节点 - 0表示是子树 1表示后继节点
        int flagRightNode = 0;

        private void clearClue(Node<T> node) {
   
     

            if (node.flagLeftNode == 1) {
   
     
                node.leftNode = null;
                node.flagLeftNode = 0;
            }

            if (node.flagRightNode == 1) {
   
     
                node.rightNode = null;
                node.flagRightNode = 0;
            }
            if (node.leftNode != null) {
   
     
                clearClue(node.leftNode);
            }

            if (node.rightNode != null) {
   
     
                clearClue(node.rightNode);
            }

        }

        private void inClues(Node node) {
   
     

            if (node == null) {
   
     
                return;
            }

            //1. 线索左节点
            inClues(node.leftNode);
            //2. 线索当前节点
            //2.1 前驱节点
            if (node.leftNode == null && node.flagLeftNode == 0) {
   
     
                node.flagLeftNode = 1;
                node.leftNode = ThreadedBinaryTree.this.pre;
            }

            //2.2 后继节点
            if (pre != null && pre.rightNode == null) {
   
     
                pre.rightNode = node;
                pre.flagRightNode = 1;
            }

            //改变前驱节点
            ThreadedBinaryTree.this.pre = node;

            //3.线索右节点
            inClues(node.rightNode);

        }

        private void preClues(Node node) {
   
     
            if (node == null) {
   
     
                return;
            }

            Node curPre = ThreadedBinaryTree.this.pre;

            //1. 线索当前节点
            //1.1 前驱节点
            if (node.leftNode == null && node.flagLeftNode == 0) {
   
     
                node.flagLeftNode = 1;
                node.leftNode = ThreadedBinaryTree.this.pre;
            }

            //1.2 后继节点
            if (pre != null && pre.rightNode == null) {
   
     
                pre.rightNode = node;
                pre.flagRightNode = 1;
            }

            //改变前驱节点
            ThreadedBinaryTree.this.pre = node;

            //2. 线索左节点
            inClues(node.leftNode);

            //3.线索右节点
            inClues(node.rightNode);

        }

        private void postClues(Node node) {
   
     
            if (node == null) {
   
     
                return;
            }
            //1. 线索左节点
            postClues(node.leftNode);

            //2.线索右节点
            postClues(node.rightNode);
            //3. 线索当前节点
            //3.1 前驱节点
            if (node.leftNode == null && node.flagLeftNode == 0) {
   
     
                node.flagLeftNode = 1;
                node.leftNode = ThreadedBinaryTree.this.pre;
            }

            //3.2 后继节点
            if (pre != null && pre.rightNode == null) {
   
     
                pre.rightNode = node;
                pre.flagRightNode = 1;
            }

            //改变前驱节点
            ThreadedBinaryTree.this.pre = node;

        }

        public Integer getId() {
   
     
            Integer id = null;
            try {
   
     
                Field field = data.getClass().getDeclaredField("id");
                field.setAccessible(true);
                id = (Integer) field.get(data);
            } catch (Exception e) {
   
     
                e.printStackTrace();
            }
            return id;
        }

        public T getData() {
   
     
            return data;
        }

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

        public Node<T> getLeftNode() {
   
     
            return leftNode;
        }

        public void setLeftNode(Node<T> leftNode) {
   
     
            this.leftNode = leftNode;
        }

        public Node<T> getRightNode() {
   
     
            return rightNode;
        }

        public void setRightNode(Node<T> rightNode) {
   
     
            this.rightNode = rightNode;
        }

        //重写Node的toString方法 - 目的方便查看node内部变化
        @Override
        public String toString() {
   
     
            return "Node{" +
                    "data=" + data +
                    ", leftNode=" + (leftNode == null ? null : leftNode.getData()) +
                    ", rightNode=" + (rightNode == null ? null : rightNode.getData()) +
                    ", flagLeftNode=" + (flagLeftNode == 0 ? "普通左子树节点" : "前驱节点指针") +
                    ", flagRightNode=" + (flagRightNode == 0 ? "普通右子树节点" : "后继节点指针") +
                    '}';
        }
    }

}

 

5. 最优二叉(赫夫曼)树

叶子结点的带权路径长度和最小的二叉树

  • 思路
    1、 数组元素是升序排序;
    2、 从数组中弹出两个元素构成一个3节点的二叉树(这两个元素是叶子节点);
    3、 将根节点(步骤2的叶子节点权值和)的权值加入到数组中,并再次升序数组;
    4、 重复1,2,3直到数组中只有一个元素就停止循环;

流程图
 

Student.java

/**
 * @Classname Student
 * @Description
 * @Date 2022/4/11 19:21
 * @Created by lrc
 */
public class Student implements Comparable<Student> {
   
     

    Integer id;
    String name;
    Integer year;
    Integer weight;

    public Student() {
   
     
    }

    public Student(Integer id, String name, Integer year) {
   
     
        this.id = id;
        this.name = name;
        this.year = year;
        this.weight = year;
    }

    public Integer getId() {
   
     
        return id;
    }

    public void setId(Integer id) {
   
     
        this.id = id;
    }

    public String getName() {
   
     
        return name;
    }

    public void setName(String name) {
   
     
        this.name = name;
    }

    public Integer getYear() {
   
     
        return year;
    }

    public void setYear(Integer year) {
   
     
        this.year = year;
        this.weight = year;
    }

    @Override
    public String toString() {
   
     
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", year=" + year +
                '}';
    }

    
    
    @Override
    public int compareTo(Student stu) {
   
     

        Integer curYear = this.getYear();
        Integer comapareYear = stu.getYear();

        if(curYear > comapareYear) {
   
     
            return 1;
        }else if (curYear < comapareYear) {
   
     
            return -1;
        }else {
   
     
            return 0;
        }
    }
}

OptimalBinaryTree.java

public class OptimalBinaryTree<T> {
   
     

    //二叉树根节点 - 根据datas进行组建
    Node<T> root;

    //构造器传入的数据
    T[] datas;
    //传数组构造最优二叉树
    OptimalBinaryTree(T...datas) {
   
     
        T[] copyData = Arrays.copyOf(datas, datas.length);
        Arrays.sort(copyData);
        datas = copyData;

        createdOptimalBinaryTree(datas);

    }

    // 最优二叉树 - 中序遍历
    public String  inOrder() {
   
     

        StringBuilder sb = new StringBuilder();

        sb.append("[");

        //真正的中序遍历
        root.inOrder(root,sb);

        sb.replace(sb.lastIndexOf(", "), sb.length(), "");

        sb.append("]");

        return sb.toString();
    }
    // 最优二叉树 - 前序遍历
    public String  preOrder() {
   
     

        StringBuilder sb = new StringBuilder();

        sb.append("[");

        //真正的前序遍历
        root.preOrder(root,sb);

        sb.replace(sb.lastIndexOf(", "), sb.length(), "");

        sb.append("]");

        return sb.toString();
    }
    @Override
    public String toString() {
   
     
        return preOrder();
    }

    private boolean createdOptimalBinaryTree(T[] datas) {
   
     

        LinkedList<Node<T>> list = new LinkedList<>();

        boolean flag = false;

        Node<T> newNode;
        for(T data : datas) {
   
     
            newNode = new Node<>();
            newNode.setData(data);
            list.add( newNode );
        }
        while(true) {
   
     

            //弹出两个子节点,构成左右子树
            Node<T> lNode = list.pop();
            Node<T> rNode = list.pop();

            //父节点权重是上面两个子节点的权重
            Node<T> parNode = new Node<>();
            parNode.weight = lNode.weight + rNode.weight;
            parNode.leftNode = lNode;
            parNode.rightNode = rNode;

            //父节点必须往链表头添加 - 否则遇到weigth相同时,组件二叉树会混乱
            list.addFirst(parNode);
            Collections.sort(list);

            System.out.println("遍历" + list);

            //如果链表中只有一个元素,说明这个节点就是根节点
            if(list.size() == 1) {
   
     
                root = list.get(0);
                flag = true;
                break;
            }

        }
        return flag;
    }

    private class Node<T> implements Comparable<Node> {
   
     
        T data;
        Integer weight;
        Node<T> leftNode;
        Node<T> rightNode;

        public  void preOrder(Node node, StringBuilder sb) {
   
     
            sb.append(node.toString() + ", ");

            if(node.leftNode != null) {
   
     

                preOrder(node.leftNode, sb);
            }

            if(node.rightNode != null) {
   
     
                preOrder(node.rightNode, sb);
            }

        }
        public  void inOrder(Node node, StringBuilder sb) {
   
     

            if(node.leftNode != null) {
   
     

                inOrder(node.leftNode, sb);
            }

            sb.append(node.toString() + ", ");
            if(node.rightNode != null) {
   
     
                inOrder(node.rightNode, sb);
            }

        }

        public void setData(T data) {
   
     
            this.data = data;

            //节点的权重硬性规定为数据data内部的权重
            try {
   
     
                Field field = data.getClass().getDeclaredField("weight");
                field.setAccessible(true);

                weight = (Integer) field.get(data);
            } catch (Exception e) {
   
     
                e.printStackTrace();
            }

        }

        @Override
        public String toString() {
   
     
            return "Node{" +
                    "data=" + data +
                    ", weight=" + weight +
                    '}';
        }

        // node排序必须要实现这个函数 大于实参则大于0 小于则小于0 等于则等于0
        @Override
        public int compareTo(Node node) {
   
     
            return this.weight - node.weight;
        }
    }
    public static void main(String[] args) {
   
     
        //1. 数据准备 - 为什么写那么麻烦,主要是写熟悉一些数组、链表之间的转换函数
        Student student1 = new Student(1, "lrc", 8);
        Student student2 = new Student(2, "qcj", 2);
        Student student3 = new Student(3, "ert", 10);
        Student student4 = new Student(4, "bfg", 5);
        Student student5 = new Student(5, "ytu", 25);
        Student[] stu = {
   
     student1,student2,student3,student4,student5};
        // 2  5 8 10 25
        // 7 8 10 25
        // 10 15 25
        // 25 25
        // 50

        //2. 构造最优二叉树
        OptimalBinaryTree<Student> tree = new OptimalBinaryTree(stu);

        //3. 前序遍历二叉树
        System.out.println(tree);
    }
}

 

6. 平衡二叉树(AVL树)

1. AVL:是个发明者名字Adelson-Velsky-Landis Tree

2. 每个节点的左右子树的高度差不能大于1

Student.java

/**
 * @Classname Student
 * @Description
 * @Date 2022/4/11 19:21
 * @Created by lrc
 */
public class Student implements Comparable<Student> {
   
     

    Integer id;
    String name;
    Integer year;
    Integer weight;

    public Student() {
   
     
    }

    public Student(Integer id, String name, Integer year) {
   
     
        this.id = id;
        this.name = name;
        this.year = year;
        this.weight = year;
    }

    public Integer getId() {
   
     
        return id;
    }

    public void setId(Integer id) {
   
     
        this.id = id;
    }

    public String getName() {
   
     
        return name;
    }

    public void setName(String name) {
   
     
        this.name = name;
    }

    public Integer getYear() {
   
     
        return year;
    }

    public void setYear(Integer year) {
   
     
        this.year = year;
        this.weight = year;
    }

    @Override
    public String toString() {
   
     
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", year=" + year +
                '}';
    }

    @Override
    public int compareTo(Student stu) {
   
     

        Integer curId = this.getId();
        Integer comapareId = stu.getId();

        if(curId > comapareId) {
   
     
            return 1;
        }else if (curId < comapareId) {
   
     
            return -1;
        }else {
   
     
            return 0;
        }
    }

}

注意:测试千万别用相同ID号的Student类 - 相同节点实在是太难处理
BalancedBinaryTree.java

/**
 * @Classname BalancedBinaryTree
 * @Description
 * @Date 2022/4/15 11:05
 * @Created by lrc
 */
public class BalancedBinaryTree<T> {
   
     

    Node<T> root = null;

    BalancedBinaryTree() {
   
     
    }

    BalancedBinaryTree(List<T> datas) {
   
     
        for (T data : datas) {
   
     
            add(data);
        }

    }

    public static void main(String[] args) {
   
     

        //数据准备
        Student student1 = new Student(1, "lrc", 8);
        Student student2 = new Student(2, "qcj", 2);
        Student student3 = new Student(3, "ert", 10);
        Student student33 = new Student(3, "rwerwe", 14);
        Student student4 = new Student(4, "bfg", 5);
        Student student5 = new Student(5, "ytu", 25);
        Student student0 = new Student(0, "ytu", 25);
        Student[] stu = {
   
     student3, student2, student1, student4, student5, student33, student0};
        List<Student> stuList = new ArrayList<>(Arrays.asList(stu));
        //构造二叉树排序树
        BalancedBinaryTree tree = new BalancedBinaryTree(stuList);
        //前序遍历查看元素
       /* System.out.println(tree.preOrder());
        System.out.println("==================\n");*/
        //删除元素 - 被删节点无左右子树
        //tree.remove(student1);
        //删除元素 - 被删节点有左右子树
        //tree.remove(student3);

        //删除元素 - 被删节点无左右子树
  /*      tree.remove(student2);
        //前序遍历查看元素
        System.out.println(tree.preOrder());
        System.out.println("==================\n");*/
    }

    public void rightRotate() {
   
     
        root.rightRotate();
    }

    //前序遍历元素
    public String preOrder() {
   
     

        StringBuilder sb = new StringBuilder();
        root.preOrder(root, sb);
        return sb.toString();
    }

    //添加元素
    public void add(T data) {
   
     

        if (root == null) {
   
     
            root = new Node<T>();
            root.data = data;
        } else {
   
     
            root.add(data, root, null);
        }

        System.out.println(preOrder());
        System.out.println("===============\n");

    }

    //删除元素
    public boolean remove(T data) {
   
     

        boolean flag = root.remove(data);

        return flag;

    }

    protected class Node<T> {
   
     

        T data;
        Node<T> leftNode;
        Node<T> rightNode;

        //返回当前节点右子树的高度
        public int leftHeihgt() {
   
     
            if (leftNode == null) {
   
     
                return 0;
            }
            return leftNode.height();
        }

        //返回当前节点左子树的高度
        public int rightHeight() {
   
     

            if (rightNode == null) {
   
     
                return 0;
            }
            return rightNode.height();

        }
        //计算当前节点的树高
        public int height() {
   
     
            return Math.max((leftNode == null ? 0 : leftNode.height()) + 1, (rightNode == null ? 0 : rightNode.height()) + 1);

        }

        //当前节点左旋
        public boolean leftRotate() {
   
     

            //1. 生成新节点跟当前节点差不多一样的信息 - 更改一下右节点信息即可
            Node<T> newNode = new Node<>();
            newNode.data = this.data;
            newNode.leftNode = this.leftNode;
            newNode.rightNode = this.rightNode.leftNode;

            //2. 将根节点的信息由有右节点的信息取代,不过左节点是上面的新节点信息
            this.data = rightNode.data;
            this.rightNode = rightNode.rightNode;
            this.leftNode = newNode;

            return true;
        }

        //当前节点左旋
        public boolean rightRotate() {
   
     
//            System.out.println("发生右旋" + data);
            //1. 生成新节点跟当前节点差不多一样的信息 - 更改一下左节点信息即可
            Node<T> newNode = new Node<>();
            newNode.data = this.data;
            newNode.rightNode = this.rightNode;
            newNode.leftNode = this.leftNode.rightNode;

            //2. 将根节点的信息由有右节点的信息取代,不过右节点是上面的新节点信息
            this.data = leftNode.data;
            this.leftNode = this.leftNode.leftNode;
            this.rightNode = newNode;

            return true;
        }
        public void add(T data, Node<T> node, Node<T> parentNode) {
   
     

            //确定 data 与 node.data的关系
            Integer flag = node.compareTo(data);
            ;
            //如果 data 大于 nodeData
            if (flag <= 0) {
   
     

                if (node.rightNode == null) {
   
     
                    Node<T> dataNode = new Node<>();
                    dataNode.data = data;
                    node.rightNode = dataNode;

                } else {
   
     
                    add(data, node.rightNode, node);
                }

                如果 data 小于等于 nodeData  左节点添加
            } else {
   
     

                if (node.leftNode == null) {
   
     
                    Node<T> dataNode = new Node<>();
                    dataNode.data = data;
                    node.leftNode = dataNode;

                } else {
   
     
                    add(data, node.leftNode, node);
                }

            }

            //右旋
            if(this.leftHeihgt() - this.rightHeight() > 1) {
   
     

                if(parentNode.leftHeihgt() - parentNode.rightHeight() == 2) {
   
     
                    if(node.rightHeight() - node.leftHeihgt() == 1) {
   
     
                        node.leftRotate();
                    }
                    parentNode.rightRotate();
                }

                if(parentNode.leftHeihgt() - parentNode.rightHeight() == -2) {
   
     

                    if(node.leftHeihgt() - node.rightHeight() == 1) {
   
     
                        node.rightRotate();
                    }
                    parentNode.leftRotate();
                }

                if(parentNode.leftHeihgt() - parentNode.rightHeight() == 1) {
   
     

                  /*  if(node.rightHeight() - node.leftHeihgt() == 1) {
                        node.leftRotate();
                    }*/
                    this.rightRotate();
                }
                if(parentNode.leftHeihgt() - parentNode.rightHeight() == -1) {
   
     

                    if(node.leftHeihgt() - node.rightHeight() == 1) {
   
     
                        node.rightRotate();
                    }
                    parentNode.leftRotate();
                    this.rightRotate();
                }

            }
            //左旋
            if(this.rightHeight() - this.leftHeihgt() > 1) {
   
     

                if(parentNode.leftHeihgt() - parentNode.rightHeight() == 2) {
   
     
                    if(node.rightHeight() - node.leftHeihgt() == 1) {
   
     
                        node.leftRotate();
                    }
                    parentNode.rightRotate();
                }

                if(parentNode.leftHeihgt() - parentNode.rightHeight() == -2) {
   
     

                    if(node.leftHeihgt() - node.rightHeight() == 1) {
   
     
                        node.rightRotate();
                    }
                    parentNode.leftRotate();
                }

                if(parentNode.leftHeihgt() - parentNode.rightHeight() == 1) {
   
     

                  /*  if(node.rightHeight() - node.leftHeihgt() == 1) {
                        node.leftRotate();
                    }*/
                    if(node.rightHeight() - node.leftHeihgt() == 1) {
   
     
                        node.leftRotate();
                    }
                    parentNode.rightRotate();
                    this.leftRotate();
                }
                if(parentNode.leftHeihgt() - parentNode.rightHeight() == -1) {
   
     

                    if(node.leftHeihgt() - node.rightHeight() == 1) {
   
     
                        node.rightRotate();
                    }

                  this.leftRotate();

                }

            }

        }

        public boolean remove(T data) {
   
     

            Node<T> curNode = this;
            Node<T> curNodeParentNode = null;
            boolean isDeleted = false;
            while (true) {
   
     
                Integer flag = curNode.compareTo(data);

                //找不到被删除的元素
                if (curNode == null) {
   
     
                    break;
                }

                找到被删除的元素
                if (flag == 0) {
   
     

                    //确定被删除元素与其父元素之间的关系
                    Integer flag2 = 0;
                    if (curNodeParentNode != null) {
   
     
                        flag2 = curNodeParentNode.compareTo(curNode.data);
                    }
                    //被删除节点没有子节点
                    if (curNode.leftNode == null && curNode.rightNode == null) {
   
     
                        if (flag2 > 0) {
   
     
                            curNodeParentNode.leftNode = null;
                        } else {
   
     
                            curNodeParentNode.rightNode = null;
                        }

                        //被删除元素有左右子节点 - 被删除元素由其右子树替代
                    } else if (curNode.leftNode != null && curNode.rightNode != null) {
   
     

                        //1. 更换被删除元素的数据为右节点的数据
                        curNode.data = curNode.rightNode.data;
                        //2. 将被删除元素的右子树中进行挂载
                        Node<T> temp = curNode.rightNode.leftNode;
                        curNode.rightNode.leftNode = null;

                        Node<T> temp2 = curNode.leftNode;
                        while (true) {
   
     

                            if (temp2.rightNode == null) {
   
     
                                temp2.rightNode = temp;
                                break;
                            }
                            temp2 = temp2.rightNode;
                        }
                        //3. 完成删除
                        curNode.rightNode = curNode.rightNode.rightNode;
                        //被删除元素只有一个子节点
                    } else {
   
     

                        if (curNode.leftNode != null) {
   
     

                            curNode.data = curNode.leftNode.data;
                            curNode.rightNode = curNode.leftNode.rightNode;
                            curNode.leftNode = curNode.leftNode.leftNode;

                        } else {
   
     
                            curNode.data = curNode.rightNode.data;
                            curNode.leftNode = curNode.rightNode.leftNode;
                            curNode.rightNode = curNode.rightNode.rightNode;

                        }

                    }

                    isDeleted = true;
                    break;

                    //当前节点大于被删除的data
                } else if (flag > 0) {
   
     

                    curNodeParentNode = curNode;
                    curNode = curNode.leftNode;

                    //当前节点小于被删除的data
                } else {
   
     
                    curNodeParentNode = curNode;
                    curNode = curNode.rightNode;
                }

            }
            return true;
        }
        //前序遍历:中左右
        private void preOrder(Node<T> node, StringBuilder sb) {
   
     

            sb.append(node + "\n");
            if (node.leftNode != null) {
   
     
                preOrder(node.leftNode, sb);
            }

            if (node.rightNode != null) {
   
     
                preOrder(node.rightNode, sb);
            }

        }
        @Override
        public String toString() {
   
     
            return "Node{" +
                    "data=" + data +
                    '}';
        }
        //比较当前节点的data与实参的data大小关系
        public int compareTo(T data) {
   
     
            //确定 data 与 node.data的关系
            Integer flag = 0;
            try {
   
     
                Method compareTo = this.data.getClass().getDeclaredMethod("compareTo", this.data.getClass());

                flag = (Integer) compareTo.invoke(this.data, data);

            } catch (Exception e) {
   
     
                throw new RuntimeException("元素比较时发生异常,请检查代码");
            }

            return flag;
        }

    }
}

 

7. 多路查找树 - 多叉树

二叉树缺点

1、 二叉树需要加载到内存-数据很多,需要分多次访问硬盘读取这些数据进行组建二叉树;

2、 节点多,高度肯多高,高度高,节点遍历需要非常多次;

多路查找树分类

1、 B树、B-tree:每个节点都存储数据;

2-3树

2-3-4树

2、 B+树:只有叶子节点存储信息,叶子节点内元素有序、叶子节点间组成链表、非叶子节点只有导航的作用;

3、 B*树:B+树的变体,同级的节点使用链表连接;

7.1 B树 - 所有叶子节点必须在同一层

 

 

插入元素规则:2-3树为例