数据结构之二叉树的构建与遍历

思考需要时间,做决定需要勇气


前言

按照已知二叉树,从键盘读入节点字符,建立二叉树(例如:ABD#G###CE##FH###);分别采
用先序、中序、后序、按层遍历该二叉树,分别输出遍历结果。
在这里插入图片描述


提示:以下是本篇文章正文内容,下面案例可供参考

一、基本思想

二叉树与链表类似,不同之处在于:二叉树具有两个指针域,分别指向他的左子树和右子树,因此处理的方法与链表类似。

二、算法设计

  1. 先序创建树:因为先序创建的顺序为根左右,因此我们可以调用递归的方法,先创建根节点,然后调用递归的思想创建根节点的左子树的根节点,如此循序下去,当遇见#号时,判定节点值为空,当左右结点都为空时,回到上一节点继续右子树的赋值。
  2. 先序遍历树:采用递归的思想,先判断根结点是否存在值,若存在则访问,,再调用递归访问左子树的根节点的值,直到左子树访问完了,在调用递归访问右子树的值。
  3. 中序遍历树和后序遍历树:思想与先序同理,不同之处在于访问的顺序不同,这里将不再冗余阐述。
  4. 按层遍历树:这里在用了队列先进先出得思想保存了结点的值:实现流程为:先判断树是否为空,若不为空则将根节点入队,将其保存到cur结点中,再将队头元素输出。使用队列主要是因为队列是先进先出,可以满足遍历条件。
  5. 先序遍历非递归:只要采用循环判断和栈的思想。首先判断树是否为空,不为空则将根节点入栈,进入循环语句,将根节点赋给cur后将根节点出栈,后判断根节点是否有左右子树,有则入栈,如此循环,直到栈为空则遍历完成。使用栈主要是因为栈的先进后出,若是右子结点先入栈,左子结点后入栈则可满足先序遍历条件。

三、代码实现

# include<iostream>
# include<queue>
# include<stack>
using namespace std;

typedef struct biTNode {
	char val;
	struct biTNode* lchild,* rchild;
} biTree;

biTree* CreatbiTreeFromFont() { //前序创建树
	biTNode* t;
	char chr;
	cin >> chr;
	if(chr == '#') {
		t = NULL;
	} else {
		t = new biTree;
		t->val = chr;
		cout<<"请输入"<<chr<<"的左子树:";
		t->lchild = CreatbiTreeFromFont();
		cout<<"请输入"<<chr<<"的右子树:";
		t->rchild = CreatbiTreeFromFont();
	}
	return t;
}

void PreOrderTraverse(biTree *t) { //前序遍历
	if(t) {
		cout<<t->val<<" ";
		PreOrderTraverse(t->lchild);
		PreOrderTraverse(t->rchild);
	}
}

void MidOrderTraverse(biTree *t) { //中序遍历
	if(t) {
		MidOrderTraverse(t->lchild);
		cout<<t->val<<" ";
		MidOrderTraverse(t->rchild);
	}
}

void BackOrderTraverse(biTree *t) { //后序遍历
	if(t) {
		BackOrderTraverse(t->lchild);
		BackOrderTraverse(t->rchild);
		cout<<t->val<<" ";
	}
}

void levelOrderTraversal(biTree* t) {//按层遍历
	if (t == NULL)
		return;
	queue<biTree*> q;
	q.push(t);
	cout<<" "; 
	while (!q.empty()) {
		biTree* cur = q.front();
		q.pop();
		cout << cur->val << " ";
		if (cur->lchild != NULL)
			q.push(cur->lchild);
		if (cur->rchild != NULL)
			q.push(cur->rchild);
	}
}

void preOrderTraversal(biTree* t) { //先序非递归 
	if (t == NULL) return;
	stack<biTree*> s;
	s.push(t);
	while (!s.empty()) {
		biTree* cur = s.top();
		s.pop();
		cout << cur->val << " ";
		if (cur->rchild != NULL)  s.push(cur->rchild);
		if (cur->lchild != NULL)  s.push(cur->lchild);
	}
}
int main() {
	biTree *T;
	cout<<"前序创建"<<endl;
	cout<<"请输入结点的值:";
	T = CreatbiTreeFromFont();
	cout<<"前序遍历:";
	PreOrderTraverse(T);
	cout<<endl;
	cout<<"中序遍历:";
	MidOrderTraverse(T);
	cout<<endl;
	cout<<"后序遍历:";
	BackOrderTraverse(T);
	cout<<endl;
	cout<<"按层遍历:";
	levelOrderTraversal(T);
	cout<<endl;
	cout<<"先序非递归:";
	preOrderTraversal(T);
	cout<<endl;
	return 0;
}

总结

  1. 采用递归的复杂度分析:
  • 时间复杂度为O(n),其中n为二叉树的节点数。
  • 空间复杂度为O(h),其中h为二叉树的高度,因为该算法使用了递归,每次递归会消耗一定的系统栈空间。
  1. 未采用递归的复杂度分析:
  • 使用了栈来模拟递归过程,时间复杂度为O(n),其中n为二叉树的节点数。
  • 空间复杂度最坏情况下为O(n),即当二叉树退化成链表时,需要将所有节点压入栈中。平均情况下空间复杂度为O(h),其中h为二叉树的高度,因为栈中最多同时存储一条从根节点到当前节点的路径。
  1. 按层遍历复杂度分析:
  • 时间复杂度是O(n),其中n是二叉树中节点的数量。因为每个节点都被访问了一次,并且每次访问操作的时间是常数。
  • 空间复杂度也是O(n),因为它需要一个队列来存储每一层的节点,而在任何给定层上的节点的数量最多大约是总节点数的一半(对于平衡的二叉树),因此队列的大小可能会增长到O(n/2)
    = O(n)。
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘子☆心酸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值