数据结构——树(3):二叉树的前中后层序遍历,Morris遍历比较试验

二叉树有多种遍历方法,按照遍历的顺序分前序,中序,后序,层序,具体内容,不详述到处都是。按是否递归分为递归和非递归。另外还有巧妙的Morris遍历法。

今天做一实验来比较它们的效率:

构建二叉树类

public class BinTree {

    public int data;
    public BinTree left;
    public BinTree right;

    public BinTree(){

    }
    public BinTree(int data){
        this.data=data;
    }

    ......

}

创建二叉树方法

    //根据数组创建完全二叉树
    public static BinTree createTree(int[] arr){
        int count=0;
        int length=arr.length;
        BinTree root=new BinTree(arr[count++]);
        LinkedList<BinTree> queue=new LinkedList<BinTree>();
        queue.add(root);

        while(count<length){
            BinTree lastNode=queue.poll();
            if(count<length){
                lastNode.left=new BinTree(arr[count++]);
                queue.add(lastNode.left);
            }
            if(count<length){
                lastNode.right=new BinTree(arr[count++]);
                queue.add(lastNode.right);
            }
        }
        return root;
    } 

递归前序遍历

    //前序遍历,返回数列
    public ArrayList<Integer> preorderTraverse(){
        BinTree root=this;
        ArrayList<Integer> list=new ArrayList<Integer>();

        list.add(root.data);

        if(root.left!=null){
            list.addAll(root.left.preorderTraverse());
        }
        if(root.right!=null){
            list.addAll(root.right.preorderTraverse());
        }
        return list;
    }

递归中序遍历

    //中序遍历,返回数列
    public ArrayList<Integer> midorderTraverse(){
        BinTree root=this;

        ArrayList<Integer> list=new ArrayList<Integer>();

        if(root.left!=null){
            list.addAll(root.left.midorderTraverse());
        }
        list.add(root.data);
        if(root.right!=null){
            list.addAll(root.right.midorderTraverse());
        }

        return list;
    }

递归后序遍历

    //后序遍历返回数列
    public ArrayList<Integer> afterorderTraverse(){
        BinTree root=this;
        ArrayList<Integer> list=new ArrayList<Integer>();
        if(root.left!=null){
            list.addAll(root.left.afterorderTraverse());
        }
        if(root.right!=null){
            list.addAll(root.right.afterorderTraverse());
        }
        list.add(root.data);
        return list;
    }

非递归前序遍历

    public ArrayList<Integer> preorderTraverse2(){

        BinTree node=this;
        ArrayList<Integer> list=new ArrayList<Integer>();
        Stack<BinTree> s = new Stack<BinTree>();    

        while (node != null || !s.empty()) {    
            while (node != null) {
                list.add(node.data);
                s.push(node);    
                node = node.left;    
            }    
            if (!s.empty()) {    
                node = s.pop();    
                node = node.right;    
            }    
        } 

        return list;
    }

非递归中序遍历

    public ArrayList<Integer> midorderTraverse2(){
        BinTree node =this;
        ArrayList<Integer> list =new ArrayList<Integer>();
        Stack<BinTree> s=new Stack<BinTree>();

        while(node!=null||!s.isEmpty()){
            while(node!=null){
                s.push(node);
                node=node.left;
            }
            if(!s.empty()){
                node=s.pop();
                list.add(node.data);
                node=node.right;
            }
        }
        return list;
    }

非递归后序遍历

    public ArrayList<Integer> afterorderTraverse2(){
        BinTree node =this;
        ArrayList<Integer> list =new ArrayList<Integer>();
        Stack<BinTree> s=new Stack<BinTree>();

        Stack<Integer> s2 = new Stack<Integer>();    
        Integer i = new Integer(1);    
        while (node!= null || !s.empty()) {    
            while (node != null) {    
                s.push(node);    
                s2.push(new Integer(0));    
                node = node.left;    
            }    
            while (!s.empty() && s2.peek().equals(i)) {    
                s2.pop();    
                list.add(s.pop().data);
            }    

            if (!s.empty()) {    
                s2.pop();    
                s2.push(new Integer(1));    
                node = s.peek();    
                node = node.right;    
            }    
        } 
        return list;
    }

