思考需要时间,做决定需要勇气
前言
按照已知二叉树,从键盘读入节点字符,建立二叉树(例如:ABD#G###CE##FH###);分别采
用先序、中序、后序、按层遍历该二叉树,分别输出遍历结果。
提示:以下是本篇文章正文内容,下面案例可供参考
一、基本思想
二叉树与链表类似,不同之处在于:二叉树具有两个指针域,分别指向他的左子树和右子树,因此处理的方法与链表类似。
二、算法设计
- 先序创建树:因为先序创建的顺序为根左右,因此我们可以调用递归的方法,先创建根节点,然后调用递归的思想创建根节点的左子树的根节点,如此循序下去,当遇见#号时,判定节点值为空,当左右结点都为空时,回到上一节点继续右子树的赋值。
- 先序遍历树:采用递归的思想,先判断根结点是否存在值,若存在则访问,,再调用递归访问左子树的根节点的值,直到左子树访问完了,在调用递归访问右子树的值。
- 中序遍历树和后序遍历树:思想与先序同理,不同之处在于访问的顺序不同,这里将不再冗余阐述。
- 按层遍历树:这里在用了队列先进先出得思想保存了结点的值:实现流程为:先判断树是否为空,若不为空则将根节点入队,将其保存到cur结点中,再将队头元素输出。使用队列主要是因为队列是先进先出,可以满足遍历条件。
- 先序遍历非递归:只要采用循环判断和栈的思想。首先判断树是否为空,不为空则将根节点入栈,进入循环语句,将根节点赋给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;
}
总结
- 采用递归的复杂度分析:
- 时间复杂度为O(n),其中n为二叉树的节点数。
- 空间复杂度为O(h),其中h为二叉树的高度,因为该算法使用了递归,每次递归会消耗一定的系统栈空间。
- 未采用递归的复杂度分析:
- 使用了栈来模拟递归过程,时间复杂度为O(n),其中n为二叉树的节点数。
- 空间复杂度最坏情况下为O(n),即当二叉树退化成链表时,需要将所有节点压入栈中。平均情况下空间复杂度为O(h),其中h为二叉树的高度,因为栈中最多同时存储一条从根节点到当前节点的路径。
- 按层遍历复杂度分析:
- 时间复杂度是O(n),其中n是二叉树中节点的数量。因为每个节点都被访问了一次,并且每次访问操作的时间是常数。
- 空间复杂度也是O(n),因为它需要一个队列来存储每一层的节点,而在任何给定层上的节点的数量最多大约是总节点数的一半(对于平衡的二叉树),因此队列的大小可能会增长到O(n/2)
= O(n)。