算法 二叉树遍历 递归和非递归

前言

本篇文章介绍二叉树的几种遍历方法:前序遍历、中序遍历、后序遍历和层序遍历。
包含递归和非递归遍历。

二叉树表示

结点表示,构造二叉树

public class BiNode {
    public String data;
    public BiNode lChild;
    public BiNode rChild;

    public BiNode(String data) {
        this.data = data;
    }
}

1. 前序遍历(根左右)

// 递归
static void preOrderRe(BiNode tree) {
    if (tree == null) return;

    System.out.print(tree.data);
    preOrderRe(tree.lChild);
    preOrderRe(tree.rChild);
}

// 非递归遍历,使用栈
static void preOrder(BiNode tree) {
    if (tree == null) return;

    Stack<BiNode> stack = new Stack<>();
    stack.push(tree);

    while (!stack.empty()) {
        BiNode node = stack.pop();
        System.out.print(node.data);

        if (node.rChild != null) {
            stack.push(node.rChild);
        }

        if (node.lChild != null) {
            stack.push(node.lChild);
        }
    }
}

// 非递归遍历,先存储所有左子结点,回溯取右结点
static void preOrder2(BiNode tree) {
    if (tree == null) return;

    Stack<BiNode> stack = new Stack<>();

    while (tree != null || !stack.empty()) {
        if (tree != null) {
            //遍历完左子树,全部存入栈内
            System.out.print(tree.data);//打印根节点
            stack.push(tree);
            tree = tree.lChild;
        } else {
            // 左节点到底了,回溯取右节点
            tree = stack.pop();
            tree = tree.rChild;
        }
    }
}

2. 中序遍历(左根右)

static void inOrderRe(BiNode tree) {
    if (tree == null) return;


    inOrderRe(tree.lChild);
    System.out.print(tree.data);
    inOrderRe(tree.rChild);
}

static void inOrder(BiNode tree) {
    if (tree == null) return;

    Stack<BiNode> stack = new Stack<>();

    while (tree != null || !stack.isEmpty()) {
        if (tree != null) {
            stack.push(tree);
            tree = tree.lChild;
        } else {
            BiNode pop = stack.pop();
            System.out.print(pop.data);
            tree = pop.rChild;
        }
    }
}

3. 后序遍历(左右根)

static void postOrderRe(BiNode tree) {
    if (tree == null) return;

    postOrderRe(tree.lChild);
    postOrderRe(tree.rChild);
    System.out.print(tree.data);
}

/*
    要保证根结点在左孩子和右孩子访问之后才能访问,因此对于任一结点P,先将其入栈。
    如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或者右孩子,但是其左孩子和右孩子都已被访问过了,则同样可以直接访问该结点。
    若非上述两种情况,则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
 */
static void postOrder(BiNode tree) {
    if (tree == null) return;

    Stack<BiNode> stack = new Stack<>();
    stack.push(tree);

    BiNode pre = null;

    //push时候按照根右左入栈
    while (!stack.empty()) {
        BiNode cur = stack.peek();

        if ((cur.lChild == null && cur.rChild == null) ||
                (pre != null && (pre == cur.rChild || pre == cur.lChild))) {
            //左右结点都是空 || 左右结点都被访问过(先判断右结点)

            System.out.print(cur.data);
            stack.pop();
            pre = cur;
        } else {

            if (cur.rChild != null) {
                stack.push(cur.rChild);
            }
            if (cur.lChild != null) {
                stack.push(cur.lChild);
            }
        }

    }
}

//用两个栈
static void postOrder2(BiNode tree) {
    if (tree == null) return;

    Stack<BiNode> stack = new Stack<>();
    Stack<BiNode> output = new Stack<>();

    stack.push(tree);

    //output按照根右左入栈,stack按照根左右入栈
    while (!stack.empty()) {
        BiNode pop = stack.pop();
        output.push(pop);

        if (pop.lChild != null) {
            stack.push(pop.lChild);
        }
        if (pop.rChild != null) {
            stack.push(pop.rChild);
        }
    }

    while (!output.empty()) {
        System.out.print(output.pop().data);
    }
}

4. 层序遍历

// 使用队列,一端进、一端出
static void levelOrder(BiNode tree) {
    if (tree == null) return;

    Queue<BiNode> queue = new LinkedList<>();

    int nodesInCurrentLevel = 1, nodesInNextLevel = 0;
    queue.offer(tree);

    while (!queue.isEmpty()) {
        BiNode node = queue.poll();
        --nodesInCurrentLevel;

        if (node != null) {
            System.out.print(node);
			
			if(node.lChild != null){
				queue.offer(node.lChild);
				++nodesInNextLevel;
			}
			
			if(node.rChild != null){
	            queue.offer(node.rChild);
	            ++nodesInNextLevel;
			}
        }

        if (nodesInCurrentLevel == 0) {
            nodesInCurrentLevel = nodesInNextLevel;
            nodesInNextLevel = 0;
        }
    }
}

> 参考: [二叉树的非递归遍历](http://www.cnblogs.com/dolphin0520/archive/2011/08/25/2153720.html) [二叉树遍历之非递归算法](http://blog.csdn.net/sgbfblog/article/details/7773103)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

baiiu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值