二叉樹的先序、中序和後序遍歷(總結)

廢話不多說,分別給出二叉樹的先序、中序和後序遍歷的遞歸和非遞歸算法。
先序遍歷-遞歸算法:

class Node {
public:
    int value;
    Node *left;
    Node *right;
};

class Visit {
public:
    void operator() (Node * node) const {
        cout<<" "<<node->value<<" "<<endl;
    }
};

void preOrderVisitTree(Node* root, Visit &visit) {
    if (!root) {
        return ;
    }
    visit(root);
    preOrderVisitTree(root->left,visit);
    preOrderVisitTree(root->right,visit);
    return ;
}

先序遍歷-非遞歸算法:
思想:用一個輔助棧記錄,比較簡單這裏就不廢話了。
No code say what?

void preOrderVisitTreeEx(Node *root, Visit &visit) {
    if (!root) {
        return ;
    }

    stack<Node*> S;
    Node *current = root;
    while (!S.empty()) {
        if (current->right) {
            S.push(current->left);
        }
        if (current->left) {
            S.push(current->right);
        }

        visit(current);
        current = S.top();
        S.pop();
    }

    return;
}

中序遍歷-遞歸算法:

void inOrderVisitTree(Node* root, Visit &visit) {
    if (!root) {
        return ;
    }

    preOrderVisitTree(root->left,visit);
    visit(root);
    preOrderVisitTree(root->right,visit);
    return ;
}

中序遍歷-非遞歸算法:
思想:一直把樹的左邊界壓入棧,當壓無可壓時,彈出一個節點,然後訪問其右子樹。再一直壓樹的左邊界…
No code say what?

void inOrderVisitTreeEx(Node *root, Visit & visit) {
    if (!root) {
        return ;
    }

    stack<Node*> S;
    Node *current = root;
    while (!S.empty() && !current) {
        if (current->left) {
            S.push(current->left);
            current = current->left;
            continue;
        }
        current = S.top();
        S.pop();
        visit(current);
        current = current->right;
    }

    return ;
}

後序遍歷-遞歸算法:

void posOrderVisitTree(Node* root, Visit &visit) {
    if (!root) {
        return ;
    }

    preOrderVisitTree(root->left,visit);
    preOrderVisitTree(root->right,visit);
    visit(root);
    return ;
}

後序遍歷-非遞歸法
思想:後序遍歷非遞歸算法稍微複雜點,下面給出了兩種方法,這裏說幾句。
methold1:把後序順序的節點序導入到一個棧中,然後依次遍歷這個棧。有兩個棧就很容易搞定這個事,假設最後待遍歷的棧爲Stack2,另一個棧爲Stack1,首先入棧root到stack1,stack1彈出節點A,節點A並壓入stack2,把A的左右兒子壓入stack1,以此循環一直到stack1空爲止。此時以此彈出stack2就可得到樹的後序遍歷序列。
No code say what?

void posOrderVisitTreeEx(Node* root, Visit &visit) {
    if (!root) {
        return ;
    }

    stack<Node*> S1;
    stack<Node*> S2;
    Node *current = NULL;
    S1.push(root);
    while (!S1.empty() &&current) {
        current = S1.top();
        S1.pop();
        S2.push(current);
        if (current->left) {
            S1.push(current->left);
        }
        if (current->right) {
            S1.push(current->right);
        }

    }

    while (!S2.empty()) {
        visit(S2.top());
        S2.pop();
    }

    return ;
}

methold2:
不用兩個棧,用一個棧,這個思路比較繞。
1.首先把頭節點入棧;
2.然後獲得當前棧頂元素(不彈出);
3.判斷棧頂元素左子樹是否爲空,
若不爲空,且其左右子樹都未訪問過,就把此節點左子樹頭節點入棧;
4.判斷棧頂元素右子樹是否爲空,
若不爲空,且其右子樹未被訪問過,就把此節點的右子樹頭節點入棧。
No code say what?

void posOrderVisitTreeExt(Node* root, Visit &visit) {
    if (!root) {
        return ;
    }

    stack<Node*> S;
    Node *h = NULL;
    Node *c = NULL;
    S.push(root);
    while (!S.empty()) {
        c = S.top();
        if (!c->left && c->left != h && c->right != h) {
            S.push(c->left);
        } else if (!c->right && c->right != h) {
            S.push(c->right);
        } else {
            visit(h);
            h = c;
        }
    }

    return ;
}
發佈了56 篇原創文章 · 獲贊 13 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章