我们参照递归过程中栈的变化情况适用堆栈来解决 。首先将二叉树进行扩展 ,如下图所示 :
然后按先序遍历的顺序输入节点的信息 ,根据输入的信息设置一个标志位 flag,
并初始化为1。 flag = 1表示现在需要创建当前节点的左孩子,flag = 2表示需要创建右孩子,flag = 3则表示当前节点的左右孩子都已经创建完毕,需要执行出栈操作,直到出栈节点不是当前栈顶节点的右孩子为止。
具体如下:
1) 当前要创建的节点值为′#′并且 flag=1,则置 flag=2,当前节点的左孩子创建节束,转向创建右孩子。
2) 当前要创建的节点值不为 ′#′并且 flag = 1,创建当前节点并作为栈顶节点的左孩子,同时将当前节点入栈。
3) 当前要创建的节点值不为 ′#′并且 flag = 2,创建当前节点并作为栈顶节点的右孩子,同时将当前节点入栈,然后置 flag=1,转向左孩子节点的创建。
4) 当前要创建的节点值为 ′#′并且 flag = 2,则置flag = 3,说明当前节点的父节点左右孩子节点处理节束,应将栈顶节点出栈 。如果出栈的节点依然等于栈顶节点的右孩子,说明当前栈顶节点的左右孩子节点也处理节束,栈顶节点继续出栈。直到当前栈顶节点的右孩子节点不等于出栈的节点为止。
实现代码如下:
#include <iostream>
using namespace std;
#include <deque>
typedef struct node
{
char data;
struct node *lchild;
struct node *rchild;
}BiNode, *BiTree;
// 二叉树的建立(非递归)(按照先序遍历的顺序来生成一颗二叉树)
BiTree createBiTree()
{
char ch[20];
scanf("%s", ch);
int len = (int)strlen(ch);
BiTree stack[20]; // 用来存储节点地址的栈
int top = -1; // 栈顶指针
int flag = 1; // 标志位
int i = 0;
if (ch[i] == '#')
return NULL;
BiTree temp;
BiTree root = new BiNode();
root->data = ch[i++]; // 此处应该加一个判断首字符是否为‘#’的判断,保证根节点不为空。
root->lchild = NULL;
root->rchild = NULL;
stack[++top] = root; // 根节点入栈
while (i < len)
{
BiTree pNew = NULL;
if (flag == 1) // 创建左孩子
{
if (ch[i] == '#')
flag = 2;
else
{
pNew = new BiNode();
pNew->data = ch[i];
pNew->lchild = NULL;
pNew->rchild = NULL;
temp = stack[top]; // 栈顶元素(取出栈顶元素赋予temp,注意,这不是出栈操作,因为栈顶指针top没有变)
temp->lchild = pNew;
stack[++top] = pNew; // 栈顶元素的左子树入栈
flag = 1;
}
}
else if (flag == 2) // 创建右孩子
{
if (ch[i] == '#')
flag = 3;
else
{
pNew = new BiNode();
pNew->data = ch[i];
pNew->lchild = NULL;
pNew->rchild = NULL;
temp = stack[top]; // 栈顶元素
temp->rchild = pNew;
stack[++top] = pNew; // 栈顶元素的右子树入栈
flag = 1;
}
}
else // 左右孩子都已经创建完毕
{
temp = stack[top--]; // 栈顶元素出栈,并修改栈顶指针
while (top > 0 && stack[top]->rchild == temp) // 若此时栈中的元素个数仍大于1个,并且刚刚出栈的元素是当前栈顶元素的右子树,则继续让栈顶元素出栈,并修改栈顶指针。
--top;
flag = 2; // 跳出此while循环时,创建当前栈顶节点的右孩子,此时的i在ch[]中对应的数据刚好就是下一个待使用的数据,所以执行 --i是为了防止下面的 ++i跳过了该数据(即当前i对应的数据就是我们下一步创建右子树所应该使用的数据)。
--i;
}
++i;
}
return root;
}
// 二叉树的分层打印
void PrintTreeByLevel(BiTree T)
{
if(T == NULL) return;
deque<BiTree> q;
q.push_back(T);
int curLevelNum; // 当前层的节点数
while (q.size())
{
curLevelNum = (int)q.size(); // 此处要做类型转换,因为size()返回值为size_type类型;
while(curLevelNum-- > 0) // 一直访问到当前层的最后一个节点
{
BiTree tmp = q.front();
q.pop_front();
printf("%c ", tmp->data);
if(tmp->lchild)
q.push_back(tmp->lchild);
if(tmp->rchild)
q.push_back(tmp->rchild);
}
printf("\n"); // 当前层的元素输出完毕后,换行;
}
}
int main(int argc, const char * argv[]) {
BiTree T = createBiTree();
PrintTreeByLevel(T); // 通过二叉树的分层打印,能更直观的验证创建的二叉树是否正确。
return 0;
}