您的位置:首页 > 其它

非递归、仅用一个栈、不加标记数组实现二叉树的后序遍历算法

2011-08-20 12:24 549 查看
作者:finallyly 出处:博客园(转载请注明作者和出处)

题记:最近在复习数据结构和算法。由于之前在数据结构和算法方面没有受过密集的训练。所以刚入门,有点吃力。最主要的一个问题是:看别人的,好像一看就全懂了,但是自己写又写不出来;给定一个具体的题目,即便是看懂了别人的算法,但是过些日子回过头来自己写,还是写不出来。和我一样出现上述状况的同学要注意啦,需要改变学习方式,否则则会一直在津津有味,乐此不疲,且自以为是地做着无用功。时间是有限的,何必浪费掉大好的时间和青春去做些无意义的事情呢?静下心来想一想,任何一本《数据结构与算法》的教材无非是想告诉我们有一些编程中可以使用的工具(栈、队列、链表、二叉树、图)以及针对如何使用这些工具应用举例而已。因此,我们只要领会到精神,就算学明白了数据结构,可是如何用数据结构实现算法呢?这体现的是自己的逻辑,永远没有什么范式,也不要去过度迷信别人。只要思路对头,你也可以设计出有效果的算法来。

对于设计算法,个人总结可以分两步:第一步:用自然语言体现出自己的思路,第二步,计算机程序亲和型的伪代码;第三步:把自己的思路用程序实现。第一步到第二步的过渡是要求,你的思路是和程序逻辑相亲和的,即用程序可以实现的。下面切入正题,讲诉非递归、仅用一个栈、不加标记数组实现二叉树的后序遍历算法的思路。



二叉树图例如上图。

第一步:思路

思路,根据二次树的结构特点,产生了如下的思路

1. 根节点入栈

2. 如果栈非空,则获取栈顶元素

3. 如果左孩子存在,则入栈左孩子

4. 如果左孩子不存在,但是右孩子存在则入栈右孩子

5. 如果左、右孩子都不存在,那么栈顶元素出栈,并访问已经出栈的栈顶元素

5.1 如果已出栈的元素是当前栈顶元素的左孩子,那么入栈右孩子

5.2如果已出栈元素是当前栈顶元素的右孩子,那么继续出栈并且访问当前栈顶元素

第二步,计算机程序亲和伪代码

思路如何变成计算机可以执行的逻辑?

考虑我们注意到 (1)5.1-5.2之间存在循环逻辑;(2)5.1 与3之间有逻辑重复。对于(1)我们可以写一个while循环,对于(2)我们可以设置一个开关变量flag,用来控制当前栈顶结点的左孩子是否参与入栈活动。

C++风格的伪代码如下

Bool PostOrderTraverse(Bitree T)

{

InitStack(S);

Push(S,T);

flag=0;

While(!Empty(S))

{

Bitree e;

GetTop(S,e);

if (e->lchild&&!flag)

{

Push(S,e->lchild);

}

else

{

if(e->rchild)

{

Push(S,e->rchild);

flag=0;

}

Else

{

Bitree pOldTop;

GetTop(S,pOldTop);

Pop(S);

Visit(pOldTop);

While(!Empty(S))

{

BiTree pNewTop;

GetTop(S,pNewTop);

if (pOldTop=pNewTop->lchild)

{

flag=1;

break;

}

else

{

Pop(S);

Visit(pNewTop);

pOldTop=pNewTop;

flag=0;

}

}

}

}

}

第三步:代码实现

bool PostOrderTraverseByStack(BiTree T)
{
stack<BiTree>bitreeStack;
bitreeStack.push(T);
int flag=0;

while(!bitreeStack.empty())
{
BiTree pTree=bitreeStack.top();
if (pTree->lchild&&!flag)
{
bitreeStack.push(pTree->lchild);
}
else//无需插入左孩子的模式
{
if (pTree->rchild)
{
bitreeStack.push(pTree->rchild);
flag=0;
}
else
{

BiTree pTopOld=bitreeStack.top();
bitreeStack.pop();
cout<<pTopOld->data<<endl;
while(!bitreeStack.empty())
{

if (!bitreeStack.empty())
{
BiTree pTopNew=bitreeStack.top();
if (pTopOld==pTopNew->lchild)
{
flag=1;
break;

}
else
{
cout<<pTopNew->data<<endl;
bitreeStack.pop();
pTopOld=pTopNew;
flag=0;

}

}
else
{
break;
}

}

}
}

}
return true;

}
为了便于大家验证,把二叉树建树、销树、主函数验证的代码张贴如下

#include <iostream>
#include <deque>
#include <stack>
using namespace std;
typedef struct BiTNode
{
char data;
BiTNode *lchild;
BiTNode *rchild;
}BiTNode,*BiTree;

bool CreateBiTree(BiTree &T,deque<char>& charQue)
{

if (!charQue.empty())
{
char ch=charQue.front();
charQue.pop_front();
if (ch==' ')
{
T=NULL;
}
else
{
T=new BiTNode;
T->data=ch;
CreateBiTree(T->lchild,charQue);
CreateBiTree(T->rchild,charQue);

}
return true;
}
return true;

}
bool PostOrderTraverse(BiTree T)
{
if (T)
{
if (PostOrderTraverse(T->lchild))
{
if (PostOrderTraverse(T->rchild))
{
cout<<T->data<<endl;
return true;
}
}
return false;
}
else
{
return true;
}
}
bool DestroyTree(BiTree &T)
{
if (T!=NULL)
{
if (DestroyTree(T->lchild))
{
if (DestroyTree(T->rchild))
{
delete T;
return true;
}

}
return false;

}
else
{
return true;
}

}
int main()
{
BiTree root;
deque<char> charQue;
charQue.push_back('A');
charQue.push_back('B');
charQue.push_back('C');
charQue.push_back(' ');
charQue.push_back(' ');
charQue.push_back('D');
charQue.push_back('E');
charQue.push_back(' ');
charQue.push_back('G');
charQue.push_back(' ');
charQue.push_back(' ');
charQue.push_back('F');
charQue.push_back(' ');
charQue.push_back(' ');
charQue.push_back(' ');
CreateBiTree(root,charQue);
PostOrderTraverse(root);
cout<<"后序遍历结束"<<endl;
PostOrderTraverseByStack(root);
cout<<"借助于栈的后序遍历结束"<<endl;
DestroyTree(root);
cout<<"删除树完毕"<<endl;
cout<<"finish"<<endl;
int f;
cin>>f;
return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