题目:
实现上述二叉树的先序、中序和后序遍历的递归和非递归算法;
思路:
(1) 前序遍历递归算法:利用递归,先输出结点,在搜索左子树,最后搜索右子树
(2) 中序遍历递归算法:利用递归,先搜索左子树,再输出结点,最后搜索右子树
(3) 后序遍历递归算法:利用递归,先搜索左子树,在搜索右子树,最后输出结点
(4) 前序遍历非递归算法:建立一个栈来存储树结点,首先将首根结点放入栈,接着,利用循环,循环中获取栈顶元素并弹出,依次放入栈顶元素的右子树和左子树(栈后进先出,前序遍历先左后右,入栈先右后左),直到栈空即可
(5) 中序遍历非递归算法:建立一个栈来存储树结点,建立循环,将结点的左子树放入栈,当结点不存在左子树时,将临时结点初始化为栈顶元素,弹出栈顶元素,将临时结点变为其右子树即可
(6) 后序遍历非递归算法:后序遍历利用栈需要记录结点使用次数,一个结点只有使用了两次的时候,左右子树才均以使用,所以利用map来记录结点使用次数,首先建立循环,找左子树并入栈,入栈结点使用次数为1,当左子树找完时,临时结点设置为栈顶元素,如果该结点使用次数为2,直接输出结点值并弹出栈,否则将访问其右子树,将其访问次数置为2。
代码块:
#include "pch.h"
#include <iostream>
#include<stack>
#include<set>
#include<map>
using namespace std;
struct Btree {
char data;
Btree *lchild;
Btree *rchild;
};
void create(Btree*&root)//创建二叉树
{
char data;
cin >> data;
root = new Btree;
if (data == '#') root = NULL;
if (root!=NULL)
{
root->data = data;
cout<<"请输入" <<data<< "的左子树:" << endl; create(root->lchild);
cout << "请输入" << data << "的右子树:" << endl; create(root->rchild);
}
}
void preorder(Btree*&root)//前序遍历递归算法
{
if(root!=NULL)
{
cout << root->data << "\t";
if(root->lchild)preorder(root->lchild);
if (root->rchild)preorder(root->rchild);
}
}
void ldr(Btree *&tree)//中序遍历递归算法
{
if (tree != NULL)
{
if(tree->lchild)ldr(tree->lchild);
cout << tree->data << '\t';
if (tree->rchild)ldr(tree->rchild);
}
}
void lrd(Btree *&tree)//后序遍历递归算法
{
if (tree != NULL)
{
if (tree->lchild)lrd(tree->lchild);
if (tree->rchild)lrd(tree->rchild);
cout << tree->data << '\t';
}
}
void NORecursionprd(Btree *&tree){//前序非递归算法
Btree *p = tree;
stack<Btree*> s;
s.push(tree);
while (!s.empty())
{
p = s.top();//获取栈顶元素
s.pop();//弹出栈顶元素
cout << p->data << '\t';
if (p->rchild) s.push(p->rchild);//先将右子树入栈
if (p->lchild)s.push(p->lchild);//再将左子树入栈,栈后进先出,符合前序遍历规则
}
}
void NORecursionldr(Btree*&tree)//中序遍历非递归算法
{
stack<Btree*> s;//建立栈
Btree *p = tree;
while (p != NULL || !s.empty()) {
while (p != NULL) {//依次将每个结点的左子树放入栈
s.push(p);
p = p->lchild;
}
if (!s.empty()) {//在栈非空时找到栈顶元素的右子树
p = s.top();
s.pop();
cout << p->data<<'\t';//弹出栈顶元素,实现中序遍历
p = p->rchild;
}
}
}
void NORecursionlrd(Btree *&tree)
{
map<Btree*, int>judge;//利用map记录访问次数
stack<Btree*>s;//利用栈来模拟后序遍历
Btree*p=tree;//临时保存结点
while (p != NULL || !s.empty())
{
if(p!=NULL)//如果结点不为空,一直往下找其左子树
{
s.push(p);
p = p->lchild;
judge[p] = 1;
}
else {//结点为空
p = s.top();//取栈顶元素
if (judge[p] == 2) {//若访问过两次,说明左右子树均已经访问,直接输出其数据即可
s.pop();
cout << p->data << '\t';
p = NULL;
}
else {//否则将访问其右子树,将其访问次数置为2
judge[p] = 2;
p = p->rchild;
}
}
}
}
int main()
{
Btree*tree=new Btree;
cout << "请输入首根结点数据:";
if (tree == NULL) cout << "树为空树!\n";
else{
create(tree);
cout << "该树递归前序遍历的结果为:\n";
preorder(tree);
cout<<endl << "该树非递归前序遍历的结果为:\n";
NORecursionprd(tree);
cout << endl << "该树递归中序遍历的结果为:\n";
ldr(tree);
cout << endl << "该树非递归中序遍历的结果为:\n";
NORecursionldr(tree);
cout << endl << "该树递归后序遍历的结果为:\n";
lrd(tree);
cout << endl << "该树非递归后序遍历的结果为:\n";
NORecursionlrd(tree);
}
}
效果图: