数据结构那时二叉树学得不是很深入,理解不够,借这段时间的复习,把二叉树的先序,中序,后序,层次遍历的各种实现重新的理解了一遍,在vs2017上码了一遍,然后我把函数都逐一写进了头文件。
.
其中《大话数据结构》中只讲到了先中后的递归算法,所以我也将他们的非递归版本也想写出来,有始有终,整理下也便于今后的学习。
.
讲到非递归的实现,我们都听过“递归的过程就是出入栈的过程”,所有的递归都可以写成非递归版本,具体都是用栈的push和pop来模拟递归的“有来有回”。统一来说,递归算法换成非递归就是使用栈和回溯的思想来实现。
.
1、先序递归、非递归实现
/*头文件bitree_pre*/
#include <iostream>
#include <stack>
using namespace std;
struct bitreenode {
int data;
bitreenode *lchild, *rchild;
};
/*
//也可以这样
typedef struct bitreenode {
int data;
bitreenode *lchild, *rchild;
}*bitree;
//下面形参改为bitree root即可
*/
class bitree_preTraverse
{
public:
//递归法
void pre_recurrece(bitreenode *root)
{
if (root == NULL)
return;
cout << root->data << endl;
pre_recurrece(root->lchild);
pre_recurrece(root->rchild);
}
//非递归法,方法有很多,这里使用较广泛的,可用于先、中序
//使用栈来进行回溯,遍历完左子树后,回溯逐一遍历右子树
void pre_unrecurrece(bitreenode *root)
{
stack<bitreenode*> s;
while (root != NULL || !s.empty())
{
if (root != NULL)//完成三步工作,将根节点out出来,压入栈,遍历到最左
{
cout << root->data << endl;
s.push(root);
root = root->lchild;
}
else//到最左后,完成三步工作,读出NULL的前一个,结点已经遍历完pop掉,轮到该根结点右子树
{
root = s.top();
s.pop();
root=root->rchild;
}
}
}
};
.
2、中序递归、非递归实现
/*头文件bitree_mid*/
#include <iostream>
#include <stack>
using namespace std;
struct bitreenode {
int data;
bitreenode *lchild, *rchild;
};
/*
//也可以这样
typedef struct bitreenode {
int data;
bitreenode *lchild, *rchild;
}*bitree;
//下面改为bitree root即可
*/
class bitree_midTraverse
{
public:
//递归法
void mid_recurrece(bitreenode *root)
{
if (root == NULL)
return;
//就换下顺序
mid_recurrece(root->lchild);
cout << root->data << endl;
mid_recurrece(root->rchild);
}
//非递归法,方法有很多,这里使用较广泛的,可用于先、中序
//使用栈来进行回溯,遍历完左子树后,回溯逐一遍历右子树
void mid_unrecurrece(bitreenode *root)
{
stack<bitreenode*> s;
while (root != NULL || !s.empty())
{
if (root != NULL)//完成两步工作,压入栈,遍历到最左
{
//先序在这里
//cout << root->data << endl;
s.push(root);
root = root->lchild;
}
else
//到最左后,完成四步工作,
//读出NULL的前一个,将节点out出来(相对就是左子树),结点已经遍历完pop掉,轮到该根结点右子树
{
root = s.top();
cout << root->data << endl;
s.pop();
root = root->rchild;
}
}
}
};
.
3、后序递归与非递归
#include <iostream>
#include <stack>
using namespace std;
struct bitreenode {
int data;
bitreenode *lchild, *rchild;
};
/*
//也可以这样
typedef struct bitreenode {
int data;
bitreenode *lchild, *rchild;
}*bitree;
//下面改为bitree root即可
*/
class bitree_postTraverse
{
public:
//递归法
void post_recurrece(bitreenode *root)
{
if (root == NULL)
return;
//就换下顺序
post_recurrece(root->lchild);
post_recurrece(root->rchild);
cout << root->data << endl;
}
/*!!!后序与先、后不一样*/
//后序遍历的非递归算法较复杂,使用一个栈可以实现,但是过程很繁琐,
//这里可以巧妙的用两个栈来实现后序遍历的非递归算法
//注意到后序遍历可以看作是下面遍历的逆过程:即先遍历某个结点,然后遍历其右孩子,然后遍历其左孩子。
//可参考https://blog.csdn.net/sgbfblog/article/details/7773103
/*
1、Push根结点到第一个栈s中。
2、从第一个栈s中Pop出一个结点,并将其Push到第二个栈output中。
3、然后Push结点的左孩子和右孩子到第一个栈s中。
4、重复过程2和3直到栈s为空。
5、完成后,所有结点已经Push到栈output中,且按照后序遍历的顺序存放,直接全部Pop出来即是二叉树后序遍历结果。
*/
void post_unrecurrece(bitreenode *root)
{
if (root == NULL)
return;
stack<bitreenode*> s1, s2;
s1.push(root);
while (!s1.empty())
{
bitreenode *tmp= s1.top();
s2.push(tmp);
s1.pop();
if (tmp->lchild)
s1.push(tmp->lchild);
if (tmp->rchild)
s1.push(tmp->rchild);
}
while (!s2.empty())
{
cout << s2.top() << endl;;
s2.pop();
}
}
};
.
4、层序遍历
//两个队列来完成层次遍历,q1存前一行,q2存后一行
#include <iostream>
#include <queue>
using namespace std;
struct bitreenode {
int data;
bitreenode *lchild, *rchild;
};
class bitree_levelTraverse
{
public:
void levelTravelse(bitreenode *root)
{
if (root == NULL) return;
queue<bitreenode*> q1,q2;
q1.push(root);
while (!q1.empty())
{
bitreenode *tmp = q1.front();
q1.pop();
//在打印q1的同时,将其左右节点存入q2
if (tmp)
{
cout << tmp->data << endl;
q2.push(tmp->lchild);
q2.push(tmp->rchild);
}
if (!q1.empty())
{//swap
while (!q2.empty())
{
q1.push(q2.front());
q2.pop();
}
}
}
}
void levelTravelse_q1(bitreenode *root)
{
if (root == NULL) return;
queue<bitreenode*> q1;
q1.push(root);
while(!q1.empty())
{
bitreenode* tmp=q1.front();
q1.pop();
cout<<tmp->data<<endl;
if(tmp->lchild) q1.push(tmp->lchild);
if(tmp->rchild) q1.push(tmp->rchild);
}
}
};