/*======================================
树的所有操作
初始化二叉树, 先序,中序,后序建立二叉树
先序,中序,后序递归, 非递归 遍历二叉树
层次遍历二叉树等
2013-08-12 By Mei
=======================================*/
#include <iostream>
#include <cstdlib>
#include <queue>
#include <stack>
#define N 20;
using namespace std;
typedef struct Binode // 树的数据结构
{
int data;
struct Binode *lchild, *rchild;
}Binode, *Bitree;
typedef struct s_stack
{
Bitree *top;
Bitree *base;
int size;
}s_stack;
typedef struct qnode
{
Bitree *rear;
Bitree *front;
}qnode;
int a[] = {1, 2, 3, 0, 0, 4, 5, 0, 6, 0, 0, 7, 0, 0, 0};
// Bitree Create_Tree(Bitree &T)//必须用二级指针
// {
// int x;
// cin>>x;
// if(x==0)// 输入二叉树的节点,左右节点不存在必须以0 代替,否则递归不能结束
// T = NULL;
// else
// {
// T = new Binode;
// T->data = x;
// cout<<T->data<<endl;
// Create_Tree(T->lchild);
// Create_Tree(T->rchild);
// }
// return T;
// }
Bitree Create_Tree()
{
Bitree p;
static int num = 0;
if (num <= 20)
{
if(a[num]==0)
{
p = NULL;
num++;
}
else
{
p=new Binode;
p->data = a[num];
p->lchild = p->rchild = NULL;
cout <<p->data<<" ";
num++;
p->lchild = Create_Tree();
p->rchild = Create_Tree();// 尼玛 指针被这里覆盖了..
}
}
else //递归出来的时候需注意..
p = NULL;
return p;
}
//先序递归遍历
void Rec_PreorderTraverse(Bitree root)
{
if(root != NULL)
{
cout<<root->data<<" ";
Rec_PreorderTraverse(root->lchild);
Rec_PreorderTraverse(root->rchild);
}
}
// 先序非递归遍历
/*
思想:利用栈实现,首先根节点进站,然后右节点进栈,接着左节点进栈
然后弹出栈顶节点,判断栈顶节点的右节点是否存在,存在则压入栈,继续判断
其左节点是否存在,存在则压入栈中,然后继续弹出栈顶元素,反复循环,知道栈为
空为止
*/
void PreorderTraverse(Bitree root)
{
s_stack st;
Bitree p = root;
st.base = new Bitree[20];
st.size = N;
st.top = st.base;
*st.top++ = p;
while(st.top!=st.base)
{
p=*--st.top;
cout<<p->data<<" ";
if(p->rchild!=NULL)
{
*st.top++ = p->rchild;
}
if(p->lchild!=NULL)
{
*st.top++ = p->lchild;
}
}
}
//中序递归遍历
void Rec_InorderTraverse(Bitree root)
{
if(root != NULL)
{
Rec_InorderTraverse(root->lchild);
cout<<root->data<<" ";
Rec_InorderTraverse(root->rchild);
}
}
//中序非递归遍历
/*
思想:首先压入根节点,如果其左节点存在,继续压入其左节点,知道左节点为空
然后弹出栈顶元素,判断其右节点是否存在,若存在压入栈中,继续判断其左节点是否存在
若存在,继续压入其左节点,知道其左节点不存在为止,然后反复循环,知道栈为空为止
*/
void InorderTraverse(Bitree root)
{
s_stack st;
Bitree p = root;
Bitree x, y;
st.base = new Bitree[20];
st.size = N;
st.top = st.base;
while(p!=NULL)
{
*st.top++ = p;
p = p->lchild;
}
while(st.top!=st.base)
{
x = *--st.top;
cout<<x->data<<" ";
if(x->rchild!=NULL)
{
*st.top++ = x->rchild;
y = x->rchild;
while(y->lchild!=NULL)
{
*st.top++ = y->lchild;
y = y->lchild;
}
}
}
}
void Rec_PostorderTraverse(Bitree root) //后序递归遍历
{
if(root != NULL)
{
Rec_PostorderTraverse(root->lchild);
Rec_PostorderTraverse(root->rchild);
cout<<root->data<<" ";
}
}
//后序非递归遍历
/*
先压入根节点到栈中,如果其左节点非空,一直压入左节点,知道左节点为空为止,此时取出栈顶元素
只是去取,并非弹栈,然后标记这个节点,表示这个节点的右子节点已经被访问过,下次遇到这个节点
直接弹出即可
(1)判断这个节点是否有右子节点 或者右子节点是否被访问过,如果是,则弹出这个节点
(2)如果这个节点的右子节点没有被访问过,则右子节点压入栈中,重复刚开始的其是否存在左子节点的判断
*/
void PostorderTraverse(Bitree root)
{
s_stack st;
Bitree p = root;
st.base = new Bitree[20];
st.top = st.base;
Bitree x,y;
int flag[10];//标记是否访问过这个节点
while(p!=NULL)
{
*st.top++ = p;
p = p->lchild;
flag[st.top-st.base-1] = 0;
}
while(st.top!=st.base)
{
p = *(st.top-1);
if(flag[st.top-st.base-1]==0)
{
flag[st.top-st.base-1] = 1;
if(p->rchild!=NULL)
{
x = p->rchild;
while(x!=NULL)
{
*st.top++ = x;
x = x->lchild;
flag[st.top-st.base-1] = 0;
}
}
}
else
{
x = *--st.top;
cout<<x->data<<" ";
}
}
}
//层次遍历
void TraversalOfLevel(Bitree root)
{
qnode st;
Bitree p;
st.front = new Bitree[20];
st.rear = st.front;
*st.front++ = root;
while(st.front!=st.rear)
{
p = *st.rear++;
cout<<p->data<<" ";
if(p->lchild!=NULL)
*st.front++ = p->lchild;
if(p->rchild!=NULL)
*st.front++ = p->rchild;
}
}
//先序,中序,后序 非递归遍历的第二种思路
//先序非递归遍历的第二种方法
/*
对任一节点来说
(1)访问节点p,节点入栈
(2)判断其左孩子是否为空,如果为空,进行出栈操作,并将栈顶元素的右孩子设置为p,
循环到1,若不为空,则将节点p的左孩子设置为当前的节点P
(3)若P为NULL 且栈为空,则结束遍历
*/
void PreorderTraverse1(Bitree root)
{
stack<Bitree> s;
Bitree p = root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
cout<<p->data<<" ";
s.push(p);
p = p->lchild;
}
if(!s.empty())
{
p = s.top();
s.pop();
p = p->rchild;
}
}
}
//中序非递归遍历
/*
对任一节点来说:
(1)若左节点不空,则将p入栈,并将p的左孩子置为P,重复这个操作,直到p的左孩子为空为止
(2)若左孩子为空,则取栈顶元素并出栈,访问栈顶元素,然后将P的右孩子置为P为止
(3)当P为NULL,且栈为空 则遍历完成
*/
void InorderTraverse1(Bitree root)
{
stack<Bitree> s;
Bitree p = root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
s.push(p);
p = p->lchild;
}
if(!s.empty())
{
p = s.top();
cout<<p->data<<" ";
s.pop();
p = p->rchild;
}
}
}
// 后序非递归遍历第二种实现方式
/*
对任一节点P,将其入栈,然后沿左子树一起向下搜索,知道左子树为空为止
此时获取栈顶元素,但是此时还不能出栈访问,因为其右孩子还未被访问,此时对
其标记一下,表示右节点已经访问过,然后让右节点入栈,重复前面的操作,知道遇到
已经标记过的节点,此时表明此节点的右节点已经都被访问完成
*/
void PostorderTraverse1(Bitree root)
{
stack<Bitree> s;
int flag[20];
int x;
Bitree p = root;
while(p!=NULL||!s.empty())
{
while(p!=NULL)
{
s.push(p);
flag[s.size()] = 0;
p = p->lchild;
}
if(!s.empty())
{
x = flag[s.size()];
p = s.top();
if(x == 0)
{
flag[s.size()] = 1;
p = p->rchild;
}
else
{
cout<<p->data<<" ";
s.pop();
p = NULL;
}
}
}
}
// 后序遍历的第三种形式
/*
要保证先访问左右节点,然后再访问根节点,可以先把根节点入栈,然后其右节点,左节点分别入栈
如果根节点没有左右节点,或者左右节点已经被访问过,根节点就可以出战,这样可以保证每次取栈顶
元素的时候,左节点在右节点前面被访问,根节点在左节点,右节点前面被访问
*/
void PostorderTraverse2(Bitree root)
{
stack <Bitree> s;
Bitree cur, pre=NULL;
s.push(root);
while(!s.empty())
{
cur = s.top();
if((cur->rchild==NULL && cur->lchild==NULL)||(pre!=NULL &&(pre==cur->lchild||pre==cur->rchild)))
{
cout<<cur->data<<" ";
s.pop();
pre = cur;
}
else
{
if(cur->rchild!=NULL)
s.push(cur->rchild);
if(cur->lchild!=NULL)
s.push(cur->lchild);
}
}
}
int main()
{
Bitree T, root;
root = Create_Tree();
cout<<endl;
cout<<"先序遍历结果:"<<endl;
Rec_PreorderTraverse(root);
cout<<endl;
PreorderTraverse(root);
cout<<endl;
PreorderTraverse1(root);
cout<<endl;
cout <<"中序遍历结果:"<<endl;
Rec_InorderTraverse(root);
cout<<endl;
InorderTraverse1(root);
cout<<endl;
InorderTraverse(root);
cout<<endl;
cout << "后序遍历结果:"<<endl;
Rec_PostorderTraverse(root);
cout<<endl;
PostorderTraverse(root);
cout<<endl;
PostorderTraverse1(root);
cout <<endl;
PostorderTraverse2(root);
cout<<endl;
cout<<"层次遍历结果:"<<endl;
TraversalOfLevel(root);
cout<<endl;
return 0;
}