数据结构 -- 03 -- 二叉树

141 阅读3分钟

二叉树的定义: 树中结点度数不大于2的有序树

特性:

设当前结点序号(层序)为i

左孩子:i * 2 + 1;

右孩子:i * 2 + 2;

先序|中序, 先序|后序, 中序|后序, 层序|中序可以确定一个二叉树

结点

设计思路:

1.具备元素:数据域,左指针域,右指针域

通过左右指针(引用)将一颗树的结点进行连接

2.基本方法:类的构造方法和元素的set和get方法

public class TreeNode<E> {
    /**
     * data 节点元素值
     * lChild 左孩子
     * rChild 右孩子
     */
    private E data;
    private TreeNode<E> lChild;
    private TreeNode<E> rChild;
    
    public TreeNode() {
    }
    
    public TreeNode(E e) {
        this.data = e;
    }
    
    public TreeNode(E data, TreeNode<E> lChild, TreeNode<E> rChild) {
        this.data = data;
        this.lChild = lChild;
        this.rChild = rChild;
    }
    
    public E getData() {
        return data;
    }
    
    public void setData(E data) {
        this.data = data;
    }
    
    public TreeNode<E> getLChild() {
        return lChild;
    }
    
    public void setLChild(TreeNode<E> lChild) {
        this.lChild = lChild;
    }
    
    public TreeNode<E> getRChild() {
        return rChild;
    }
    
    public void setRChild(TreeNode<E> rChild) {
        this.rChild = rChild;
    }
}

接口:

设计思路:关于接口设计我觉得应该简洁,所以只包含一棵树的应有的基本方法

1.创建方法

2.插入方法

3.删除方法

4.求高度

5.求节点数

public interface BinaryTree<E> {
    /**
     * @param val 根节点
     * @param l 左子树
     * @param r 右子树
     * @Desription 手动建树
     */
    void create(E val, TreeNode<E> l, TreeNode<E> r);
    
    /**
     * @param array
     * @return TreeNode<E>
     * @Desription 自动将数组转化成完全二叉树
     */
    public TreeNode<E> buildTree(E[] array);
    
    /**
     * @param val
     * @param p
     * @Desription 将元素插入p的左结点,原先的左子树成为新结点的左子树
     */
    void insertL(E val, TreeNode<E> p);
    
    /**
     * @param val
     * @param p
     * @Desription 将元素插入p的右节点,原先的右子树成为新节点的右子树
     */
    void insertR(E val, TreeNode<E> p);
    
    /**
     * @param p
     * @return TreeNode<E>
     * @Desription 删除p的左子树
     */
    TreeNode<E> deleteL(TreeNode<E> p);
    
    /**
     * @param p
     * @return TreeNode<E>
     * @Desription 删除p的右子树
     */
    TreeNode<E> deleteR(TreeNode<E> p);
    
    /**
     * @param root
     * @param value
     * @return TreeNode<E>
     * @Desription  在root中查找值为value的结点
     */
    TreeNode<E> search(TreeNode<E> root, E value);
    
    /**
     * @param p
     * @return boolean
     * @Desription 判断是否是叶子结点
     */
    boolean isLeaf(TreeNode<E> p);
    
    /**
     * @param p
     * @return int
     * @Desription 求树的高度
     */
    int height(TreeNode<E> p);
    
    /**
     * @param p
     * @return int
     * @Desription 求结点数
     */
    int size(TreeNode<E> p);
}

实现类:

设计思路:基于实现接口的的基础上实现了如下方法

  1. 4种遍历方式 先 中 后 层

  2. 对一些递归结构进行优化,一般来说,相同的问题用递归和递推求解,在最坏的看似复杂度相同都是O(n),但是常系数还是不同的。

递归:实质上是使用了系统栈来进行遍历,在最坏情况下可能需要递归n层

递推:实质上也是用栈来进行遍历的,在最坏情况下可能有n个点入栈出栈

public class LinkBinaryTree<E> implements BinaryTree<E>{
    
    private TreeNode<E> root;
    
    private List<TreeNode<E>> nodeList = null;
    
    public LinkBinaryTree(){
        root = null;
    }
    
    public LinkBinaryTree(E val){
        this(val, null, null);
    }
    
    public LinkBinaryTree(E val, TreeNode<E> lp, TreeNode<E> rp){
        TreeNode<E> p = new TreeNode<E>(val, lp, rp);
        root = p;
    }
    
    public TreeNode<E> getRoot(){
        return root;
    }
    
    public boolean isEmpty(){
        return root == null;
    }
    
    @Override
    public void create(E val, TreeNode<E> l, TreeNode<E> r) {
        TreeNode<E> p = new TreeNode<>(val, l, r);
        root = p;
    }
    
    @Override
    public TreeNode<E> buildTree(E[] array) {
        nodeList = new LinkedList<>();
        for(int i = 0 ; i < array.length; i++){
            nodeList.add(new TreeNode(array[i]));
        }
        for(int i = 0; i < array.length; i++){
            nodeList.get(i).setLChild(nodeList.get(i * 2 + 1));
            nodeList.get(i).setRChild(nodeList.get(i * 2 + 2));
        }
        //特判,最后一个父节点可能没有右孩子
        int index = array.length / 2 - 1;
        nodeList.get(index).setLChild(nodeList.get(index * 2 + 1));
        if(array.length % 2 == 0){
            nodeList.get(index).setRChild(nodeList.get(index * 2 + 2));
        }
        root = nodeList.get(0);
        return root;
    }
    
    
    @Override
    public void insertL(E val, TreeNode<E> p) {
        TreeNode<E> newNode = new TreeNode<E>(val);
        TreeNode<E> oldLChild = p.getLChild();
        p.setLChild(newNode);
        newNode.setLChild(oldLChild);
    }
    
