二叉树的建立与之前的相同,就不多做阐述。非递归的前序中序遍历,主要思想就是把二叉树上的每一个结点进行入栈操作,然后输出结点的值,出栈。但在其中前序和中序的顺序不一样,但大体的思路是相同的。后序遍历相比前序中序更为复杂。
都是沿着左分支访问,直到左分支为空时,再依次对栈中节点的右分支进行处理。(遵循从左至右的遍历原则,体现深度优先搜索的思想)
前序遍历:每个结点只进栈一次,在进栈前访问结点
中序遍历:每个结点进栈一次,在出栈时进行访问
后序遍历:每个结点进栈两次,在第二次出栈时访问节点
前序遍历
以根节点开始,每次都进行输出,然后不断地遍历结点的左子树,将遍历到的左子树入栈,直到结点的左子树为空,跳出此while循环后判断栈是否为空,把栈顶结点记录下来后出栈,遍历记录的节点的右子树。外层while循环进行控制,当遇到出栈后继续遍历左子树等一系列操作。
void PreOrder(BiNode* root)
{
stack<BiNode*>s;
while (root != NULL || !s.empty())
{
while (root != NULL)
{
cout << root->data;
s.push(root);
root = root->lchild;
}
if (!s.empty())
{
root = s.top();
s.pop();
root = root->rchild;
}
}
}
中序遍历
从根节点开始,不断地将左子树入栈,但并不输出,知道左子树为空后,将此结点记录后出栈,再进行输出,然后遍历其右子树。外层while循环控制每次遍历到右子树后进行的一系列操作。
void InOrder(BiNode* root)
{
stack<BiNode*>s;
while (root != NULL || !s.empty())
{
while (root != NULL)
{
s.push(root);
root = root->lchild;
}
if (!s.empty())
{
root = s.top();
s.pop();
cout << root->data;
root = root->rchild;
}
}
}
其实上面的两个遍历思想都是靠栈实现的,实现思路还是比较简单,明白大体的思路后代码实现也没有太大的难度。
后序遍历
思想:
- 遇到一个结点,把它推入栈中,遍历它的左子树
- 左子树遍历结束后,还不能马上访问处于栈顶的该结点,而是要再按照它的右链接结构指示的地址去遍历该结点的右子树
- 遍历遍右子树后才能从栈顶托出该结点并访问之
解决方案:
需要给栈中的每个元素加上一个特征位,以便当从栈顶弹出一个结点时区别是从栈顶元素左边回来的(则要继续遍历右子树),还是从右边回来的(该结点的左、右子树均已遍历)
特征:Left表示已进入该结点的左子树,将从左边回来;
特征:Right表示已进入该结点的右子树,将从右边回来
enum Tags { Left, Right };
class StackElement
{
public:
Tags tag;
BiNode* point;
};
void PostOrder(BiNode* root)
{
StackElement element;
stack<StackElement>s;
BiNode* point;
if (root == NULL)
return;
else
point = root;
while (true)
{
while (point != NULL)
{
element.point = point;
element.tag = Left;
s.push(element);
point = point->lchild;
}
element = s.top();
s.pop();
point = element.point;
while (element.tag == Right)
{
cout << point->data;
if (s.empty())
return;
else
{
element = s.top();
s.pop();
point = element.point;
}
}
element.tag = Right;
s.push(element);
point = point->rchild;
}
}
后序比前序中序都要复杂一些,层序遍历反而就会简单很多,广搜思想,实现较为方便。
全部代码:
#include<iostream>
#include<stack>
using namespace std;
struct BiNode
{
char data;
BiNode* lchild, * rchild;
};
enum Tags { Left, Right };
class StackElement
{
public:
Tags tag;
BiNode* point;
};
class BiTree
{
public:
BiTree() { root = Creat(); }
void PreOrder() { PreOrder(root); }
void InOrder() { InOrder(root); }
void PostOrder() { PostOrder(root); }
private:
BiNode* root;
BiNode* Creat()
{
BiNode* root;
char ch;
cin >> ch;
if (ch == '#')
root = NULL;
else
{
root = new BiNode;
root->data = ch;
root->lchild = Creat();
root->rchild = Creat();
}
return root;
}
void PreOrder(BiNode* root)
{
stack<BiNode*>s;
while (root != NULL || !s.empty())
{
while (root != NULL)
{
cout << root->data;
s.push(root);
root = root->lchild;
}
if (!s.empty())
{
root = s.top();
s.pop();
root = root->rchild;
}
}
}
void InOrder(BiNode* root)
{
stack<BiNode*>s;
while (root != NULL || !s.empty())
{
while (root != NULL)
{
s.push(root);
root = root->lchild;
}
if (!s.empty())
{
root = s.top();
s.pop();
cout << root->data;
root = root->rchild;
}
}
}
void PostOrder(BiNode* root)
{
StackElement element;
stack<StackElement>s;
BiNode* point;
if (root == NULL)
return;
else
point = root;
while (true)
{
while (point != NULL)
{
element.point = point;
element.tag = Left;
s.push(element);
point = point->lchild;
}
element = s.top();
s.pop();
point = element.point;
while (element.tag == Right)
{
cout << point->data;
if (s.empty())
return;
else
{
element = s.top();
s.pop();
point = element.point;
}
}
element.tag = Right;
s.push(element);
point = point->rchild;
}
}
};
int main()
{
BiTree bt;
bt.PreOrder();
cout << endl;
bt.InOrder();
cout << endl;
bt.PostOrder();
cout << endl;
return 0;
}