二叉树的中序遍历

二叉树是一种树形的数据结构,而树形结构应用非常广泛,例如我们操作系统中的文件系统。那么我们对树形结构的使用大多数都是基于树的遍历的,掌握了二叉树的基本遍历思想,对于其他普通的树进行遍历那就是小case。
下面进入我们今天的正题吧。

对树形结构进行遍历实际上就是找到树中所有结点的一个线性序列。对于二叉树我们一般有4种遍历方法:

  • 先(前)序遍历
  • 中序遍历
  • 后序遍历
  • 层序遍历

中序遍历的算法如下:
如果当前访问结点为空,则什么都不做,直接返回
如果不为空,则

  1. 访问左子树
  2. 访问当前结点
  3. 访问右子树

由此可见,二叉树的中序遍历非常适合使用递归。从算法中我们可以看到(实际上从树的定义中也可以看出对树的遍历适合用递归),递归的结束条件就是当前访问结点为空结点。那么我们很容易的给出递归的代码:

public List<Integer> solution1(TreeNode root) {
		//如果当前访问结点为空,那么直接返回
        if(root == null)
            return new ArrayList<Integer>();
        List<Integer> res = new ArrayList();
        //访问左子树
        res.addAll(solution1(root.left));
        //访问当前结点
        res.add(root.val);
        //访问右子树
        res.addAll(solution1(root.right));
        return res;
    }

递归的代码非常容易理解,那么能不能采用非递归的方法呢?答案是可以的。但是采用非递归遍历就有一个难点:假如我们访问完了某个结点的左子树,那么我们该怎么退回到该结点呢?(因为在二叉树的二叉链表结构中是没有指向双亲结点的指针的)这就要求在访问左子树之前,我们得先把该结点保存起来,要不然找不到回来的路就尴尬了。我们用栈作为存储结构保存该结点的祖先,那么就有了非递归的代码:

public List<Integer> solution2(TreeNode root) {
        List<Integer> res = new ArrayList();
        //初始化一个栈
        Stack<TreeNode> s = new Stack();
        //先将根结点入栈,栈中的结点的意义是当前返回结点的祖先,
        //同时也是没有被访问过的结点
        s.push(root);
        //栈不空的时候也就是还有结点没有被访问到
        while(!s.empty()){
        	//把当前栈顶的左子树入栈,因为中序遍历时访问的第一个
        	//结点一定是该树中最左下边的结点
            while(s.peek() != null) s.push(s.peek().left);
            //空指针出栈
            s.pop();
            //这里还要进行栈是否为空的判断,因为
            //如果在这时对所有结点访问完毕那么栈就空了
            if(!s.empty()) {
            	//访问当前结点
                TreeNode p = s.pop();
                res.add(p.val);
                //该访问右子树了,也是一样的过程,需要找到
                //右子树的最左下的结点
                s.push(p.right);
            }
        }
        return res;
    }

还有一种非递归的方式,思想都是一样的:

public List<Integer> solution3(TreeNode root) {
        List<Integer> res = new ArrayList();
        Stack<TreeNode> s = new Stack();
        TreeNode p = root;
        while(p != null || !s.empty()) {
        	//找到最左下的结点
            if(p != null) {
                s.push(p);
                p = p.left;
            }
            else{
            	//访问当前结点
                p = s.pop();
                res.add(p.val);
                //访问右子树
                p = p.right;
            }
        }
        return res;
    }

ok,以上就是对二叉树进行中序遍历的三种方式,你get到了嘛?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值