    @Override
    public void insertR(E val, TreeNode<E> p) {
        TreeNode<E> newNode = new TreeNode<>(val);
        TreeNode<E> oldRChild = p.getRChild();
        p.setRChild(newNode);
        newNode.setRChild(oldRChild);
    }
    
    @Override
    public TreeNode<E> deleteL(TreeNode<E> p) {
        if(p == null){
            return null;
        }else{
            TreeNode<E> lChild = p.getLChild();
            p.setLChild(null);
            return lChild;
        }
    }
    
    @Override
    public TreeNode<E> deleteR(TreeNode<E> p) {
        if(p == null){
            return null;
        }else {
            TreeNode<E> rChild = p.getRChild();
            p.setRChild(null);
            return rChild;
        }
    }
    
    @Override
    public TreeNode<E> search(TreeNode<E> root, E value) {
        LinkedList<TreeNode<E>> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            TreeNode<E> treeNode = q.poll();
            if(treeNode.getLChild() != null){
                q.add(treeNode.getLChild());
            }
            if(treeNode.getRChild() != null){
                q.add(treeNode.getRChild());
            }
            if(treeNode.getData() == value){
                return treeNode;
            }
        }
        return null;
    }
    
    @Override
    public boolean isLeaf(TreeNode<E> p) {
        if(p == null){
            return false;
        }
        LinkedList<TreeNode<E>> q = new LinkedList<>();
        q.add(p);
        while(q.isEmpty()){
            TreeNode<E> treeNode = q.poll();
            if(treeNode.getLChild() != null){
                q.add(treeNode.getLChild());
            }
            if(treeNode.getRChild() != null){
                q.add(treeNode.getRChild());
            }
            if(treeNode.getData().equals(p.getData()) && treeNode.getLChild() == null && treeNode.getRChild() == null){
                return true;
            }
        }
        return false;
    }
    
    @Override
    public int height(TreeNode<E> p) {
        if(p == null){
            return 0;
        }else{
            int i = height(p.getLChild()) + 1;
            int j = height(p.getRChild()) + 1;
            return Math.max(i, j);
        }
    }
    
    @Override
    public int size(TreeNode<E> p) {
        if(p == null){
            return 0;
        }else{
            return size(p.getLChild()) + size(p.getRChild()) + 1;
        }
    }
    
    
    public void preOrder(TreeNode<E> p){
        if(p != null){
            System.out.print(p.getData() + " ");
            preOrder(p.getLChild());
            preOrder(p.getRChild());
        }
    }
    
    public void nonRecPreOrder(TreeNode<E> p){
        if(p != null){
            Stack<TreeNode<E>> stack = new Stack<>();
            TreeNode<E> treeNode = p;
            while(treeNode != null || !stack.isEmpty()){
                //存在左结点,则将左结点入栈
                if(treeNode != null){
                    stack.push(treeNode);
                    System.out.print(stack.peek().getData() + " ");
                    treeNode = treeNode.getLChild();
                }else{
                    treeNode = stack.pop();
                    treeNode = treeNode.getRChild();
                }
            }
        }
    }
    
    public void inOrder(TreeNode<E> p){
        if(p != null){
            inOrder(p.getLChild());
            System.out.print(p.getData() + " ");
            inOrder(p.getRChild());
        }
    }
    
    public void nonRecInOrder(TreeNode<E> p){
        if(p != null){
            Stack<TreeNode<E>> stack = new Stack<>();
            TreeNode<E> treeNode = p;
            while(treeNode != null || !stack.isEmpty()){
                if(treeNode != null){
                    stack.push(treeNode);
                    treeNode = treeNode.getLChild();
                }else{
                    treeNode = stack.pop();
                    System.out.print(treeNode.getData() + " ");
                    treeNode = treeNode.getRChild();
                }
            }
        }
    }

    public void postOrder(TreeNode<E> p){
        if(p != null){
            postOrder(p.getLChild());
            postOrder(p.getRChild());
            System.out.print(p.getData() + " ");
        }
    }
    
    public void nonRecPostOrder(TreeNode<E> p){
        if(p != null){
            Stack<TreeNode<E>> stack = new Stack<>();
            TreeNode<E> treeNode = p;
            TreeNode<E> preNode = null;
            while(treeNode != null || !stack.isEmpty()){
                while(treeNode != null){
                    stack.push(treeNode);
                    treeNode = treeNode.getLChild();
                }
                treeNode = stack.peek();
                if(treeNode.getRChild() == null || treeNode.getRChild() == preNode){
                    treeNode = stack.pop();
                    System.out.print(treeNode.getData() + " ");
                    preNode = treeNode;
                    treeNode = null;
                }else{
                    treeNode = treeNode.getRChild();
                }
            }
        }
    }
    
    public void levelOrder(TreeNode<E> p){
        if(p != null){
            LinkedList<TreeNode<E>> q = new LinkedList<>();
            q.add(p);
            while(!q.isEmpty()){
                TreeNode<E> treeNode = q.poll();
                System.out.print(treeNode.getData() + " ");
                if(treeNode.getLChild() != null){
                    q.add(treeNode.getLChild());
                }
                if(treeNode.getRChild() != null){
                    q.add(treeNode.getRChild());
                }
            }
        }
    }
}

参考文章:

java实现二叉树以及实例 - 让你一生残梦 - 博客园 (cnblogs.com)

www.cnblogs.com/CherishFX/p…