堆栈实现二叉树的遍历
该方式主要通过使用栈这一数据结构实现二叉树的遍历。
中序遍历
对于中序遍历而言,采用该方式的详细过程如下:
- 遇到一个结点,就把它压栈,并遍历它的左子树
- 当左子树遍历结束后,从栈顶弹出这个结点并访问它
- 然后按其右指针再去中序遍历该节点
void PreOrder(BinTree BT)
{
BinTree t = BT;
Stack s = CreateStack();
while(t || !IsEmpty(s))
{
while(t){
Push(s, t);
t = t->left;
}
if(!IsEmpty(s))
{
t = Pop(s);
printf("%c", t->Data);
t = t->right;
}
}
}
先序遍历
- 遇到一个结点,就输出,然后把它压栈,并遍历它的左子树
- 当左子树遍历结束后,从栈顶弹出这个结点
- 然后按其右指针再去先序遍历该节点的左子树
// 先序非递归
void PreOrderTraversal(BinTree BT){
BinTree T = BT;
Stack S = CreateStack(); // 创建并初始化堆栈 S
while(T || !IsEmpty(S)){ // 当树不为空或堆栈不空
while(T){
Push(S,T); // 压栈,第一次遇到该结点
printf("%d",T->Data); // 访问结点
T = T->Left; // 遍历左子树
}
if(!IsEmpty(S)){ // 当堆栈不空
T = Pop(S); // 出栈,第二次遇到该结点
T = T->Right; // 访问右结点
}
}
}
后序遍历
对于后序遍历,可以使用反序进行输出。先序的访问顺序是root,left,right,我们可以先将左右对调,则顺序变为root,right,left,然后用栈来存储,最后输出栈中的内容, 此时顺序就变为了left,right,root。
具体实现的步骤:
建立两个栈,一个用作存储root,right,left顺序的结果栈,一个用作临时栈进行先序遍历。
- 遇到一个结点,就把它压栈,同时将该节点存到结果栈中,遍历它的右子树
- 当右子树遍历结束后,从栈顶弹出这个结点
- 然后按其左指针再去先序遍历该节点的左子树
- 最后输出结果栈中的内容即可。
void PostOrder( BinTree BT )
{
BinTree t = BT;
Stack s = CreateStack(); //创建并初始化堆栈S
Stack q = CreateStack(); //创建并初始化堆栈Q,用于输出反向
while( t || !IsEmpty(s) ){
while(t){ //一直向右并将沿途结点压入堆栈
Push(s,t);
Push(q,t);// 将遍历到的结点压栈,用于反向
t = t->right;
}
if(!IsEmpty(s)){
t = Pop(s); //结点弹出堆栈
t = t->left; //转向左子树
}
}
while( !IsEmpty(q) ){
t = Pop(q);
printf("%c", t->Data); //(访问)打印结点
}
}
例子
针对如下二叉树的三种遍历方式进行实现:
#include<stdio.h>
#include<malloc.h>
typedef struct TreeNode *BinTree;
struct TreeNode{
char Data;
BinTree left;
BinTree right;
};
//创建堆栈用于实现堆栈方式遍历二叉树
typedef struct Snode *Stack;
struct Snode{
BinTree Data;
Stack next;
};
Stack CreateStack();
int IsEmpty(Stack s);
void Push(Stack s, BinTree item);
BinTree Pop(Stack s);
Stack CreateStack()
{
Stack s;
s = (Stack)malloc(sizeof(struct Snode));
s->next = NULL;
return s;
}
int IsEmpty(Stack s)
{
return s->next == NULL;
}
void Push(Stack s, BinTree item)
{
Stack tmp = (Stack)malloc(sizeof(struct Snode));
tmp->Data = item;
//栈顶元素是链表头结点,新入栈的链表在栈顶元素后面
tmp->next = s->next;
s->next = tmp;
}
BinTree Pop(Stack s)
{
BinTree val;
Stack tmp = s->next;
val = tmp->Data;
s->next = tmp->next;
free(tmp);
return val;
}
//创建二叉树
BinTree CreateBinTree();
//插入节点
BinTree Insert(char Data);
//堆栈实现先序遍历
void PreOrder(BinTree BT);
//堆栈实现中序遍历
void InOrder(BinTree BT);
//堆栈实现后序遍历
void PostOrder(BinTree BT);
BinTree Insert(char Data)
{
BinTree bt = (BinTree)malloc(sizeof(struct TreeNode));
bt->Data = Data;
bt->left = NULL;
bt->right = NULL;
return bt;
}
BinTree CreateBinTree()
{
BinTree bt;
bt = (BinTree)malloc(sizeof(struct TreeNode));
bt->Data = 'a';
bt->left = Insert('b');
bt->right = Insert('c');
bt->left->left = Insert('d');
bt->left->right = Insert('f');
bt->right->left = Insert('g');
bt->right->right = Insert('i');
bt->left->right->left = Insert('e');
bt->right->left->right =Insert('h');
return bt;
}
//堆栈实现先序遍历
void PreOrder(BinTree BT)
{
BinTree t = BT;
Stack s = CreateStack();
while(t || !IsEmpty(s))
{
while(t){
Push(s, t);
printf("%c", t->Data);
t = t->left;
}
if(!IsEmpty(s))
{
t = Pop(s);
t = t->right;
}
}
}
void InOrder(BinTree BT)
{
BinTree t = BT;
Stack s = CreateStack();
while(t || !IsEmpty(s))
{
while(t){
Push(s, t);
t = t->left;
}
if(!IsEmpty(s))
{
t = Pop(s);
printf("%c", t->Data);
t = t->right;
}
}
}
void PostOrder( BinTree BT )
{
BinTree t = BT;
Stack s = CreateStack(); //创建并初始化堆栈S
Stack q = CreateStack(); //创建并初始化堆栈Q,用于输出反向
while( t || !IsEmpty(s) ){
while(t){ //一直向右并将沿途结点压入堆栈
Push(s,t);
Push(q,t);// 将遍历到的结点压栈,用于反向
t = t->right;
}
if(!IsEmpty(s)){
t = Pop(s); //结点弹出堆栈
t = t->left; //转向左子树
}
}
while( !IsEmpty(q) ){
t = Pop(q);
printf("%c", t->Data); //(访问)打印结点
}
}
int main()
{
BinTree bt = CreateBinTree();
PreOrder(bt);
printf("\n");
InOrder(bt);
printf("\n");
PostOrder(bt);
}