您的位置:首页 > 理论基础 > 数据结构算法

先序非递归遍历二叉树解析——面试高频数据结构

2015-07-17 22:45 260 查看

一、基本概念

二叉树是笔试面试中高频数据结构。

而二叉树的遍历是解决一切二叉树题目的基础。因此,有必要熟练掌握二叉树的遍历方法,包括递归方法 和 非递归方法。

由于递归方法比较简单,因此,这里我们着重来学习二叉树的非递归遍历方法。

首先明确,二叉树的遍历方法按照访问根节点的次序不同,可以分为如下三种:先序遍历、中序遍历、后序遍历。

先序遍历,即先访问根节点,然后再分别访问左子节点、右子节点。

二、实现策略

实现先序遍历的思路:

1、深度优先法则

深度优先遍历是图的一种遍历算法,二叉树是一种图的特例,因此也可以用深度优先法则来进行遍历。

需要注意的问题是:要考虑节点重复访问的问题!

具体实现方法:利用辅助栈!存储访问的节点

举例说明,比如有树结构如图所示:



按照先序遍历的策略:向左走到头,向右走一步

访问根节点,并将根节点入栈
栈不为空,沿栈顶节点的左子树遍历,将途经的所有节点访问并入栈,同时断开父子节点之间的指针;
若当前栈顶点无左子树,则访问右子树;
若当前栈顶点无右子树,则将栈顶节点弹出,回到第2步;
若当前栈顶点有右子树,则将右孩子节点压入栈,并且断开父子之间的指针,回到第2步;
当栈为空,结束。

实现代码:

#include"iostream"
#include"stack"
using namespace std;

struct BiTNode{
int data;
struct BiTNode *lchild, *rchild;
};

class Solution{
public:
void preOrderTraverse(BiTNode *T)
{
if (T == NULL)
return;
stack<BiTNode*> assi;//定义辅助栈
assi.push(T);//压栈
cout << assi.top()->data;//入栈时候访问

while (!assi.empty())
{
while (assi.top()->lchild)
{
cout << assi.top()->lchild->data;
BiTNode *temp = assi.top();//用于断开父子连接 防止重复访问
assi.push(assi.top()->lchild);
temp->lchild = NULL;//断开父子连接
}

if (!assi.top()->rchild)//若右孩子为空则直接弹出,该节点已经访问输出过了。
assi.pop();
else
{
cout << assi.top()->rchild->data;
BiTNode *temp = assi.top();
assi.push(assi.top()->rchild);
temp->rchild = NULL;
}
}
}
};


2、利用栈的特性

栈是后进先出,所以可以先访问右子树 再访问左子树,那么在出栈的时候,就是左子树在右子树前面,符合先序遍历的要求。

这种方法的好处是:写代码的时候不用考虑重复访问,断开指针的事情。

具体操作步骤:

根节点入栈
栈不为空时,访问栈顶节点并出栈
若出栈的节点右孩子不为空,右孩子入栈;若出栈节点的左孩子不为空,左孩子入栈
栈为空时,结束

void preOrderTraverse2(BiTNode *T)
{
if (T == NULL)
return;
stack<BiTNode *> st;
st.push(T);
BiTNode *p = NULL;

while (!st.empty())
{
p = st.top();
cout << p->data;
st.pop();

if (p->rchild != NULL)
st.push(p->rchild);
if (p->lchild != NULL)
st.push(p->lchild);
}
}


三、总结

两种思路都借助了栈,思路一只是借助栈临时存储遍历的变量,

思路二,则利用栈的后进先出的特性,来实现先序遍历。

两种思路在编码实现的时候略有区别,需加注意。

总得来说,理解了先序遍历的过程,就可以顺利地写出上面的代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: