算法设计思路
二叉树的建立采用struct指针建立结点,每个结点内建两个struct指针来指向它的左右孩子,其中建立方法可采用先序,中序、后序。这里仅介绍先序建树,中序建树和后序建树实际上殊途同归。
建树代码如下
typedef struct node
{
char data;
int visit = 0;
struct node *l, *r;
} btree, *Btree;
void build(Btree &t)
/**
* @description: 建树
* 采用先序建树,先根后左右
* @param {*Btree &t}
*/
{
char s;
sc("%c", &s);
if (isdigit(s))
{
t = new btree;
t->data = s;
build(t->l);
build(t->r);
}
else
t = NULL;
}
这边先简单叙述一下二叉树的先序、中序、后序遍历的递归方法。首先对于先序遍历,采用根左右的顺序输出,所以每遇到一个结点就先输出它对应的值,再先递归它的左孩子然后递归它的右孩子。
代码如下
void pre_rec(Btree t)
/**
* @description: 递归先序遍历二叉树
* @param {*Btree t}
*/
{
if (t != NULL)
{
pr("%c ", t->data);
pre_rec(t->l);
pre_rec(t->r);
}
}
void in_rec(Btree t)
/**
* @description: 递归中序遍历二叉树
* @param {*Btree t}
*/
{
if (t != NULL)
{
in_rec(t->l);
pr("%c ", t->data);
in_rec(t->r);
}
}
void post_rec(Btree t)
/**
* @description: 递归后序遍历二叉树
* @param {*Btree t}
*/
{
if (t != NULL)
{
post_rec(t->l);
post_rec(t->r);
pr("%c ", t->data);
}
}
先序遍历的非递归方法: 从根结点开始往左孩子方向遍历,每遍历到一个元素就把它对应的值输出,然后将该结点入栈,直至左孩子为空,然后弹出栈顶结点,遍历其右子树,如此往复直至栈空且结点为空。
void pre_transe(Btree ti)
/**
* @description: 非递归先序遍历二叉树
* 从根结点开始往左孩子方向遍历,每遍历到一个元素就
* 把它对应的值输出,然后将该结点入栈,直至左孩子为
* 空,然后弹出栈顶结点,遍历其右子树,如此往复直至
* 栈空且结点为空。
* @param {*Btree ti}
*/
{
stack<Btree> s;
while (ti != NULL || !s.empty())
{
while (ti != NULL)
{
pr("%c ", ti->data);
s.push(ti);
ti = ti->l;
}
if (!s.empty())
{
ti = s.top()->r;
s.pop();
}
}
}
非递归中序遍历二叉树 从根结点开始往左孩子方向遍历,然后将该结点入栈,直至左孩子为空,然后弹出栈顶结点并输出该结点对应的元素的值,接着遍历其右子树如此往复直至栈空且结点为空。
void in_transe(Btree ti)
/**
* @description: 非递归中序遍历二叉树
* 从根结点开始往左孩子方向遍历,然后将该结点入栈,
* 直至左孩子为空,然后弹出栈顶结点并输出该结点对
* 应的元素的值,接着遍历其右子树如此往复直至栈空
* 且结点为空。
* @param {*Btree ti}
*/
{
stack<Btree> s;
while (ti != NULL || !s.empty())
{
while (ti != NULL)
{
s.push(ti);
ti = ti->l;
}
if (!s.empty())
{
ti = s.top();
s.pop();
pr("%c ", ti->data);
ti = ti->r;
}
}
}
非递归后序遍历二叉树从根节点开始顺序遍历其左孩子,并将每个顺序遍历到的左孩子入栈同时标记其入栈次数,当左孩子为空 时,弹出栈顶元素,判断栈顶元素入栈次数,若为2则输出栈顶元素对应的值,并将栈顶结点置为空,避免陷入死循环,若为1,则将该节点再次入栈,并自增其入栈次数,然后遍历其右子树,如此往复,直至栈空且结点为空。
void post_transe(Btree ti)
/**
* @description: 非递归后序遍历二叉树
* 从根节点开始顺序遍历其左孩子,并将每个顺序遍历
* 到的左孩子入栈同时标记其入栈次数,当左孩子为空
* 时,弹出栈顶元素,判断栈顶元素入栈次数,若为2则
* 输出栈顶元素对应的值,并将栈顶结点置为空,避免
* 陷入死循环,若为1,则将该节点再次入栈,并自增其
* 入栈次数,然后遍历其右子树,如此往复,直至栈空
* 且结点为空。
* @param {*Btree ti}
*/
{
stack<Btree> s;
while (ti != NULL || !s.empty())
{
while (ti != NULL)
{
ti->visit = 1;
s.push(ti);
ti = ti->l;
}
if (!s.empty())
{
ti = s.top();
s.pop();
if(ti->visit == 1)
{
ti->visit++;
s.push(ti);
ti = ti->r;
}
else
{
if(ti->visit == 2)
{
pr("%c ", ti->data);
ti = NULL;
}
}
}
}
}
层序遍历二叉树将根节点入队后,逐一弹出队首元素输出它对应的值并将队首元素的左右孩子入队,如此往复,直至队空
void level_transe(Btree t)
/**
* @description: 层序遍历二叉树
* 将根节点入队后,逐一弹出队首元素输出它对应的值
* 并将队首元素的左右孩子入队,如此往复,直至队空
* @param {*Btree t}
*/
{
queue<btree> q;
if (t != NULL)
{
q.push(*t);
btree ti;
while (!q.empty())
{
ti = q.front();
q.pop();
pr("%c ", ti.data);
if (ti.l != NULL)
q.push(*ti.l);
if (ti.r != NULL)
q.push(*ti.r);
}
}
}