数据结构:二叉树的递归和非递归遍历(先序、中序、后序、层次)

最近在学习二叉树,第一次写博客,总结一下,方便以后复习。

先序遍历(根-左-右)
递归算法
public void preorder(BinaryNode<T> node){    //先根次序遍历二叉树

    if (node!=null){
        System.out.print(node.data.toString()+" ");
        preorder(node.left);
        preorder(node.right);
    }

}
非递归算法

借助一个栈实现

public void preorderTraverse(BinaryNode node){//非递归中根次序遍历二叉树,借助栈
    if (node==null)
        System.out.println("该树为空树");
    Stack stack=new Stack();
    while (!stack.isEmpty()||node!=null){   //栈非空或者该结点非空
        if (node!=null){            //若该结点非空,则访问并压栈
            System.out.print(node.data.toString()+" ");
            stack.push(node);
            node=node.left;
        }
        else {      //当左边的孩子访问完
            node=(BinaryNode) stack.pop();//把左孩子结点弹出
            node=node.right;//访问右边的
        }
    }

}
中序遍历(左-根-右)
递归算法
public void inorder(BinaryNode<T> node){    //中根次序遍历二叉树.递归法

    if (node!=null){
        inorder(node.left);
        System.out.print(node.data.toString()+" ");
        inorder(node.right);
    }

}
非递归算法
public void inorderTraverse(BinaryNode node){//非递归中根次序遍历二叉树,借助栈
    if (node==null)
        System.out.println("该树为空树");
    Stack stack=new Stack();
    while (!stack.isEmpty()||node!=null){
        if (node!=null){        //把左边的结点都压栈,根结点最后放在栈底
            stack.push(node);       
            node=node.left;
        }
        else {
            node=(BinaryNode) stack.pop();  //接着弹栈并打印该结点
            System.out.print(node.data.toString()+" ");
            node=node.right;    //访问右孩子
        }
    }

}
后序遍历(左-右-根)
递归算法
public void postOrder(BinaryNode<T> p)       //后根次序遍历以p结点为根的子二叉树,递归方法
{
    if (p!=null)
    {
        postOrder(p.left);
        postOrder(p.right);
        System.out.print(p.data.toString()+" ");
    }
}
非递归算法

1、这里和先序以及中序的不太一样,不能简单的换一下顺序,后序遍历先访问左孩子然后是右孩子,两者是兄弟结点,没有必然的联系,所以我第一个想到的是借助两个栈,每次把根结点压入原栈中,然后再弹出放到辅助栈中,接着把左右孩子压入原栈中,再弹出,直到原栈空为止,再打印出辅助栈的元素,就是后序序列。

public void postorderTraverse(){//实现二叉树后根次序遍历的非递归算法,借助两个栈实现
    Stack stack=new Stack();
    Stack stackHelp=new Stack();//辅助栈
    if (this.root==null)
        return;
    BinaryNode node=this.root;
    stack.push(node);//把根结点压入栈中
    while (!stack.isEmpty()){       //栈非空时
        node=(BinaryNode)stack.pop();//弹出根结点,并把根节点弹入辅助栈
        stackHelp.push(node);
        if (node.left!=null)//把左右孩子结点压入栈中
            stack.push(node.left);
        if (node.right!=null)
            stack.push(node.right);
    }
    while (!stackHelp.isEmpty()){//最后把辅助栈的元素全部弹出
        System.out.print(((BinaryNode) stackHelp.pop()).data.toString()+" ");
    }

}

2、两个栈进行遍历,如果数据量大,会造成存储浪费,时间效率也会降低,下面的代码借助一个栈实现,用front标记其在后根次序的前驱结点。(这里Stack封装类没有get()方法,要创建一个LinkedStack类来获取栈顶元素,或者可以用一个变量把元素弹栈保存后再压栈)

public void postOrderTraverse()                        //后根次序遍历二叉树的非递归算法
{
    System.out.print("后根次序遍历(非递归):  ");
    LinkedStack<BinaryNode<T>> stack = new LinkedStack<BinaryNode<T>>();
    BinaryNode<T> p=this.root, front=null;
    while (p!=null || !stack.isEmpty())                //p非空或栈非空时
        if (p!=null)
        {
            stack.push(p);                             //p结点入栈
            p=p.left;                                  //进入左子树
        }
        else                                           //p为空且栈非空时
        {
            p=stack.get();                             //从左子树返回p结点,p结点不出栈
            if (p.right!=null && p.right!=front)       //p有右孩子,且右孩子没被访问过
            {
                p = p.right;                           //进入右子树
                stack.push(p);
                p=p.left;                              //向左走
            }
            else
            {
                p=stack.pop();                         //从右子树返回p结点,p结点出栈
                System.out.println(p.data+"的所有祖先结点是:"+stack.toString());
                front = p;                             //front是p在后根遍历次序下的前驱结点
                p=null; 
            }
        }
    System.out.println();
}    
层次遍历(每一层地访问)

非递归用队列实现,类似于广度优先搜索

public void levelOrder(){   //层序遍历,非递归
    System.out.print("层序遍历二叉树:");
    Queue<BinaryNode> queue = new LinkedList<BinaryNode>(); //LinkedList类实现了Queue接口
    BinaryNode<T> p=this.root;
    while (p!=null){
        System.out.print(p.data.toString()+" ");//访问当前结点
        if (p.left!=null)
            queue.offer(p.left);  //p的左孩子入队,add方法也可以入队,但失败时会抛出异常
        if (p.right!=null)
            queue.offer(p.right); //p的有孩子入队
        p=queue.poll();     //p指向出队结点,若队列空,则返回null
    }
    System.out.println();
}
二叉树的结点类
class BinaryNode<T extends Comparable<? super T>>{  // T继承Comparable类
    public T data;
    public BinaryNode<T> left;
    public BinaryNode<T> right;
    public BinaryNode(T data,BinaryNode<T> left,BinaryNode<T> right){
        this.data=data;
        this.left=left;
        this.right=right;
    }
    public BinaryNode(T data){
        this(data,null,null);
    }
    public String toString(){
        return this.data.toString();
    }
    public boolean isLeaf(){
        return this.left==null && this.right==null;
    }
}

以上源码均经过测试没有错误,用笔画画图会更好理解,如果有错误的欢迎在评论区指正。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值