设计并实现基于后序线索二叉树的后序遍历的非递归算法。
一、二叉树的创建
我们使用二叉链表得方式进行二叉树存数。每个结构有一个数据域,存放结点的数据,还有两个左右指针,以及两个标志。当标志为0时表示指向孩子,标志为1时,指向线索。
二叉树的创建根据扩展线序序列创建的。当左右孩子为空时,以“.”来代替。
代码如下:
template<class T>//创建二叉树
void xstree<T>::create(tbnode<T>*& t) {
T x;
cin >> x;
if (x == '.')
t = NULL;
else
{
t = new tbnode<T>;
t->data = x;
create(t->lchild);
create(t->rchild);
root = t;
}
}
二、后序的递归思想。
这个比较简单,就是根据后序的定义,左右根来对二叉树进行遍历的,主要就是递归。
template<class T>
void xstree<T>::post_order(tbnode<T>* t) //后序遍历
{
if (t != NULL)
{
post_order(t->lchild);
post_order(t->rchild);
cout << t->data <<" ";
}
}
三、后序的非递归思想。
非递归实现我们需要使用到栈这样的数据结构。我使用的是c++STL中的栈。
1.首先我们需要做的是二叉树的后序线索化。
(1)如果在当前指针指向的节点为空,则返回。
(2)依次后序线索化左子树,后序线索化右子树
(3)如果当前节点的左孩子为空,那么当前节点的ltag=1;且lchild指针指向其前驱。
(4)如果当前节点的前驱节点不为空,且前驱的右孩子为空,则前驱的rtag=1,且后继即为当前节点。
(5)前驱节点等于当前节点。
按着上述步骤即可完成二叉树的后序线索化。
template<class T>//二叉树的线索化
void xstree<T>::postthread(tbnode<T>* &t)
{
if (t == NULL)
return;
postthread(t->lchild);
postthread(t->rchild);
if (t->lchild == NULL)//当前节点前驱
{
t->ltag = 1;
t->lchild = pre;
}
if (pre != NULL && pre->rchild == NULL)//前驱节点后继
{
pre->rtag = 1;
pre->rchild = t;
}
pre = t;//指针传递
}
2.后序线索二叉树中,求节点的前驱。
(a) 若p有右孩子 —— 右孩子结点是其前驱;
(b) 否则,若P有左孩子 —— 左孩子结点是其前驱;
(c)否则 —— p -> lchild是其前驱线索 。
template<class T>
tbnode<T>* xstree<T>::postpre(tbnode<T>* p){
if (p->rtag == 0) return (p->rchild);
else return (p->lchild);
}
3.然后我们就需要建立一个栈,并且从根节点开始,求其前驱,并将前驱入栈。求完之后。再将他们依次出栈即可。
四、实验数据
所使用的二叉树
结果如下:
五、源代码:
//源代码如下
#include<iostream>
#include<stack>
using namespace std;
template<class T>
struct tbnode {
T data;
tbnode* lchild=NULL, * rchild=NULL;
bool ltag=0, rtag=0;
};
template<class T>
class xstree {
public:
xstree();
~xstree();
void create(tbnode<T>*&t);//创建普通二叉树
void postthread(tbnode<T>* &t);//后序线索化
tbnode<T>* postpre(tbnode<T>* p);//求后序二叉树的前驱节点
void postorder(tbnode<T>* t);//后序遍历(非递归)
tbnode<T>* get_root();//获得树根
void post_order(tbnode<T>* t);//后序遍历(递归)
void delete_tree(tbnode<T>* t);//删除节点,用于析构
private:
tbnode<T>* root;
tbnode<T>* pre;
};
template<class T>//构造函数
xstree<T>::xstree() {
root = NULL;
pre = NULL;
}
template<class T>
void xstree<T>::post_order(tbnode<T>* t) //后序遍历
{
if (t != NULL)
{
post_order(t->lchild);
post_order(t->rchild);
cout << t->data <<" ";
}
}
template<class T>//创建二叉树
void xstree<T>::create(tbnode<T>*& t) {
T x;
cin >> x;
if (x == '.')
t = NULL;
else
{
t = new tbnode<T>;
t->data = x;
create(t->lchild);
create(t->rchild);
root = t;
}
}
template<class T>//二叉树的线索化
void xstree<T>::postthread(tbnode<T>* &t)
{
if (t == NULL)
return;
postthread(t->lchild);
postthread(t->rchild);
if (t->lchild == NULL)//当前节点前驱
{
t->ltag = 1;
t->lchild = pre;
}
if (pre != NULL && pre->rchild == NULL)//前驱节点后继
{
pre->rtag = 1;
pre->rchild = t;
}
pre = t;//指针传递
}
//求前驱
template<class T>
tbnode<T>* xstree<T>::postpre(tbnode<T>* p){
if (p->rtag == 0) return (p->rchild);
else return (p->lchild);
}
template<class T>//后序遍历(线索树)
void xstree<T>::postorder(tbnode<T> *t) {
stack<tbnode<T>*> S;
tbnode<T>* p = t;
while (p != NULL)//后序序列中,根节点的前驱依次入栈
{
S.push(p);
p = postpre(p);
}
while (!S.empty())//出栈并输出。
{
p = S.top();
S.pop();
cout << p->data << " ";
}
}
template<class T>
void xstree<T>::delete_tree(tbnode<T>* t)
{
tbnode<T>* p = t;
while (p != NULL)
{
tbnode<T>* q = postpre(p);
delete p;
p = q;
}
}
template<class T>
xstree<T>::~xstree()
{
delete_tree(root);
}
template<class T>
tbnode<T>* xstree<T>::get_root() {
return root;
}
int main()
{
tbnode<char> *p;
xstree<char> tree;
cout << "请输入树(先序输入):";
tree.create(p);//创建普通二叉树
cout << "未线索化的二叉树后序遍历为:";
tree.post_order(p);//后序遍历普通二叉树
cout << endl;
p = tree.get_root();//获得树根
tree.postthread(p);//二叉树线索化
p = tree.get_root();//获得树根
cout << "线索化后的线索二叉树其后序遍历为(非递归):";
tree.postorder(p);//非递归后序遍历线索二叉树
cout << endl;
system("pause");
return 0;
}