前序遍历:根节点—>左子树—>右子树
中序遍历:左子树—>根节点—>右子树
后序遍历:左子树—>右子树—>根节点
【构造一棵树】
我们用数组存树的节点
int a[15] = { 1, 2, ‘#’, 3, ‘#’, ‘#’, 4, 5, ‘#’, 6, ‘#’, 7, ‘#’, ‘#’, 8 }
“#”代表非法值,就是为空的节点
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
template < class T>
struct BinaryTreeNode
{
BinaryTreeNode* _left;
BinaryTreeNode* _right;
T _data;
BinaryTreeNode(const T&x)
:_left(NULL)
, _right(NULL)
,_data(x)
{}
};
template <class T>
class BinaryTree
{
typedef BinaryTreeNode<T> Node;
public:
BinaryTree()
:_root(NULL)
{}
BinaryTree(const T* a, size_t n, const T& invalid)
{
size_t index = 0;
_root = _CreatTree(a, n, invalid, index);//构造树的函数
}
//构造树
Node* _CreatTree(const T*a, size_t n, const T& invalid, size_t& index)
{
Node* root = NULL;
if (index < n&&a[index] != invalid)
{
root = new Node(a[index]);
root->_left = _CreatTree(a,n,invalid,++index);
root->_right = _CreatTree(a, n, invalid, ++index);
}
return root;
}
~BinaryTree()
{
_Destroy(_root);
cout << endl;
}
protected:
Node* _root;
前序——–递归
前序就是遇到根节点就访问,之后访问左子树,再右子树,所以很容易可以写出如下非递归代码
void PrevOrder()
{
_PrevOrder(_root);
cout << endl;
}
void _PrevOrder(Node* root)
{
if (root == NULL)
{
return;
}
cout << root->_data << " ";
_PrevOrder(root->_left);
_PrevOrder(root->_right);
}
前序——–非递归
这里我们要借用栈,因为栈的特性是后进先出。
先遍历树的最左节点,并把每个节点入栈。在入栈的同时就可以访问根节点。
当cur为NULL时,这颗树的最左边的根节点节点都全部入栈,
然后取出栈顶节点,访问右子树,
当栈为空,这个树就遍历结束
void PrevOrder_NonR()//非递归前序遍历
{
stack<Node*> s;
Node* cur = _root;
while (cur||!s.empty())
{
while (cur)
{
s.push(cur);
cout << cur->_data << " ";
cur = cur->_left;
}
Node* top = s.top();
s.pop();
cur = top->_right;
}
cout << endl;
}
中序—-递归
void InOrder()//中序
{
_InOrder(_root);
cout << endl;
}
void _InOrder(Node* root)
{
if (root == NULL)
{
return;
}
_InOrder(root->_left);
cout << root->_data << " ";
_InOrder(root->_right);
}
中序—-非递归
依然借助栈,把树的最左边的根节点cur全部入栈,
然后依次取栈顶节点访问,
再访问右子树,右子树不为空的时候继续入栈。
void InOrder_NonR()//非递归中序遍历
{
Node* cur = _root;
stack<Node*> s;
while (cur||!s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();//此时访问的是最左节点
cout << top->_data << " ";
s.pop();
cur = top->_right;
}
cout << endl;
}
后序—-递归
void PosOrder()//后序
{
_PosOrder(_root);
cout << endl;
}
void _PosOrder(Node* root)
{
if (root == NULL)
{
return;
}
_PosOrder(root->_left);
_PosOrder(root->_right);
cout << root->_data << " ";
}
后序—-非递归
还是借助栈。但是此时有一个问题:后序是先访问左子树,在右子树,最后根节点,那么问题来了:–访问右子树,是需要通过先访问根节点,当cur=top->_right,cur不是NULL,把cur入栈,依次访问右子树,最后依次退到根节点访问,但是此时cur=top->_right,cur不等于NULL,再次入栈;可是我们已经把右树访问过了,所以我们会在这里陷入死循环。
那么如何解决呢?
我们可以设置一个标记prev,prev表示上一个访问的节点。当我们取出栈顶节点时,如果他的右子树已经访问过了,就不再把右子树入栈,而直接访问当前节点。
void PostOrder_NonR()//后序非递归
{
stack<Node*> s;
Node* cur = _root;
Node* prev = NULL;
while (cur||!s.empty())
{
while (cur)
{
s.push(cur);
cur = cur->_left;
}
Node* top = s.top();
if (top->_right == NULL || top->_right == prev)
{
cout << top->_data << " ";
prev = top;
s.pop();
}
else
{
cur = top->_right;
}
}
cout << endl;
}