非递归层序遍历

    public ArrayList<Integer> levelTraverse() {

        BinTree root=this;
        LinkedList<BinTree> queue = new LinkedList<BinTree>();  
        ArrayList<Integer> list=new ArrayList<Integer>();
        BinTree current = null;  
        queue.add(root);//将根节点入队  
        while(!queue.isEmpty())  
        {  
            current = queue.poll();//出队队头元素并访问  
            list.add(current.data);
            if(current.left != null)//如果当前节点的左节点不为空入队  
            {  
                queue.add(current.left);  
            }  
            if(current.right != null)//如果当前节点的右节点不为空,把右节点入队  
            {  
                queue.add(current.right);  
            }  
        }  
        return list;
    }  

Morris中序遍历

    public ArrayList<Integer> MorrisTraverse() {  
        ArrayList<Integer> list = new ArrayList<Integer>();  
        BinTree root=this;

        BinTree node = root;  
        while(node != null) {  
            if(node.left == null) {  
                list.add(node.data);  
                node = node.right;  
            } else {  
                BinTree tmp = node.left;  
                while(tmp.right != null && tmp.right != node)  
                    tmp = tmp.right;  
                if(tmp.right == null) {  
                    tmp.right = node;  //找到当前节点的前驱节点  
                    node = node.left;  
                } else {  
                    list.add(node.data);  
                    tmp.right = null;  //恢复二叉树  
                    node = node.right;  
                }  
            }  
        }  
        return list;  
    }

测试

    public static void main(String[] args){
        //创建一个二叉树
        int[] arr=new int[10000];
        for(int i=0;i<arr.length;i++){
            arr[i]=i;
        }
        BinTree tree=BinTree.createTree(arr);

        //创建一个线性表存储遍历结果
        ArrayList<Integer> list=new ArrayList<Integer>();

        //起始时间计时
        long start;
        long end;

        //统计每种方法的总时间
        long time1,time2,time3,time4,time5,time6,time7,time8;
        time1=0;
        time2=0;
        time3=0;
        time4=0;
        time5=0;
        time6=0;
        time7=0;
        time8=0;

        for(int i=0;i<100;i++){
            //递归前序
        start = System.nanoTime();
        list=tree.preorderTraverse();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time1+=(end-start);
            //递归中序遍历
        start = System.nanoTime();
        list=tree.midorderTraverse();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time2+=(end-start);

        //递归后序
        start = System.nanoTime();
        list=tree.afterorderTraverse();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time3+=(end-start);

        //非递归前序
        start = System.nanoTime();
        list=tree.preorderTraverse2();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time4+=(end-start);

        //非递归中序
        start = System.nanoTime();
        list=tree.midorderTraverse2();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time5+=(end-start);

        //非递归后序
        start = System.nanoTime();
        list=tree.afterorderTraverse2();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time6+=(end-start);

        //非递归层序
        start = System.nanoTime();
        list=tree.levelTraverse();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time7+=(end-start);

        //Morris中序遍历
        start = System.nanoTime();
        list=tree.MorrisTraverse();
        //System.out.println(list.toString());
        end = System.nanoTime();
        //System.out.println(end-start);
        time8+=(end-start);
        }

        System.out.println(time1);
        System.out.println(time2);
        System.out.println(time3);
        System.out.println(time4);
        System.out.println(time5);
        System.out.println(time6);
        System.out.println(time7);
        System.out.println(time8);
    }

可以通过改变数组的大小,和循环的次数来观看算法的性能是否稳定,按照10000个元素,循环100次有以下输出结果:

递归前序:   588550392
递归中序:   798815444
递归后序:   859625367
非递归前序: 177709179
非递归中序: 191600347
非递归后序: 449614968
非递归层序: 265552014
Morris:   149713899

反复试验,结果基本稳定,效率排序与二叉树元素数量有关,在各个二叉树元素数量,Morris算法都最快,其次是非递归前序和非递归中序,两者各有胜负,层序再次,递归后序遍历最慢。非递归方法普遍比递归方法快。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值