二叉树

通过前序遍历二维数组生成二叉树

ublic class BinaryTree {
    private TreeNode root = null;//根结点

    public BinaryTree() {
        root = new TreeNode(1, "A");
    }

    /**
     * 构建二叉树
     * A
     * B       C
     * D      E        F
     */
    private void createBinaryTree() {
        TreeNode nodeB = new TreeNode(2, "B");
        TreeNode nodeC = new TreeNode(3, "C");
        TreeNode nodeD = new TreeNode(4, "D");
        TreeNode nodeE = new TreeNode(5, "E");
        TreeNode nodeF = new TreeNode(6, "F");
        root.leftNodes = nodeB;
        root.rightNodes = nodeC;
        nodeB.leftNodes = nodeD;
        nodeB.rightNodes = nodeE;
        nodeC.rightNodes = nodeF;
    }

    public int getHeight() {
        return getHeight(root);
    }

    /**
     * 获得二叉树的高度或深度
     */
    private int getHeight(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int i = getHeight(root.leftNodes);
        int j = getHeight(root.rightNodes);
        return (i < j) ? j + 1 : i + 1;
    }

    /**
     * 获取二叉树的结点数
     */
    private int getSize() {
        return getSize(root);
    }

    private int getSize(TreeNode root) {
        if (root == null) {
            return 0;
        } else {
            //遍历所有的结点
            return 1 + getSize(root.leftNodes) + getSize(root.rightNodes);
        }

    }

    /**
     * 前序遍历——非迭代
     */
    public void nonRecOrder(TreeNode node) {//前序遍历:A B D E C F
        if (node == null) {
            return;
        } else {
            //根左右,也就是先把栈弹出
            Stack<TreeNode> stack = new Stack<>();
            stack.push(root);
            while (!stack.isEmpty()) {
                //出栈和进栈
                TreeNode n = stack.pop();
                //压入子结点
                System.out.println("nonRecOrder data" + n.getData());
                //先进后出
                if (n.rightNodes != null) {
                    stack.push(n.rightNodes);

                }
                if (n.leftNodes != null) {
                    stack.push(n.leftNodes);
                }
            }

        }
    }

    /**
     * 前序遍历——迭代
     * A
     * B       C
     * D      E        F
     */
    public void preOrder(TreeNode node) {//前序遍历:A B D E C F
        if (node == null) {
            return;
        } else {
            //根然后左然后右
            System.out.println(node.data);
            preOrder(node.leftNodes);
            preOrder(node.rightNodes);
        }
    }

    /**
     * 中序遍历——迭代
     * A
     * B       C
     * D      E        F
     */
    public void midOrder(TreeNode node) {//D B E A C F
        if (node == null) {
            return;
        } else {
            //左然后根然后右
            midOrder(node.leftNodes);
            System.out.println(node.data);
            midOrder(node.rightNodes);
        }
    }

    /**
     * 后序遍历——迭代
     * A
     * B       C
     * D      E        F
     */
    public void postOrder(TreeNode node) {//D E B F C A
        if (node == null) {
            return;
        } else {
            //左然后右然后根
            postOrder(node.leftNodes);
            postOrder(node.rightNodes);
            System.out.println(node.data);
        }
    }

    /**
     * 通过前序遍历二维数组生成二叉树
     * A
     * B                 C
     * D          E       #          F
     * #      #   #     #            #      #
     * <p>
     * ABD##E##C#F##
     */
    public void createBinaryTreePre(ArrayList<String> data) {
        createBinaryTree(data.size(), data);
    }

    private TreeNode createBinaryTree(int size, ArrayList<String> data) {
        if (data.size() == 0) {//如果数组的大小等于0,则返回null
            return null;
        }
        String d = data.get(0);
        int index = size - data.size();
        TreeNode node;
        if (d.equals("#")) {
            node = null;
            data.remove(0);
            return node;
        }
        node = new TreeNode(index, d);
        if (index == 0) {
            //创建根结点
            root = node;
        }
        data.remove(0);//从数据中移除第一个
        node.leftNodes = createBinaryTree(size, data);
        node.rightNodes = createBinaryTree(size, data);
        return node;
    }

    public class TreeNode {
        private int index;//当前结点的层次
        private String data;//当前结点的数据
        private TreeNode leftNodes;//左结点
        private TreeNode rightNodes;//右结点

        public TreeNode(int index, String data) {
            this.index = index;
            this.data = data;
        }

        public String getData() {
            return data;
        }

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

    @Test
    public void main() {
        BinaryTree binaryTree = new BinaryTree();
        /*binaryTree.createBinaryTree();
        int height = binaryTree.getHeight();
        System.out.println(height);
        int size = binaryTree.getSize();
        System.out.println(size);*/
//        binaryTree.preOrder(binaryTree.root);
//        binaryTree.midOrder(binaryTree.root);
//        binaryTree.postOrder(binaryTree.root);
        //binaryTree.nonRecOrder(binaryTree.root);
        ArrayList<String> data = new ArrayList<>();
        String[] arrays = new String[]{"A", "B", "D", "#", "#", "E", "#", "#", "C", "#", "F", "#", "#"};
        for (String array : arrays) {
            data.add(array);
        }
        binaryTree.createBinaryTreePre(data);
        binaryTree.preOrder(binaryTree.root);
    }


}

树、森林、二叉树的转换

树转换为二叉树

  • 1.加线。在所有兄弟结点之间加一条连线。
  • 2.去线。对树中每个结点,只保留它与第一个孩子结点的连线,删除它与其他孩 子结点之间的连线。
  • 3.层次调整。以树的根结点为轴心,将整棵树顺时针旋转一定的角度,使之结构 层次分明。注意第一个孩子是二叉树结点的左孩子,兄弟转换过来的孩子是结 点的右孩子。

image.png

森林转化为二叉树

  • 1.把每个树转换为二叉树。
  • 2.第一棵二又树不动,从第二棵二叉树开始,依次把后一棵二叉树的根结点作为 前一棵二叉树的根结点的右孩子,用线连接起来。当所有的二叉树连接起来后 就得到了由森林转换来的二叉树。

image.png

二叉树转换为树

  • 1.加线。若某结点的左孩子结点存在,则将这个左孩子的右孩子结点、右孩子的 右孩子结点、右孩子的右孩子的右孩子结点…哈,反正就是左孩子的n 个 右孩子结点都作为此结点的孩子。将该结点与这些右孩子结点用线连接起来。
  • 2.去线。删 除原 二 叉 树 中 所 有结点 与 其 右 孩 子 结点 的连 线。
  • 3.层次调整。使之结构层次分明。

image.png

二叉树转换为森林
判断一棵二叉树能够转换成一棵树还是森林,标准很简单,那就是只要看这棵二
叉树的根结点有没有右孩子,有就是森林,没有就是一棵树。那么如果是转换成森
林,
步骤如下:

  • 1.从根结点开始,若右孩子存在,则把与右孩子结点的连线删除,再查看分离后 的二叉树,若右孩子存在,则连线删除…直到所有右孩子连线都删除为 止,得到分离的二叉树。
  • 2.再将 每 棵 分离后 的二 叉树转换 为树 即 可。

image.png

赫夫曼树

image.png
image.png

####查找二叉树:根结点的右结点一定比根结点大,左结点一定比根结点小

通过数组生成查找二叉树

public class SearchBinaryTree {
    private TreeNode root;

    public SearchBinaryTree() {

    }

    @Test
    public void main() {
        SearchBinaryTree serchBinaryTree = new SearchBinaryTree();
        int[] datas = new int[]{15, 10, 50, 30, 70, 65, 90};
        for (int data : datas) {
            serchBinaryTree.put(data);
        }
        serchBinaryTree.midOrder(serchBinaryTree.root);

    }

    /**
     * 中序遍历——迭代
     */
    public void midOrder(TreeNode node) {
        if (node == null) {
            return;
        } else {
            //左然后根然后右
            midOrder(node.leftChild);
            System.out.println(node.data);
            midOrder(node.rightChild);
        }
    }


    public TreeNode put(int data) {
        //根结点不会变,相对的父结点,当前结点
        TreeNode parent = null;//父结点
        TreeNode node = null;//当前结点
        //1.首先判断当前根结点是否为空
        if (root == null) {//根布局为空
            node = new TreeNode(0, data);
            root = node;
        }
        //2.不为空的时候每次从根结点开始遍历
        node = root;
        while (node != null) {
            parent=node;//最终目的是获得父结点
            //3.判断你传入的值与根结点的值进行判断,如果大于切换到右边的结点,小于切换到左结点
            if (node.data < data) {//右边
                node = node.rightChild;
            } else if (node.data > data) {//左边
                node = node.leftChild;
            }else {
                return node;//相等的话跳出整个put方法
            }

        }
        //4.获得切换的结点之后,放值
        node=new TreeNode(0,data);//当前结点为空的时候new一个节点
        if(data>parent.data){//放到右边
            parent.rightChild=node;
        }else{
            parent.leftChild=node;
        }
        return node;
    }

    public class TreeNode {
        private int data;
        private int key;
        private TreeNode leftChild;
        private TreeNode rightChild;
        private TreeNode parent;

        public TreeNode(int key, int data) {
            this.data = data;
            this.key = key;
            leftChild = null;
            rightChild = null;
            parent = null;
        }
    }
}

这里写图片描述
新增结点删除

 /**
     * 删除二叉树某个结点
     */
    public void deleteNote(int data) throws Exception {
        //查找获取到当前的结点
        TreeNode node = searchNode(data);
        if (node == null) {//查找到结点为空
            throw new Exception("改结点无法找到");
        } else {
            //删除该结点
            delete(node);
        }
    }

    /**
     * 删除该结点
     */
    private void delete(TreeNode node) throws Exception {
        if (node == null) {//查找到结点为空
            throw new Exception("改结点无法找到");
        } else {
            //1.被删除的结点无孩子(如上图的65)
            TreeNode parent = node.parent;
            //首先判断删除的结点位于哪边
            if (node.leftChild == null && node.rightChild == null) {
                if (parent.leftChild == node) {//父结点大于子结点,则删除左结点
                    parent.leftChild = null;
                } else {
                    parent.rightChild = null;
                }
                return;
            }
            //2.被删除的结点有左结点无右结点(如上图的10)
            if (node.leftChild != null && node.rightChild == null) {
                //首先判断当前的结点位于父布局的什么位置
                if (parent.leftChild == node) {//位于左结点
                    parent.leftChild = node.leftChild;
                } else {
                    parent.rightChild = node.leftChild;
                }
                return;
            }
            //3.被删除的结点无左结点有右结点(如上图的90)
            if (node.rightChild != null && node.leftChild == null) {
                //首先判断当前的结点位于父布局的什么位置
                if (parent.rightChild == node) {//位于右结点
                    parent.rightChild = node.rightChild;
                } else {
                    parent.leftChild = node.rightChild;
                }
                return;
            }
            //4.被删除的结点有左结点也有右结点(如上图的30),此时需要找个后继者(未新增(红色的是新增)30后面的最小的应该是45)
            //寻找下一个后继者
            TreeNode next = getNextNode(node);//如此时是45
            delete(next);//删除45这个结点
            node.data = next.data;//当前结点数据改变为下一个结点的数据
        }
    }

    /**
     * 寻找下一个后继者
     */
    private TreeNode getNextNode(TreeNode node) {
        //后继者一定比当前节点大,所以肯定在当前节点的右边寻找(比如新增红线45,此时后继者应该是40)
        if (node == null) {
            return null;
        } else {
            if (node.rightChild != null) {//右结点不为空
                return getMinTreeNode(node.rightChild);
            } else {//比如49的后继者是50此时应该怎么做
                TreeNode parent = node.parent;
                while (parent != null && parent.rightChild == node) {
                    node = parent;
                    parent = node.parent;
                }
                return parent;
            }
        }

    }

    //后来寻找的全是右边最小的结点
    private TreeNode getMinTreeNode(TreeNode node) {
        if (node == null) {
            return null;
        } else {
            while (node.leftChild != null) {
                node = node.leftChild;
            }
        }
        return node;
    }

    /**
     * 查找到二叉树
     */
    private TreeNode searchNode(int data) {
        //从根结点开始找
        TreeNode node = root;
        if (node == null) {
            return null;
        }
        while (node != null && node.data != data) {
            if (node.data > data) {//左结点
                node = node.leftChild;
            } else if (node.data < data) {
                node = node.rightChild;
            }
        }
        return node;
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值