二叉树的构建和前中后序遍历

在描述二叉树的前中后序遍历之前,我们要先了解什么是树。根据教材上的定义,树是一个n(n>0)的有限集,且在任意一颗非空树中,有且仅有一个特定的结点称为根,且当 n>1 时,其余结点可分为m(m>0)个互不相交的有限集,其中每一个本身又是一棵树,并且称为根的子树。简单来说,树除了根以外的每一个结点都有且仅有一个前驱结点,称为双亲结点,可以有0个、1个、2个甚至多个后继结点,称为孩子结点。双亲结点相同的结点,称为兄弟结点。结点拥有的子树个数,称为子树的度,而树的度,是树中各结点度的最大值。

而二叉树,又是树中的特例,二叉树是度为2,且子树有左右之分的树。因此可以说二叉树是度为2的树,但不能说度为2的数是二叉树,因为二叉树的子树有左右之分,左子树与右子树即使有一方不存在,另一方仍为左子树或右子树。

所以从二叉树的数据结构就可以看出,对它的构建和遍历并不像顺序表、链表等线性表那样方便。不管是创建二叉树还是遍历二叉树,都需要使用函数的递归调用。

比如二叉树的构建,就需要使用递归调用。如果输入的数字大于零,则构建一个结点并将该数字存入结点的数据域中,然后开始构建该结点的左子树或右子树,当输入小于零的数字时,另该结点的值为空,然后返回,继续执行未完成的函数:

void creattree(tnode** t) {
	int a;
	cin >> a;
	if (a < 0)
		*t = NULL;
	else {
		*t = new tnode;
		(*t)->data = a;
		creattree(&(*t)->ltnode);
		creattree(&(*t)->rtnode);
	}
}

而相较于构建,遍历的操作更多样,可以根据根节点的输出顺序分为前序遍历、中序遍历和后序遍历。对于这三种遍历,显然较为方便的是利用函数递归,只调整数据输出的位置即可:

void preorder(tnode* t) {
	if (t) {
		cout << t->data;
		preorder(t->ltnode);
		preorder(t->rtnode);
	}
}

void midorder(tnode* t) {
	if (t) {
		midorder(t->ltnode);
		cout << t->data;
		midorder(t->rtnode);
	}
}

void lastorder(tnode* t) {
	if (t) {
		lastorder(t->ltnode);
		lastorder(t->rtnode);
		cout << t->data;
	}
}

 当然,也可以不使用函数递归的方式进行二叉树的后序遍历,但是代码较为复杂。为了实现后序遍历的非递归算法,可以使用两个栈,其中一个栈存放第一次经过的结点,另一个栈存放第二次经过的点,如果第一个栈中不存在第二个栈中结点的子孙结点,则将第二个栈中的该结点输出。

int notin(SqStack sq1, SqStack sq2) {
	for (int i = 0; i < sq1.len; i++) {
		if ((*(sq2.top - 1))->rtnode == *(sq1.base + i))
			return 0;
	}
	return 1;
}
void lastorder2(tnode* t) {
	SqStack sq1, sq2;
	sq1.base = new tnode*;
	sq1.top = sq1.base;
	sq2.base = new tnode*;
	sq2.top = sq2.base;
	while (t || sq1.len >= 0 || sq2.len >= 0) {
		if (t) {
			push(sq1, t);
			t = t->ltnode;
			continue;
		}
		else {
			while (1) {
				t = pop(sq1);
				push(sq2, t);
				t = t->rtnode;
				if (!t) {
					t = pop(sq2);
					cout << t->data;
					if (sq2.len > 0)
						while (notin(sq1, sq2) && sq2.len > 0) {
							t = pop(sq2);
							cout << t->data;
							if (sq2.len == 0)
								break;
						}
				}
				else {
					break;
				}
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值