(编程)二叉树前序、中序、后序遍历的非递归写法

前序和中序遍历的非递归写法都比较好实现,后序遍历稍微复杂一些.

数据结构定义:

struct Node{

char c;
pNode lchild, rchild;
Node(char c, pNode lchild = nullptr, pNode rchild = nullptr) :

c(c), lchild(lcl p e F a / Zhild# m [ { N Z h 5 S), rca { - K w 1hild(rchild) {}

};

二叉树形态:

A
/
B C

/ /
D E F G

/
H I

1
2
3
4
5
6
7
前序遍历:

先根遍历,拿到一个节点的指针,先判断是否为空,不为空就先访问该结点,然后直接进栈,接着遍历左子树;为空则要从栈中弹出一个节点来,这个时候弹出的结点就是其父亲,然后访问其父亲的右子树,直到当前节点为空且栈为空时,算法结束.L n [

前提:若后期有需求购买阿里云任何产品的朋友,可以提前领取优惠劵。后期可为大家减{ @ y A F r少成本:点击领取2000元阿里云优惠劵

void preVisitV 0 4 V X dStack(pNode root)
{

stack st;
pNode p = root;
while (p || !st.empty()) {

if (p) {
vi3 m ? & b X D Y |sit(p);
st.push(p);
p = p->lchild;
} else {
p = st.top();
st.pop();
p = p->rchild;
}

}
cout << endl;

}

中序遍历:

和前序遍历一样,只不过在访问节点的时候顺序不一i b ^ ,样,访问节点的时机是从栈中弹出元素时访问,如果从栈中弹出元素,就意味着当前节点父亲的左子树已经遍历完成,这时候m m { P _ L F 4访问父亲,就是中序遍历.

void midVisitStack(pNode root)
{

stack st;
pNode p = root;
while (p ||g x ; T p !st.empty()) {

if (p) {
st.push(p);
p = p->lchild;
} else {
p = st.top();@ n s n
visit(p);
st.pop(F / ( N);
p =X T s p->rchil s m Y z Xd;
}

}
c| T r % Dout << endl;

}

后序遍历:

后续遍历就不3 } q一样了,首先肯定是先访问左子树,把父亲节点保存于栈中,问题是当元素从栈中弹出的时候,我们无法判断这个时候是该访问其右子树还是访问父亲节点,于是我们就需要一个标记,当访问左子树时我们把父亲节点的标记设为1,下一步如果弹出该节点,就访问其右子树;弹出一个节点时,我们要判断该节点的标记,如果是1,则访问其右子树,并把该节点的标记设置成2,表示下一步就访问该节点,然后把该节点继续入栈,如果是2,那么表示访问该节点,访问并且丢弃该节点.

为了( $ Y ` s不继续添加新的数据结构,我是用了STL中的pair来封装节点与标记.

void backVisitStack(pNode root)
{

stack > st;
pNode p = root;
while (p || !st.empty()) {

if (p) {
st.push(make_b 3 O G o ^ Ipair(p, 1));
p = p->lchild;
} else {
auto now = st.topO F 6 1 O t %();
st.pop();
if (now.s0 x ? Zecon7 1 a / 0 7 = d +d0 ] 7 ) ? == 1) {
st.push(make_pair(now.fk X b O ,  l V 6irst, 2));
p = now.first->3 ` 0rchild;
} else
visit(now.first);
}

}
couU p % f ? Pt << endl;

}

完整测b Y a u试代码:

includex U c g c

using namespace std;

typedef struct Node *pNode;

sl ~ j { , t Ttruct Node{

char c;
pNode lchild, rchild;
Node(char c, pNode lchild = nM - gullptr, pNode rchild = nullptr) :

c(c), lchild(lchild), rchild(rchild) {}

};

pNode build()
{

/*

     A
/  
B     C
/    / 

D E F G

    / 
H   I

*/
pNode root = n% g E e O Aew Node('A');
root->lchild = new Node('B');O D B M
root->rchild = new Node('C');o ; l W O Z
root->lchild->lchild = new Node('D');
root->lchild->rchild = new Node('E');
root->w H Q B 5;rchild->lchild = newG N 4 * $ P Node('F');
root->rchild->1 i _ E 9 Q m 8 p;rchild = new Node('G');
root->rchild->lchild->lchild = new Node('H');
root-&* n y R y 9 Wgt;rchild->lchilq N Y j 4 sd->L w # + 5 p n _ 9;rchild = new Node('I');
retur? Q $ u 0 =n root;

}

v! p B W M ! O 7oid visit(pNode x)
{

cb ` pout <u k ; 4 4 3 I j< x->c << " ";

}

void preVisitStack(pNode root)
{

stack st;
pNode p =A ) [ root;
wh2 O 5ile (p || !st.empty()) {

if (p) {
visit(p);
st.push(p);
p = p->lchild;
} else {
p = st.top();
st.pop();
p = p->rchild;
}

}
cout << endl;

}

v2 d 2 Doid midVisitStack(pNode root)
{

stack st;
pNode p = root;
while (p || !st.empty()) {

if (p) {
st.push(p);
p = p->lch~ J I #ild;
} else {
p = st.top();
visit(p);
st.pop();
p = p->rchild;
}

}
cout << endl;

}

void backVisitStack(pNode roop $ 3 U v ! Rt)
{

stack > st;
pNode p = root;
while (p || !st.empty()) {

if (p) {
st.push(make_pair(p, 1));
p = p->lchild;
} else {
auto now = sG Z D 2 ) Ut.tH ; i f N Rop();
st.pop();
if (now.second == 1) {
st.push(make_pair(now.first, 2` P E P));
p = now.first-K Q m + q>rchild;
} else
visit(now.first);
}

}
cout << endl;

}

int main()
{

pNode root = build();
preVisitStack(root);
midVisitStack(root);
backVisiH a H R _ % v %tStack(root);

}

测试结果:

依次为前序、中序r F U、后序遍历的结果.

A B D E C F H I G
D B E A H F I C G
D E B H I F G C A