二叉树的非递归创建
【算法原理】
利用栈先进后出的特点及栈的相关操作,再加上标记数组,完成二叉树的非递归创建。
注意:
1.顺序栈:a数组用来存每个树节点(tree类型),tag数组(int类型)是标记数组,用来非递归建树和非递归后序遍历。top,始终指向当前栈中元素的下一个位置。
2.标记:0表示没有左子树,1表示左子树已经创建,2表示左右子树都已创建。
算法主要分为七部分:
- 创建根节点:创建一个新节点,并对它进行初始化操作,即:对它的info域赋值,左右孩子指针置空;再用一个移动指针p1指向它,用来代替根节点进行操作,因为根节点指针不能移动。然后把它压入栈中,并标记为0,表示这个节点的没有左孩子,当然也没有右孩子,但是用不着标记,因为是按照前序遍历的顺序来建树,即:根节点-左子树-右子树。先建左树。
- 创建左子树:输入元素非空,即输入不是“#”,并且他的标记是0。即:
if (ch[i] != '#'&&st->tag[st->top - 1] == 0)
。就执行创建左子树的操作。创建一个新结点,并进行初始化(同根节点的操作)。然后把它压入栈中,并标记为0。然后将它连接到树上面,即:p1->lchild = p2;
,然后指针下移,即:p1 = p2;
。 - 创建右子树:输入元素非空,即输入不是“#”,并且他的标记是1。即:
else if (ch[i] != '#'&&st->tag[st->top - 1] == 1)
。就执行创建右子树的操作。同创建左子树。 - 左子树创建完成:输入元素为空,即输入是“#”,并且他的标记是0。即:
else if (ch[i] == '#'&&st->tag[st->top - 1] == 0)
。使该节点的左孩子为空:p1->lchild = NULL;
,并且标记为1. - 右子树创建完成:输入元素为空,即输入是“#”,并且他的标记是1。即:
else if (ch[i] == '#'&&st->tag[st->top - 1] == 1)
。使该节点的右孩子为空:p1->rchild = NULL;
,并且标记为2.,此时表示右子树创建完成。 - 出栈:如果一个节点的标记为2,表示他左右子树都已创建,就对它进行出栈操作。清除标记,即:
st->tag[st->top - 1] = 0;
。出栈,即:p1 = pop(st);
。如果当前栈不是空栈,就取出当前的栈顶元素,相当于从子树往上返一层。并判断返上来的节点的标记是不是1,如果是,则表明它左子树已存在,并且当前指针是从右子树返上来的,就更新标记为2。 - 指针检查:对返上来的指针进行判断,如果它有左子树,即:
if (p1->lchild != NULL )
,就更新标记为1。 - 重复执行以上步骤:重复执行以上步骤,直到每一个元素都已加入树中。
输入:ABDH#K###E##CFI###G#J##
树:
完整代码入下:
#include<stdio.h>
#include<stdlib.h>
#define MAX 1000
typedef struct node//结点
{
char info;
struct node* lchild;
struct node* rchild;
}tree;
typedef struct stack_1//顺序栈
{
tree* a[MAX];//用来存树的每一个结点
int tag[MAX];//起标记作用,用于非递归建树和非递归后序遍历
int top;//始终指向当前栈中元素的下一个位置,下标从零开始
}stack;
void push(stack* st, tree* t)//入栈
{
st->a[st->top] = t;
st->top++;
}
tree* pop(stack* st)//出栈,即删除栈顶元素,并返回指向已删除元素的指针
{
if (st->top != 0)
{
st->top--;
return st->a[st->top];
}
else
return NULL;
}
tree* top(stack* st)//取栈顶元素,但不删除,返回指向栈顶元素的指针。
{
if (st->top != 0)
{
return st->a[st->top - 1];
}
else
{
return NULL;
}
}
tree *create()//非递归建树
{
//0---左孩子为空,1---右孩子为空,2建树完成,“#”代表空;
stack_1 A;
stack_1 *st;
st = &A;
tree *root;//树的跟节点
tree *p1, *p2;//因为跟节点不能动,所有用两个移动指针,用来建树,
int i = 0;//访问ch数组
char ch[MAX];//存放结点的info值的字符数组。
scanf_s("%s", ch, MAX);
st->top = 0;//栈初始化
while (ch[i] != '\0')
{
if (i == 0)//建立根节点
{
root = (tree*)malloc(sizeof(tree));//建立跟节点
root->info = ch[i];
root->lchild = NULL;//左右孩子都置空;
root->rchild = NULL;
p1 = root;//p1代替root操作,因为root不能移动。
push(st, p1);//入栈
st->tag[st->top - 1] = 0;//将他标记为0---左孩子为空,当然右孩子也为空,但是用不着标记,
//因为是按照前序遍历的顺序来建树,即:根节点-左子树-右子树。先建左树
}
else//非根节点
{
if (ch[i] != '#'&&st->tag[st->top - 1] == 0)//建左树(元素非空,即输入不是“#”,并且他的标记是0);
{
p2 = (tree*)malloc(sizeof(tree));//创建一个新结点
p2->info = ch[i];
p2->lchild = NULL;//一定要有,不然会和下面的代码冲突,可以看做是对这个结点的初始化;
p2->rchild = NULL;
push(st, p2);//入栈
p1->lchild = p2;//将新创建的左孩子连接的树上
p1 = p2;//指针下移,即:指针指向现在的左孩子。
st->tag[st->top - 1] = 0;//标记为0,表示此节点没有左孩子
}
else if (ch[i] == '#'&&st->tag[st->top - 1] == 0)//左树完成
{
p1->lchild = NULL;
st->tag[st->top - 1] = 1;//左子树构建完成
}
else if (ch[i] == '#'&&st->tag[st->top - 1] == 1)//右树完成
{
p1->rchild = NULL;
st->tag[st->top - 1] = 2;//右子树构建完成,即:这课小树构建完成;
}
else if (ch[i] != '#'&&st->tag[st->top - 1] == 1)//建右树
{
p2 = (tree*)malloc(sizeof(tree));
p2->info = ch[i];
p2->lchild = NULL;
p2->rchild = NULL;
push(st, p2);
p1->rchild = p2;
p1 = p2;
st->tag[st->top - 1] = 0;
}
while (st->tag[st->top - 1] == 2)//是否出栈操作,当左右子树都已建立时,出栈
{
st->tag[st->top - 1] = 0;//出栈之后,清除标记
p1 = pop(st);//出栈
if (st->top != 0)//避免最后一个节点误操作,如果没有此句,会导致栈的top越界
p1 = top(st);//取当前的栈顶元素
else
break;//所有元素均已出栈,当前的栈为空
if (st->tag[st->top - 1] == 1)//说明此时结点的左子树已存在,并且当前指针是从下一右子树返上来的结点,即:右子树也存在;
{
st->tag[st->top - 1] = 2;
}
}
if (p1->lchild != NULL || st->tag[st->top - 1] ==1)//对返上来的结点进行判断,有左子树则改变标记为1
{
st->tag[st->top - 1] = 1;
}
}
i++;//输入下一个元素
}
return root;
}
void preprint(tree* t)//递归前序输出
{
tree* p1;
p1 = t;
if (!p1)
return;
else
{
printf("%c->", p1->info);
preprint(p1->lchild);
preprint(p1->rchild);
}
}
void inorprint(tree* t)
{
tree* p1;
p1 = t;
if (!p1)
return;
else
{
inorprint(p1->lchild);
printf("%c->", p1->info);
inorprint(p1->rchild);
}
}
int main()
{
tree* root;
printf("输入一组数据(以#分隔):\n");
root = create();
printf("前序遍历:");
preprint(root);
printf("\n");
printf("后序遍历:");
inorprint(root);
printf("\n");
return 0;
}
创建出的树:
输出结果