二叉链表前序、中序、后序遍历非递归算法的实现
好东西写在前面:对几个遍历的输出结果一直记不清楚,知道看到了博客分享的动画,理解起来真的不废劲!话不多说直接上传送门二叉链表的三个遍历过程
前序遍历
前序遍历非递归算法的关键:
在前序遍历过某结点的整个左子树之后,如何找到其右子树的根指针
。仔细分析遍历的过程可以看出,在访问某结点之后,应将该结点保存到栈中
,以便能通过它找到该结点的右子树。
设要遍历二叉树的根指针为bt,可能有两种情况:
①:bt != nulllptr,表明当前二叉树不为空,此时应输出根结点bt的值并将bt保存到栈中,准备继续遍历bt的左子树
②:bt == nullptr,表明以bt为根指针的二叉树遍历完毕,并且bt时栈顶指针所指的左子树。若栈不空,则弹出栈顶指针并根据栈顶指针找到右子树的根指针赋予bt,继续遍历下去。若栈为空,则表明整个二叉树遍历完毕。
代码实现
#include <iostream>
using namespace std;
template<class T>
struct BiNode
{
T data;
BiNode* lchild, * rchild;
};
template<class T>
class BiTree
{
public:
//构造函数 建立一颗二叉树
BiTree()
{
root = Creat(root);
}
//析构函数 释放各节点的存储空间
~BiTree()
{
this->Release(root);
}
//前序遍历二叉树
void PreOrder();
private:
BiNode<T>* Creat(BiNode<T>* bt);//构造函数调用
void Release(BiNode<T>* bt);//析构函数调用
BiNode<T>* root;//指向根结点的头指针
};
template<class T>
void BiTree<T>::PreOrder()
{
BiNode<T>* bt = root;
BiNode<T>* s[100];//顺序栈,最多100个结点指针
int top = -1;//初始化栈
while (bt != nullptr || top != -1)//只有同时满足bt为空和栈空的时候才退出循环
{
while (bt != nullptr)
{
cout << bt->data;
//根指针bt入栈
top++;
s[top] = bt;
bt = bt->lchild;
}
//左子树为空的情况下
if (bt == nullptr)
{
//出栈遍历右子树
bt = s[top];
top--;
bt = bt->rchild;
}
}
}
template<class T>
BiNode<T>* BiTree<T>::Creat(BiNode<T>* bt)
{
char ch;
cout << "请输入扩展二叉树的前序遍历序列,每次输入一个字符:";
cin >> ch;//输入结点的数据信息,假设为字符
if (ch == '#')
{
bt = nullptr;
}
else
{
bt = new BiNode<T>;
bt->data = ch;
bt->lchild = Creat(bt->lchild);//递归建立左子树
bt->rchild = Creat(bt->rchild);//递归建立右子树
}
return bt;
}
template<class T>
void BiTree<T>::Release(BiNode<T>* bt)
{
if (bt == nullptr)
{
return;
}
else
{
Release(bt->lchild);
Release(bt->rchild);
delete bt;//释放根结点
}
}
int main()
{
BiTree<char> t{};
cout << "该二叉树的前序遍历序列是:";
t.PreOrder();
return 0;
}
/*
请输入扩展二叉树的前序遍历序列,每次输入一个字符:a
请输入扩展二叉树的前序遍历序列,每次输入一个字符:b
请输入扩展二叉树的前序遍历序列,每次输入一个字符:#
请输入扩展二叉树的前序遍历序列,每次输入一个字符:#
请输入扩展二叉树的前序遍历序列,每次输入一个字符:c
请输入扩展二叉树的前序遍历序列,每次输入一个字符:d
请输入扩展二叉树的前序遍历序列,每次输入一个字符:#
请输入扩展二叉树的前序遍历序列,每次输入一个字符:#
请输入扩展二叉树的前序遍历序列,每次输入一个字符:e
请输入扩展二叉树的前序遍历序列,每次输入一个字符:#
请输入扩展二叉树的前序遍历序列,每次输入一个字符:#
该二叉树的前序遍历序列是:abcde
*/
中序遍历
在二叉树中序遍历中,访问结点的操作发生在该结点的左子树遍历完毕并且准备遍历右子树时,所以,在遍历过程中遇到某结点时并不能立即访问它,而是将它压栈,
等到它的左子树遍历完毕后,再从栈中弹出并访问之
。中序遍历的非递归算法只需要将前序遍历非递归算法中的输出操作移到出栈操作bt = S[top--]之后即可
。
代码实现
#include <iostream>
using namespace std;
template <class T>
struct BiNode
{
T data;
BiNode* lchild, * rchild;
};
template <class T>
class BiTree
{
public:
BiTree()
{
root = Creat(root);
}
void InOrder();
~BiTree()
{
Release(root);
}
private:
BiNode<T>* Creat(BiNode<T>* bt);
void Release(BiNode<T>* bt);
BiNode<T>* root;
};
template <class T>
void BiTree<T>::InOrder()
{
BiNode<T>* bt = root;
BiNode<T>* s[100];
int top = -1;
while (bt != nullptr || top != -1)
{
while (bt != nullptr)
{
s[++top] = bt;//入栈
bt = bt->lchild;
}
if (top != -1)
{
bt = s[top--];//出栈
cout << bt->data;
bt = bt->rchild;
}
}
}
template <class T>
BiNode<T>* BiTree<T>::Creat(BiNode<T>* bt)
{
char ch;
cout << "请输入扩展二叉树的中序遍历序列,每次输入一个字符:";
cin >> ch;
if (ch == '#')
{
return nullptr;
}
else
{
bt = new BiNode<T>;//少了这一步
bt->data = ch;
//递归调用Creat初始化
bt->lchild = Creat(bt->lchild);
bt->rchild = Creat(bt->rchild);
}
return bt;
}
template <class T>
void BiTree<T>::Release(BiNode<T>* bt)
{
if (bt == nullptr)
{
return;
}
else
{
Release(bt->lchild);
Release(bt->rchild);
delete bt;//不能忘了delete指针
}
}
int main()
{
BiTree<char> t{};
cout << "该二叉树的中序遍历是:";
t.InOrder();
return 0;
}
/*
请输入扩展二叉树的中序遍历序列,每次输入一个字符:a
请输入扩展二叉树的中序遍历序列,每次输入一个字符:b
请输入扩展二叉树的中序遍历序列,每次输入一个字符:#
请输入扩展二叉树的中序遍历序列,每次输入一个字符:#
请输入扩展二叉树的中序遍历序列,每次输入一个字符:c
请输入扩展二叉树的中序遍历序列,每次输入一个字符:d
请输入扩展二叉树的中序遍历序列,每次输入一个字符:#
请输入扩展二叉树的中序遍历序列,每次输入一个字符:#
请输入扩展二叉树的中序遍历序列,每次输入一个字符:e
请输入扩展二叉树的中序遍历序列,每次输入一个字符:#
请输入扩展二叉树的中序遍历序列,每次输入一个字符:#
该二叉树的中序遍历是:badce
*/
后序遍历
后序遍历与另外两个有所不同,当遍历完左子树,由于右子树尚未遍历,因此栈顶结点不能出栈,而是通过栈顶结点找到它的右子树,当遍历完右子树,才能将栈顶结点出栈并访问。
区别栈顶结点的不同处理,设置标志变量flag。flag=1表示遍历完左子树,栈顶结点不能出栈;flag=2表示遍历完右子树,栈顶结点可以出栈并访问。
代码实现
#include <iostream>
using namespace std;
template <class T>
struct BiNode
{
T data;
BiNode<T>* lchild, * rchild;
};
template <class T>
struct element
{
BiNode<T>* ptr;
int flag;//flag=1表示遍历完左子树,flag=2表示遍历完右子树
};
template <class T>
class BiTree
{
public:
BiTree()
{
root = Creat(root);
}
void PostOrder();
~BiTree()
{
Release(root);
}
private:
BiNode<T>* Creat(BiNode<T>* bt);
void Release(BiNode<T>* bt);
BiNode<T>* root;
};
template <class T>
void BiTree<T>::PostOrder()
{
BiNode<T>* bt = root;
element<T> s[100];
int top = -1;
while (bt != nullptr || top != -1)
{
while (bt != nullptr)
{
top++;
s[top].ptr = bt;
s[top].flag = 1;
bt = bt->lchild;
}
while(top != -1 && s[top].flag == 2)
{
bt = s[top--].ptr;
cout << bt->data;
}
if (top != -1)
{
//bt = bt->rchlid;
//s[++top].ptr = bt;
s[top].flag = 2;
bt = s[top].ptr->rchild;
}
else
{
bt = nullptr;
}
}
}
template <class T>
BiNode<T>* BiTree<T>::Creat(BiNode<T>* bt)
{
char ch;
cout << "请输入扩展二叉树的后序遍历序列,每次输入一个字符:";
cin >> ch;
if (ch == '#')
{
return nullptr;
}
else
{
bt = new BiNode<T>;
bt->data = ch;
bt->lchild = Creat(bt->lchild);
bt->rchild = Creat(bt->rchild);
}
return bt;
}
template <class T>
void BiTree<T>::Release(BiNode<T>* bt)
{
if (bt == nullptr)
{
return;
}
else
{
Release(bt->lchild);
Release(bt->rchild);
delete bt;
}
}
int main()
{
BiTree<char> t{};
cout << "该二叉树的后序遍历序列是:";
t.PostOrder();
return 0;
}