【算法导论学习-22】二叉树专题1:一般二叉树的实现和常用处理函数

一、   一般二叉树的实现

这里的一般二叉树指的是没有任何特殊要求的二叉树。

1.     二叉树的建立

步骤1:设计二叉树类的结点,包括左右结点和卫星数据

public class BinaryTreeNode<T> {
    private BinaryTreeNode<T> leftChild,rightChild;
    private T data;
    public BinaryTreeNode() {
        // TODO 自动生成的构造函数存根
        leftChild=rightChild=null;
    }
    public BinaryTreeNode(T data) {
        // TODO 自动生成的构造函数存根
        leftChild=rightChild=null;
        this.data=data;
    }
    public T getData() {
        return data;
    }
    public BinaryTreeNode<T> getLeftChild() {
        return leftChild;
    }
    public BinaryTreeNode<T> getRightChild() {
        return rightChild;
    }
    public void setLeftChild(BinaryTreeNode<T> leftChild) {
        this.leftChild = leftChild;
    }
    public void setRightChild(BinaryTreeNode<T> rightChild) {
        this.rightChild = rightChild;
    }
}

步骤2:设计最简单的二叉树类

public class BinaryTree<T> {
    BinaryTreeNode<T> root;
    public BinaryTree(BinaryTreeNode<T> root) {
        // TODO 自动生成的构造函数存根
        this.root = root;
    }
}

步骤3:建立二叉树

public class BinaryTreeTest {
 
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
       BinaryTreeNode<String> a = new BinaryTreeNode<String>("A");
       BinaryTreeNode<String> b = new BinaryTreeNode<String>("B");
       BinaryTreeNode<String> c = new BinaryTreeNode<String>("C");
       BinaryTreeNode<String> d = new BinaryTreeNode<String>("D");
       BinaryTreeNode<String> e = new BinaryTreeNode<String>("E");
       BinaryTreeNode<String> f = new BinaryTreeNode<String>("F");
       a.setLeftChild(b);
       a.setRightChild(c);
       b.setLeftChild(d);
       b.setRightChild(e);
       c.setLeftChild(f);
       BinaryTree<String> binaryTree=new BinaryTree<>(a);
    }
}

binaryTree即为一颗这样的二叉树。但是没有任何处理它的函数,包括前序、后续、中序的输出。下面就这个二叉树来讨论这些函数。



2.     二叉树的遍历

1)   分层遍历(广度优先)

参考:http://www.cnblogs.com/miloyip/archive/2010/05/12/binary_tree_traversal.html

《编程之美》给出的方案

    /* 树的广度优先搜索(分层输出)*/
    public void PrintNodeByLevel () {
        ArrayList<BinaryTreeNode<T>> list=new ArrayList<>();
        if (root==null) {
            return;
        }
        list.add(root);
        int cur=0;
        while (cur<list.size()) {
            int lastofCurrentLevel=list.size();
            while (cur<lastofCurrentLevel) {
                BinaryTreeNode<T> tempNode=list.get(cur);
                System.out.print(tempNode.getData());
                if (tempNode.getLeftChild()!=null) {
                    list.add(tempNode.getLeftChild());
                }
                if (tempNode.getRightChild()!=null) {
                    list.add(tempNode.getRightChild());
                }
                cur++;
            }
            System.out.println();
        }  
    }

  算法解释:使用辅助队列list,cur为游标,last为list的长度。外层循环是控制level的,内层循环是某一个level的内部遍历。

2)   前序遍历

方案一:递归

 /*☆较简单——前序遍历递归过程 */
    private void recursePreOrder(BinaryTreeNode<T> root) {
        if (root == null)
            return;
        System.out.print(root.getData());
        if (root.getLeftChild() != null)
            recursePreOrder(root.getLeftChild());
        if (root.getRightChild() != null)
            recursePreOrder(root.getRightChild());
}
方案二:辅助的 stack 的方式 (《算法导论》 248 10.4-3
/* 较简单——使用1个辅助stack方式进行前序遍历 */
    private void PreOrderUsingStack(BinaryTreeNode<T> root) {
        BinaryTreeNode<T> temp=root;
        Stack<BinaryTreeNode<T>> stack=new Stack<>();
        while (!stack.isEmpty()||temp!=null) {
            if (temp!=null) {
                 System.out.print(temp.getData());
                 stack.push(temp);
                 temp=temp.getLeftChild();
            }else {
                temp=stack.pop();
                temp=temp.getRightChild();
            }
        }
    }
3)   中序遍历

思路:《算法导论》288页

 /* ☆较简单——中遍历递归过程 */
    private void recurseInOrder(BinaryTreeNode<T> root) {
        if (root == null)
            return;
        if (root.getLeftChild() != null)
            recurseInOrder(root.getLeftChild());
        System.out.print(root.getData());
        if (root.getRightChild() != null)
            recurseInOrder(root.getRightChild());
    }

4)   后序遍历

参考:http://hi.baidu.com/8qianyun/item/bf61f3dc390a7df493a97434

关键点:前序遍历如果的法则如果改成先遍历右边再遍历左边,将这种算法命名为“left前序遍历”算法。则“left前序遍历”结果为:acfbed。“left前序遍历”结果倒序即为后续遍历:debfca

思路:使用1个辅助stack的方式实现“left前序遍历”算法,用另一个辅助stack进行倒序输出。

