程序小白,希望和大家多交流,共同学习
//非递归二叉树借用栈
//使用链栈,
//使用它的原因:1.需要使用先进后出的存储结构;2.需要存储数据个数不定;
//三种遍历存储的虽然都是相同的数据类型,但是使用的目的不一样,所以使用的位置不一样
//先序遍历:根据给定的根节点,直接访问根节点(左结点,有左孩子的结点有两重身份),
// 存储的结点是为了可以很容易的找到右子树的根节点。如此反复。
//中序遍历:根据给定的根节点,在搜索最左结点时,存储所有的根节点。
// 然后使用栈访问根节点,再使用根节点,搜索右子树的根节点。如此反复。
//后续遍历:使用根节点配合栈找到第一个没有左右孩子的结点。栈存储的是每一个结点。
// 为的是,当使用根节点找到第一个没有左孩子的结点后,使用栈找到第一
// 没有右孩子的结点。找到的是第一个既没有左孩子,也没有右孩子的结点。如此反复。
#include<iostream>
using namespace std;
//定义二叉树结点
typedef char elemBTree;
struct BTNode
{
elemBTree data;//二叉树数据域
BTNode *lChild, *rChild;//左右孩子
};
typedef BTNode *BTree;
//定义存储二叉树结点的栈
//typedef char elemStack;
typedef BTNode *elemStack;
struct sNode
{
elemStack data;
sNode *next;
};
typedef sNode *linkList;
//初始化栈
void initStack(linkList &ls);
//入栈
void push(linkList &ls, elemStack data);
//出栈
void pop(linkList &ls);
//返回栈顶元素
elemStack getTop(linkList ls);
//判空
bool isEmpty(linkList ls);
//判满
bool isFull(linkList ls);
//先序创建二叉树
void preCreateBT(BTree &bt);
//先序遍历二叉树
void preOrder(const BTree &bt);
//中序遍历二叉树
void inOrder(const BTree &bt);
//后续遍历二叉树
void postOrder(const BTree &bt);
//访问结点
void visit(BTNode *node);
int main()
{
//ABCF##DI##E###G#H##
BTree bt;
cout << "先序创建二叉树:";
preCreateBT(bt);
cout << "先序遍历二叉树(非递归): ";
preOrder(bt);
cout << "\n中序遍历二叉树(非递归): ";
inOrder(bt);
cout << "\n后序遍历二叉树(非递归): ";
postOrder(bt);
cout << endl;
return 0;
}
//初始化栈
void initStack(linkList &ls)
{
ls = NULL;
}
//入栈
void push(linkList &ls, elemStack data)
{
if (!isFull(ls))
{
sNode *newNode = new sNode;
newNode -> data = data;
newNode -> next = ls;
ls = newNode;
}
else
cout << "栈已满,无法入栈";
}
//出栈
void pop(linkList &ls)
{
if (!isEmpty(ls))
{
sNode *delNode = new sNode;
delNode = ls;
ls = ls -> next;
delete delNode;
}
else
cout << "栈空,无法出栈";
}
//返回栈顶元素
elemStack getTop(linkList ls)
{
return ls -> data;
}
//判空
bool isEmpty(linkList ls)
{
if (ls == NULL)
{
return true;
}
else
return false;
}
//判满
bool isFull(linkList ls)
{
sNode *newNode = new sNode;
if (newNode)
{
delete newNode;
return false;
}
else
{
delete newNode;
return true;
}
}
//先序创建二叉树
//对于每个结点,左右孩子为空输入#
void preCreateBT(BTree &bt)
{
elemBTree elem;
cin >> elem;
if (elem == '#')
{
bt = NULL;
}
else
{
bt = new BTNode;//创建新节点
bt -> data = elem;//为结点数据域赋值
preCreateBT(bt -> lChild);//以此创建左右孩子
preCreateBT(bt -> rChild);
}
}
//先序遍历二叉树
//
void preOrder(const BTree &bt)
{
BTNode *node = bt;
linkList ls;
initStack(ls);
while (node || !isEmpty(ls))
{
while (node)
{
visit(node);
if (node -> rChild)
{
push(ls, node);
}
node = node -> lChild;
}
if (!isEmpty(ls))
{
node = getTop(ls);
pop(ls);
node = node -> rChild;
}
}
}
//中序遍历二叉树
void inOrder(const BTree &bt)
{
BTNode *node = bt;
linkList ls;
initStack(ls);
while (node || !isEmpty(ls))
{
while (node)
{
push(ls, node);
node = node -> lChild;
}
if (!isEmpty(ls))
{
node = getTop(ls);
visit(node);
pop(ls);
node = node -> rChild;
}
}
}
//后续遍历二叉树
//需要亲自模拟才能明白其中pre和node==0的作用
void postOrder(const BTree &bt)
{
BTNode *node = bt;
BTNode *pre = NULL;
linkList ls;
initStack(ls);
while (node || !isEmpty(ls))
{
while (node)//找最左边的结点(L)
{
push(ls, node);
node = node -> lChild;
}
if (!isEmpty(ls))//找第一个没有右孩子的结点(R)
{
node = getTop(ls);
if ((node -> rChild == NULL) || (node -> rChild == pre))
//保证访问完右结点在访问根节点
{
visit(node);//(D)
pop(ls);
pre = node;//记录最近一次访问的结点,防止重复访问右结点
node = NULL;//防止重复输入左结点,访问新的左结点,应该在else那里
//跳转至新的右子树,然后访问左结点,用while找最左边的结点
}
else
node = node -> rChild;//当有右孩子的时候,向右转
}
}
}
//访问结点
void visit(BTNode *node)
{
cout << node -> data;
}