上一篇文章,讲了二叉树的创建——C++实现 链表存储二叉树
接下来讲解二叉树的三种遍历方式:先序(前序)遍历、中序遍历、后序遍历,三种方式都是DFS(Depth First Search)深度优先搜索,核心思想都是函数的递归(栈),如果你能理解上面这篇文章中创建二叉树的具体过程,那么遍历就轻而易举
1.先序遍历
void Former_Order_Traversel(BinTree_Node* p)
{
if(p)
{
cout<<p->data;
Former_Order_Traversal(p->left);
Former_Order_Traversal(p->right);
}
}
下面分析具体过程,以上一篇文章创建的二叉树为例,圆圈中的数字为data。从上到下,从左到右给结点编号,遍历顺序为ABDECFG,根-左-右
整个递归过程其实是靠函数栈来实现的,先访问再入栈:
-
1.把根结点指针传进来,判断结点不为空,访问根结点数据,然后将根结点A入栈
-
2.把根结点的left指针(B结点)传进来,判断结点不为空,访问B结点数据,将B结点入栈
-
3.把B结点的left指针(D结点)传进来,判断结点不为空,访问D结点数据,D结点入栈
-
4.把D结点的left指针传进来,指针为空,从栈顶抛出一个元素D,处理右子树
-
-
5.把D的right指针传进来,指针为空,从栈顶抛出一个元素B,处理右子树
-
6.把B的right指针(E结点)传进来,判断不为空,访问E结点数据,E结点入栈
-
7.把E结点的left指针传进来,指针为空,从栈顶抛出一个元素E,处理右子树
-
8.把E结点的right指针传进来,指针为空,从栈顶抛出一个元素A,然后同理
搞清楚函数栈的实现过程后,我们可以利用stl中的stack模拟出栈和入栈
void Former_Order_Stack(Bintree_Node* p)
{
if(!p) return;//如果是空树,就直接返回
Bintree_Node* temp = p;
stack<Bintree_Node*>s;//创建一个数据栈
while (temp != NULL || !s.empty())//当temp为空指针且栈空时,遍历就结束了
{
while (temp != NULL)//判断结点是否为空
{
cout << temp->data << endl;//访问数据
s.push(temp);//该结点入栈
temp = temp->left;//将指针指向左子树
}
temp = s.top();//抛出前,获得栈顶元素的引用,也就是出栈结点的引用
s.pop();
temp = temp->right;//将指针指向出栈结点的右子树,准备处理
}
}
2.中序遍历
void Middle_Order_Stack(Bintree_Node* p)
{
if(p)
{
Middle_Order_Traversal(p->left);
cout<<p->data;
Middle_Order_Traversal(p->right);
}
}
遍历顺序为DBEAFCG,左-根-右,具体过程如下
- 1.根结点指针传进来,判断不为空,根结点A入栈
- 2.把根结点的left指针(B结点)传进来,判断不为空,B结点入栈
- 3.把B结点的left指针(D结点)传进来,判断不为空,D结点入栈
- 4.把D结点的left指针传进来,判断为空,抛出栈顶元素D,输出D结点数据
- 5.把指针指向D结点的right指针,判断为空
- 6.抛出栈顶元素B,输出B结点数据
- 7.把指针指向B结点right指针(E结点),判断不为空,E结点入栈
- 8.把指针指向E结点的left指针,判断为空,抛出栈顶E结点,输出结点E数据
- 9.把指针指向E结点的right指针,判断为空,抛出栈顶A结点,输出A结点数据
…右子树同理
弄清楚上述过程后,用stack模拟
void Middle_Order_Stack(Bintree_Node* p)
{
if(!p) return;//如果是空树,就直接返回
Bintree_Node* temp = p;
stack<Bintree_Node*>s;
while (temp != NULL || !s.empty())
{
while (temp != NULL)
{
s.push(temp);
temp = temp->left;
}
temp = s.top();
cout << temp->data << endl;
s.pop();
temp = temp->right;
}
}
3.后序遍历
void Last_Order_Traversal(Bintree_Node* p)
{
if (p)
{
Last_Order_Traversal(p->left);
Last_Order_Traversal(p->right);
cout << p->data << endl;
}
}
遍历顺序为:DEBFGCA ,左-右-根,因为要记录当前结点的遍历情况,后序遍历会稍微复杂
stack模拟如下
void postorderTraversalNew(Bintree_Node *root)
{
stack<pair<Bintree_Node*,bool>> s;
s.push(make_pair(root,false));
while (!s.empty())
{
Bintree_Node* root = s.top().first;
bool flag = s.top().second;
s.pop();//先出队
if (root == NULL)
continue;
if (flag == true)//遍历过的就直接输出
cout << root->data << endl;
else//如果没遍历过的点,要再次入队
{
s.push(make_pair(root, true));//第二次入队,改为true
s.push(make_pair(root->right, false));
s.push(make_pair(root->left, false));
}
}
}