1. 程式人生 > >樹的三種遍歷方式原始碼(遞迴與非遞迴)

樹的三種遍歷方式原始碼(遞迴與非遞迴)

在面試的時候,我們會經常被問到樹的三種遍歷,也就是前序遍歷、中序遍歷和後序遍歷。

所謂前序遍歷,就是先訪問根節點,再左,再右。命名方式就是根據根節點是在哪訪問的去定義的。下面我們先用Java實現三種遍歷的遞迴,是非常的簡單。

樹的前序遍歷:

public void recursiveProOrder(Node root) {
    if (root != null) {
        System.out.print(root.value);
        if (root.left != null) {
            recursivePostOrder(root.left);
        }
        if
(root.right != null) { recursivePostOrder(root.right); } } }

樹的中序遍歷:

public void recursiveInOrder(Node root) {
    if (root != null) {
        if (root.left != null) {
            recursiveInOrder(root.left);
        }
        System.out.print(root.value);
        if (root.right != null
) { recursiveInOrder(root.right); } } }

樹的後序遍歷:

public void recursivePostOrder(Node root) {
    if (root != null) {
        if (root.left != null) {
            recursivePostOrder(root.left);
        }
        if (root.right != null) {
            recursivePostOrder(root.right);
        }
        System.out
.print(root.value); } }

下面介紹如何用非遞迴的方式進行遍歷。所謂遞迴,其實在語言的底層層面上來講,也是用棧來實現的,因此,要把遞迴的演算法改為非遞迴,我們都可以考慮用棧來實現怎麼操作。其中,前序和中序的非遞迴實現都比較容易,需要重點理解的是樹的後序遍歷的非遞迴實現。下面直接給出程式碼。

樹的前序遍歷(非遞迴):

public void preOrder(Node node)
{
    Stack<Node> stack = new Stack<>();
    while(node != null || !stack.empty())
    {
        while(node != null)
        {
            System.out.print(node.element + " ");
            stack.push(node);
            node = node.left;
        }    //while迴圈負責掃描所有當前結點,並判斷有沒有左子樹
        if(!stack.empty())    //當stack為空的時候,說明沒有左子樹了
        {
            node = stack.pop();
            node = node.right;
        }
    }
}

樹的中序遍歷(非遞迴):

public void midOrder1(Node node)
{
    Stack<Node> stack = new Stack<>();
    while(node != null || !stack.empty())
    {
        while (node != null)
        {
            stack.push(node);
            node = node.left;
        }    //先壓到樹的最左下角的左子樹
        if(!stack.empty())
        {
            node = stack.pop();
            System.out.print(node.element + " ");
            node = node.right;
        }
    }
}

樹的後序遍歷(非遞迴):

public void postOrder(Node node){
        if(node==null)
            return;
        Stack<Node> s = new Stack<Node>();

        Node curNode; //當前訪問的結點
        Node lastVisitNode; //上次訪問的結點
        curNode = node;
        lastVisitNode = null;

        //把currentNode移到左子樹的最下邊
        while(curNode!=null){
            s.push(curNode);
            curNode = curNode.getLchild();
        }
        while(!s.empty()){
            curNode = s.pop();  //彈出棧頂元素
            //一個根節點被訪問的前提是:無右子樹或右子樹已被訪問過
            if(curNode.getRchild() != null
                && curNode.getRchild() != lastVisitNode){
                //根節點再次入棧
                s.push(curNode);
                //進入右子樹,且可肯定右子樹一定不為空
                curNode = curNode.getRchild();
                while(curNode != null){
                    //再走到右子樹的最左邊
                    s.push(curNode);
                    curNode = curNode.getLchild();
                }
            }else{
                //訪問
                System.out.println(curNode.getData());
                //修改最近被訪問的節點
                lastVisitNode = curNode;
            }
        } //while
}

對於後序遍歷的非遞迴實現,需要好好理解。