/* 较复杂——使用2个辅助stack方式进行后序遍历 */
    public void PostOrderUsingStack() {
        BinaryTreeNode<T> temp=root;
        Stack<BinaryTreeNode<T>> stack=new Stack<>();
        Stack<BinaryTreeNode<T>> outPutStack=new Stack<>();
        while (!stack.isEmpty()||temp!=null) {
            if (temp!=null) {
                stack.push(temp);
                outPutStack.push(temp);
                temp=temp.getRightChild();
            }else {
                temp=stack.pop();
                temp=temp.getLeftChild();
            }
        }
        System.out.print("\n使用2个辅助stack进行后续输出:");
        while (!outPutStack.isEmpty()) {
            System.out.print(outPutStack.pop().getData());
        }

3.     其他常用处理函数

1)   求二叉树中的节点个数

思路:递归的方案,二叉树节点个数 = 左子树节点个数 + 右子树节点个数 + 1

 private int getNodeNumber(BinaryTreeNode<T> root) {
        if (root==null) {
            return 0;
        }else {
            return 1+getNodeNumber(root.getLeftChild())+getNodeNumber(root.getRightChild());
        }
    }
    public int getNodeNumber() {
        return getNodeNumber(root);
    }

2)   求二叉树深度

思路:二叉树的深度 = max(左子树深度,右子树深度) + 1

 /* 获得树的高度,递归过程 */
    private int getTreeDeep(BinaryTreeNode<T> root) {
        if (root == null) {
            return 0;
        }
        if (root.getLeftChild() == null && root.getRightChild() == null) {
            return 1;
        }
        return 1 + Math.max(getTreeDeep(root.getLeftChild()),
                getTreeDeep(root.getRightChild()));
    }
 
    public int getFianlTreeDeep() {
        return getTreeDeep(root);
    }

3)  二叉树第K层的节点个数

  思路:如果二叉树不为空且k>1,返回左子树中k-1层的节点个数与右子树k-1层节点个数之和。当然也可以用广度优先算法来计算第k层的节点个数。

 /* 递归方案获取第K层的节点个数*/
    public int getNumberofKthLevel(BinaryTreeNode<T> node,int k) {
        if (node==null||k<1) {
            return 0;
        }
        if (k==1) {
            return 1;
        }
        int leftNumber=getNumberofKthLevel(node.getLeftChild(),k-1);
        int rightNumber=getNumberofKthLevel(node.getRightChild(), k-1);
        return leftNumber+rightNumber;
    }
    public int getNumberofKthLevel(int k) {
        return getNumberofKthLevel(root, k);
    }
4)   获取叶子节点个数

  思路:如果二叉树不为空,且左右子树不同时为空,返回左子树中叶子节点个数加上右子树中叶子节点个数

/* 递归方案获取叶子节点个数*/
    public int getLeafNumber(BinaryTreeNode<T> node) {
        if (node==null) {
            return 0;  
        }
        if (node.getRightChild()==null&&node.getLeftChild()==null) {
            return 1;
        }
        int leftNumber=getLeafNumber(node.getLeftChild());
        int rightNumber=getLeafNumber(node.getRightChild());
        return leftNumber+rightNumber;
       
    }
    public int getLeafNumber() {
        return getLeafNumber(root);
    }
5)   判断两颗二叉树是否结构相同

思路:如果两棵二叉树都不为空,如果对应的左子树和右子树都同构返回真,其他返回假

  /* 递归方案比较两个二叉树是否结构相同*/
    public static boolean isSameOfTreeStucture(BinaryTreeNode<String> tree1Root,BinaryTreeNode<String> tree2Root) {
        if (tree1Root==null&&tree2Root==null) {
            return true;
        }else if (tree1Root==null||tree2Root==null) {
            return false;
        }
        boolean leftFlag=isSameOfTreeStucture(tree1Root.getLeftChild(), tree2Root.getLeftChild());
        boolean rightFlag=isSameOfTreeStucture(tree1Root.getRightChild(), tree2Root.getRightChild());
        return leftFlag&&rightFlag;
    }
}
6)   求二叉树的镜像

思路:如果二叉树不为空,求左子树和右子树的镜像,然后交换左子树和右子树

 /* 递归方案进行镜像反转*/
    public static BinaryTreeNode<String> getMirrorTree(BinaryTreeNode<String> node) {
        if (node==null) {
            return null;
        }
        BinaryTreeNode<String> leftMirror=getMirrorTree(node.getLeftChild());
        BinaryTreeNode<String> rightMirror=getMirrorTree(node.getRightChild());
        node.setLeftChild(rightMirror);
        node.setRightChild(leftMirror);
        return node;
    }
****************************************************************************************************************************************************************************************
【百度的面试题】输出二叉树第 m 层的第 k 个节点值(m, k 均从 0 开始计数)
利用分层输出来统计到第m层的第k个结点。

 

/* 树的广度优先搜索(分层输出)*/
    public void PrintNodeByLevelAndNumber (int k,int m) {
        ArrayList<BinaryTreeNode<T>> list=new ArrayList<>();
        if (root==null) {
            return;
        }
        list.add(root);
        int cur=0;
        int level=0;
        int pointer=0;
        while (cur<list.size()) {
            int lastofCurrentLevel=list.size();
            level++;
            while (cur<lastofCurrentLevel) {
                BinaryTreeNode<T> tempNode=list.get(cur);
                if (level==k) {
                    pointer++;
                }
                if (level==k&&pointer==m) {
                    System.out.print(tempNode.getData());
                }
                if (tempNode.getLeftChild()!=null) {
                    list.add(tempNode.getLeftChild());
                }
                if (tempNode.getRightChild()!=null) {
                    list.add(tempNode.getRightChild());
                }
                cur++;
            }
            System.out.println();
        }  
    }













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值