非递归创建二叉树

二叉树的非递归创建

【算法原理】

利用栈先进后出的特点及栈的相关操作,再加上标记数组,完成二叉树的非递归创建。

注意:

1.顺序栈:a数组用来存每个树节点(tree类型),tag数组(int类型)是标记数组,用来非递归建树和非递归后序遍历。top,始终指向当前栈中元素的下一个位置。
2.标记:0表示没有左子树,1表示左子树已经创建,2表示左右子树都已创建。

算法主要分为七部分:

  1. 创建根节点:创建一个新节点,并对它进行初始化操作,即:对它的info域赋值,左右孩子指针置空;再用一个移动指针p1指向它,用来代替根节点进行操作,因为根节点指针不能移动。然后把它压入栈中,并标记为0,表示这个节点的没有左孩子,当然也没有右孩子,但是用不着标记,因为是按照前序遍历的顺序来建树,即:根节点-左子树-右子树。先建左树。
  2. 创建左子树:输入元素非空,即输入不是“#”,并且他的标记是0。即:if (ch[i] != '#'&&st->tag[st->top - 1] == 0)。就执行创建左子树的操作。创建一个新结点,并进行初始化(同根节点的操作)。然后把它压入栈中,并标记为0。然后将它连接到树上面,即:p1->lchild = p2;,然后指针下移,即:p1 = p2;
  3. 创建右子树:输入元素非空,即输入不是“#”,并且他的标记是1。即:else if (ch[i] != '#'&&st->tag[st->top - 1] == 1)。就执行创建右子树的操作。同创建左子树。
  4. 左子树创建完成:输入元素为空,即输入是“#”,并且他的标记是0。即:else if (ch[i] == '#'&&st->tag[st->top - 1] == 0)。使该节点的左孩子为空:p1->lchild = NULL;,并且标记为1.
  5. 右子树创建完成:输入元素为空,即输入是“#”,并且他的标记是1。即:else if (ch[i] == '#'&&st->tag[st->top - 1] == 1)。使该节点的右孩子为空:p1->rchild = NULL;,并且标记为2.,此时表示右子树创建完成。
  6. 出栈:如果一个节点的标记为2,表示他左右子树都已创建,就对它进行出栈操作。清除标记,即:st->tag[st->top - 1] = 0;。出栈,即:p1 = pop(st);。如果当前栈不是空栈,就取出当前的栈顶元素,相当于从子树往上返一层。并判断返上来的节点的标记是不是1,如果是,则表明它左子树已存在,并且当前指针是从右子树返上来的,就更新标记为2。
  7. 指针检查:对返上来的指针进行判断,如果它有左子树,即:if (p1->lchild != NULL ),就更新标记为1。
  8. 重复执行以上步骤:重复执行以上步骤,直到每一个元素都已加入树中。

输入: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;
}

创建出的树:
在这里插入图片描述

输出结果
在这里插入图片描述

  • 15
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值