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

版权声明:本文为博主原创文章,转载请注明出处 https://github.com/baiiu https://blog.csdn.net/u014099894/article/details/72638380

前言

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

二叉树表示

结点表示,构造二叉树

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;
        }
    }
}


参考:
二叉树的非递归遍历
二叉树遍历之非递归算法

猜你喜欢

转载自blog.csdn.net/u014099894/article/details/72638380