typedef struct NodeType{
int data;
struct NodeType* left;
struct NodeType* right;
NodeType(){left = NULL;right = NULL;};
}Node;
const int MAX = 100;
Node* stack[MAX];
int top = -1;
int tag[MAX];
1 前序遍历
从根节点开始的所有的左结点依次入栈,然后从root的左子树的左叶子结点开始回溯,那么此左叶子结点一定没有左子结点,可能会有右子结点。该回溯节点出栈后,将它的右子结点当作根结点,重复上述动作。
void PreOrder(Node* root)
{
while (NULL != root ||
top >= 0) {
while (NULL != root) {
cout << root->data << endl;
top++;
stack[top] = root;
root = root->left;
}
//从root的左子树的左叶子节点开始回溯
if (top >= 0) {
Node* cur = stack[top];
top--;//回溯完后即出栈
root = cur->right;
}
}
}
2 中序遍历
与前序遍历基本一样,root表示需要入栈的根节点,当root为NULL,并且栈为空时,结束遍历。即所有的树节点都已经入栈过,并且最后都通过回溯的方式出栈了,则表示遍历结束。
void InOrder(Node* root)
{
//所有的节点都是先将其左子树的根节点入栈,然后从叶子节点开始回溯,回溯完叶子节点后入栈该叶子节点的右子树。如果该叶子节点的右子树为NULL,则继续回溯该叶子节点的父节点。
while (NULL != root ||
top >= 0) {
while (NULL != root) {
top++;
stack[top] = root;
root = root->left;
}
//从root的左子树的左叶子节点开始回溯
if (top >=0) {
Node* cur = stack[top];
cout << cur->data << endl;
top--;//回溯完后即出栈
root = cur->right;
}
}
}
3 后序遍历
从根节点开始的所有的左结点依次入栈,然后将最后一个入栈的左子结点开始回溯。但是入栈的这些左子结点都会被回溯两次。一次是从左子结点返回,一次是从右子结点返回。第一次回溯到该结点不能出栈,必须要先访问其右子结点(可以看作一个根结点,重复上述访问步骤),等到其右子树访问完了后再次回溯到该左子结点时,才能真正出栈。
void PostOrder(Node* root)
{
while (NULL != root ||
top >= 0) {
while (NULL != root) {
top++;
stack[top] = root;
tag[top] = 0;//默认root的右节点没有访问过(算法保证回溯到root时,则它的左节点一定是访问过的)
root = root->left;
}
//从roo的t左子树的左叶子节点开始回溯
if (top >= 0) {
Node* cur = stack[top];
if (1 == tag[top]) {
cout << cur->data << endl;
top--;//第二次回溯到该节点后出栈
} else {
//第一回溯到该节点暂时不出栈
root = cur->right;
tag[top] = 1;//标识root的右节点已经访问过
}
}
}
}