廢話不多說,分別給出二叉樹的先序、中序和後序遍歷的遞歸和非遞歸算法。
先序遍歷-遞歸算法:
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() &¤t) {
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 ;
}