前言
2022考研初试结束,总结了一些考研中基本常用算法。这篇主要是关于树的前中后遍历,递归实现和非递归实现两种,现在很多自命题在考算法的时候很喜欢要求同时写出递归和非递归两种实现。最后还有层次遍历的实现。代码实现,试卷上可用,上机运行可以结合注释完善一下。
一、递归实现树的遍历
//递归实现看起来十分简洁,但有时候并不是很好理解
void preorder(BiTree bt) { //先序遍历
if (bt) {
//visit(bt);
cout << bt->data << endl;
preorder(bt->lchiled);
preorder(bt->rchiled);
}
}
void inorder(BiTree bt) { //中序遍历
if (bt) {
inorder(bt->lchiled);
//visit(bt);
cout << bt->data << endl;
inorder(bt->rchiled);
}
}
void postorder(BiTree bt) { //后序遍历
if (bt) {
postorder(bt->lchiled);
postorder(bt->rchiled);
//visit(bt);
cout << bt->data << endl;
}
}
二、非递归实现
对于递归算法转非递归实现,一般都是借用栈来实现,下面非递归算法的实现都是用栈来实现的,其中前中序遍历好理解些,后序遍历则相对复杂些。
void preorder2(BiTree T) { //先序
InitStack(s); //初始化栈S
BiTree p = T;
while (p || !IsEmpty(s)) { //栈不空或者p不为空
if (p) {
visit(p); //访问结点
push(s, p); //进栈
p = p->lchiled; // 遍历左子树
}
else {
pop(s, p); //栈顶结点出栈
p = p->rchiled; //遍历右子树
}
}
}
void inorder2(BiTree T) { //先序
InitStack(s); //初始化栈S
BiTree p = T;
while (p || !IsEmpty(s)) { //栈不空或者p不为空
if (p) {
push(s, p); //进栈
p = p->lchiled; // 遍历左子树
}
else {
pop(s, p); //栈顶结点出栈
visit(p); //访问结点
p = p->rchiled; //遍历右子树
}
}
}
void postorder2(BiTree T) { //先序
InitStack(s); //初始化栈S
BiTree p = T;
BiTree r = NULL;
while (p || !IsEmpty(s)) { //栈不空或者p不为空
if (p) {
push(s, p); //进栈
p = p->lchiled; // 遍历左子树
}
else {
GetTop(s, p); //读取栈顶结点,该结点不出栈
if (p->rchiled && p->rchiled != r) { //右孩子存在且未被访问
p = p->rchiled; //遍历右孩子
push(s, p);
p = p->lchiled;
}
else {
pop(s, p); //栈顶结点出栈
visit(p); //访问结点
r = p;
p = NULL;
}
}
}
}
层次遍历
层次遍历的实现是通过一个辅助队列实现的。
void LevelOrder(BiTree bt) { //层次遍历
InitQueue(Q); //初始化辅助队列
BiTree p;
EnQueue(Q, bt); //根结点入队
while (!IsEmpty(Q)) { //队不空
DeQueue(Q, p); //队头结点出队
visit(p); //访问该结点
if (p->lchiled)
EnQueue(Q, p->lchiled); //左孩子入队
if (p->rchiled)
EnQueue(Q, p->rchiled); //右孩子入队
}
}
总结
在树的算法中,前中后序遍历和层次遍历是实现其他很多相关算法的基础,比如查找两个结点的公共祖先、根节点到叶子节点的路径以及求树的高度和宽度等。
借鉴书籍:王道的考研辅导书和严蔚敏版的《数据结构》。