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

【数据结构】【二叉树后序遍历】【非递归实现方法】三种方法总结 浙江大学课程课后练习

2019-08-05 18:23 323 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/u012127385/article/details/98504638

非递归实现的先序与中序遍历、递归实现的三种二叉树遍历方法及结构定义将在后面给出)

后序遍历:左->右->根

方法一:取巧法

最优方法:将先序遍历的左右子顺序倒置后,逆序将输出结果。

即先序遍历为:根-左-右 左右子树顺序倒置后得到:根-右-左,逆序输出得到左-右-根。

使用两个栈储存,一个保存左右颠倒的先序遍历,一个保存结果,然后将结果逆序输出。

[code]​
void PostOrderTreaversalStack(BinTree BT)
{
//建立一个堆栈
TStack ts=CreateStack();
//保存结果用于逆序输出的堆栈
TStack tsR=CreateStack();
BinTree T=BT;
while(T||!IsEmpty(ts))//栈和树指针全空时跳出循环
{
while(T)
{
Push(ts,T);
Push(tsR,T);
T=T->Right;
}
if(!IsEmpty(ts))
{
T=Pop(ts);
T=T->Left;
}
}
while(!IsEmpty(tsR))
{
T=Pop(tsR);
cout<<T->Date<<endl;
}
}

​

方法二:设置访问记录栈法

利用两个堆栈,一个正常使用的ts,一个存有存在右子树结点的tsR  。访问时,右子树非空时对比两个堆栈当前结点。结点相等便一起pop,不相等时右子树非空便push(tsR,ts指向的当前结点),T指针指向右子树。右子树空ts栈pop当前结点。

[code]void PostOrderTreaversalStack2(BinTree BT)
{
//建立一个正常的堆栈
TStack ts=CreateStack();
//保存右子树非空的结点,用于判断访问次数
TStack tsR=CreateStack();
BinTree T=BT;
while(T||!IsEmpty(ts))//栈和树指针全空时跳出循环
{
while(T)
{
Push(ts,T);
T=T->Left;
}
if(!IsEmpty(ts))
{
BinTree Tnow=(ts->Next)->TS;//主栈当前结点
BinTree TRnow=(tsR->Next)->TS;//访问栈当前结点
BinTree Tright=Tnow->Right;//获取结点右子树情况
if(!Tright)//右子树空
{
T=Pop(ts);
cout<<T->Date<<endl;
T=T->Right;//相当于赋值为NULL
}
else if(Tright&&Tnow==TRnow) //右子树非空并且访问过刚好到那个结点
{
T=Pop(ts);
cout<<T->Date<<endl;
T=Pop(tsR);//释放访问栈结点
T=NULL; //使循环进入下一个栈内结点
}
else//右子树非空且未访问过
{
Push(tsR,Tnow);//记录访问
T=Tright;//指向右子树
}
}
}
while(!IsEmpty(tsR))
{
T=Pop(tsR);
cout<<T->Date<<endl;
}
}

方法三:在栈结构体中设置右子树访问次数的属性。根据访问次数判断是否pop(需要修改结构体,比较麻烦,不给出代码)

先序遍历与中序遍历:

[code]//中序遍历
//遇到一个结点就压栈,并去遍历该树的左子树;
//当左子树遍历结束后,从栈顶弹出这个结点并访问它;
//然后按其右指针再去遍历一遍该节点的右子树
//压入栈的是指针!!!!
void InOrderTreversalStack(BinTree BT)
{
//建立一个堆栈
TStack ts=CreateStack();
BinTree T=BT;
while(T||!IsEmpty(ts))//栈和树指针全空时跳出循环
{
while(T)
{
Push(ts,T);
T=T->Left;
}
if(!IsEmpty(ts))
{
T=Pop(ts);
cout<<T->Date<<endl;
T=T->Right;
}
}
}
//先序遍历
void PreOrderTreaversalStack(BinTree BT)
{
//建立一个堆栈
TStack ts=CreateStack();
BinTree T=BT;
while(T||!IsEmpty(ts))//栈和树指针全空时跳出循环
{
while(T)
{
Push(ts,T);
cout<<T->Date<<endl;
T=T->Left;
}
if(!IsEmpty(ts))
{
T=Pop(ts);
T=T->Right;
}
}
}

递归方法:

[code]//递归遍历

//先序遍历 根->左->右
void PreOrderTreaversal(BinTree BT)
{
if(BT)//不为空
{
cout<<BT->Date<<endl;
PreOrderTreaversal(BT->Left);
PreOrderTreaversal(BT->Right);
}
}
//中序遍历 左->根->右
void InOrderTreaversal(BinTree BT)
{
if(BT)
{
InOrderTreaversal(BT->Left);
cout<<BT->Date<<endl;
InOrderTreaversal(BT->Right);
}
}
//后序遍历 左->右->根
void PostOrderTreaversal(BinTree BT)
{
if(BT)
{
PostOrderTreaversal(BT->Left);
PostOrderTreaversal(BT->Right);
cout<<BT->Date<<endl;
}
}

二叉树与堆栈定义:

[code]#define MAXSIZE 1024

//链表方式储存 二叉树
typedef int ElementType;
typedef struct TreeNode *BinTree ;
struct TreeNode {
ElementType Date;
BinTree Left;
BinTree Right;
};

//链表方式储存堆栈

typedef struct TreeStack *TStack;
struct TreeStack{
BinTree TS;//储存指针
TStack Next;//指向下一个栈值
};
TStack CreateStack() //建立一个堆栈
{
TStack head=(TStack)malloc(sizeof(TreeStack));//申请头结点
if(head){
head->Next=NULL;//TS不保存任何信息
}
return head;
}
bool IsEmpty(TStack TS)//判断是否非空 true为空 false为非空
{
return (TS->Next==NULL);
}
bool Push(TStack S,BinTree BT)//入栈 true成功入栈
{
TStack ts =(TStack)malloc(sizeof(TreeStack));//申请新结点的空间
if(ts)//申请成功
{
ts->TS=BT;
ts->Next=S->Next;
S->Next=ts;
return true;
}
else return false;
}
BinTree Pop(TStack S)//出栈并释放空间
{
if(S->Next)//判断S非空
{
TStack ts;
BinTree B;
ts=S->Next;
B=ts->TS;
S->Next=ts->Next;
free(ts);
return B;
}
else return NULL;
}

 

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