#include <iostream>
#include "stdio.h"
#include "stdlib.h"
#include "cstdlib"//syste()函数需要该头文件;
using namespace std;
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef char TElemType;
//00 二叉链表存储结构的定义3个:数据元素---原子类型不用结构体,结点BiTNode---3个域的结构体,二叉链表*BiTree---原子类型指针表示一棵二叉树,也可以表示某一结点指针
typedef struct BiTNode{
TElemType data;
struct BiTNode *lchild, *rchild;
}BiTNode,*BiTree;
//typedef BiTree SElemType;
//定义一个栈,用于完成二叉树遍历的非递归算法
typedef struct StackNode{
BiTNode *data; //存放的是二叉树(指针型)结点,也就是将一个树结点类型的指针作为数据放入栈结点的data中
struct StackNode *next;//指向下一个栈结点(data,next)
}StackNode, *LinkStack;
//定义一个队列,用于完成二叉树层次遍历的非递归算法
typedef struct QNode { // 结点QNode定义
BiTNode *data;
struct QNode *next;
}QNode, *QueuePtr;
typedef struct { // 链队LinkQueue定义
QueuePtr front; // 队头指针
QueuePtr rear; // 队尾指针
} LinkQueue;
//01 _按先序遍历创建,没有头结点、长度,也无需提前开辟空间放数据(开辟一个空间放一个数据),所以不用初始化了T.data=0;t.lchile=null,t.lchild=null;
Status CreateBiTree(BiTree &T)
{
char ch;
cin>>ch; //上机输入_P126最下面 ABC##DE#G##F###,注意画图就知道怎么回事了C##表示C为根,左右孩子为空。ABD##E##CF##G##什么图?
if(ch=='#')
{
T=NULL;
}
else
{
T=new BiTNode;
if (!T)
{
exit(OVERFLOW);
}
T->data=ch;//先序
CreateBiTree(T->lchild);//左子树递归创建
CreateBiTree(T->rchild);//右子树递归创建 根左右
}
return OK;
}
//02 _先序遍历
Status PreOrderTraverse(BiTree T)
{
if(T)
{
cout<<T->data<<" ";
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
return OK;
}
//03 中序遍历
Status InOrderTraverse(BiTree T)
{
if(T)
{
InOrderTraverse(T->lchild);
cout<<T->data<<" ";
InOrderTraverse(T->rchild);
}
return OK;
}
//04 后序遍历
Status PostOrderTraverse(BiTree T)
{
if(T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout<<T->data<<" ";
}
return OK;
}
//05 复制二叉树,先序方式
Status CopyBiTree(BiTree T,BiTree &NewT)//加&
{
if(T==NULL)
{
NewT=NULL;
}
else
{
NewT=new BiTNode;
NewT->data=T->data;
CopyBiTree(T->lchild,NewT->lchild);
CopyBiTree(T->rchild,NewT->rchild);
}
return OK;
}
//06 计算二叉树的深度
int GetDeptbBT(BiTree T)//深度不能用status了
{
int m,n;
if(T==NULL)
return 0;
else
{
m=GetDeptbBT(T->lchild);//左子树也是一棵二叉树,所以可以递归调用函数自身
n=GetDeptbBT(T->rchild); //同上
if(m>n)
return (m+1);
else
return (n+1);
}
}
//07 计算结点个数
int NodeCount(BiTree T)
{
if(T==NULL)
return 0;
else
return NodeCount(T->lchild)+NodeCount(T->rchild)+1;//根节点也要加上,故+1;
}
//08 计算叶子结点个数
int LeafNodeCount(BiTree T)
{
if(T==NULL)
return 0;
else
if(T->lchild==NULL&&T->rchild==NULL)//碰见叶子结点终止递归
return 1;
else
return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);//注意树若只有一个根节点,叶子结点数是1
}
//09 中序非递归遍历
Status InitStack(LinkStack &S)
{
S = NULL; //由于链栈没有头结点,所以不用开辟一个结点空间,也不用定义S->next = NULL;甚至不需要初始化子函数,只需主函数中声明时StackNode *S=NULL即可;
return OK;
}
int StackEmpty(LinkStack S)
{
if (S == NULL)
return 1; //链栈为空,用0还是用1表示,看你后面程序中怎么用,用1方便就置1;
else
return 0;
}
Status Push(LinkStack &S, BiTree tNode)//每入栈一个结点,总要修改指针S的值,使其指向新的栈顶元素,故加&;
{
StackNode *sNode;//等价于LinkStack p;为什么用StackNode *p?而不用LinkStack p呢???
sNode = (LinkStack)malloc(sizeof(StackNode));
sNode->data = tNode;
sNode->next = S; //新入栈的元素的指针指向原本的栈顶元素
S = sNode;//重新让S指向刚入栈的(栈顶)元素
return OK;
}
Status Pop(LinkStack &S, BiTree &tNode)
{
StackNode *sNode;//栈s顶结点
if (S == NULL)//链栈为空就不能出栈
{
cout<<"栈空,无法读取!";
return ERROR;
}
tNode = S->data;//S就是栈顶结点
sNode = S;
S = S->next; //出栈时,指针要指向栈顶的下一个元素了
free(sNode); //释放栈顶指针
return OK;
}
Status InOrderTraverseByIteration(BiTree T)//二叉树遍历的中序非递归算法,先序后序呢???
{
BiTNode *p; //等价于BiTree p; 为什么不用BiTree p呢???主要是BiTree用来表示二叉树,给人的感觉 p 是一个二叉树,但实际p只是一个节点指针
p = T; //T表示一棵链树,也表示链树的根结点,把根赋值给p
StackNode *S;
InitStack(S);//初始化栈,置空
while (p!= NULL || !StackEmpty(S))
{
if (p != NULL)
{
Push(S,p); //把根节点压栈
p = p->lchild; //先去遍历左子树
}
else
{
Pop(S, p); //一开始p是二叉树最左结点,相当于其是一个左孩子是空的根节点,再遍历右子树,如果右孩子也空,说明其是一个叶子结点
cout<<p->data<<" ";
p = p->rchild; //遍历右子树
}
}
return OK;
}
//10 二叉树先序非递归遍历
Status PreOrderTraverseByIteration(BiTree T)
{
BiTNode *p; //等价于BiTree p;为什么用BiTNode *p?而不用BiTree p呢???
p = T; //T表示一棵链树,也表示链树的根结点,把根赋值给p
StackNode *S;
InitStack(S);//空栈置空
while (p!= NULL || !StackEmpty(S))
{
if (p != NULL)
{
cout<<p->data<<" ";//先访问根
Push(S,p->rchild);//和下一行代码顺序不能换,右孩子入栈,先不访问 //若此处Push(S,p);则else要在pop后面+p=p->rchild;
p = p->lchild;//沿着左孩子一直进行,访问左孩子,后面出栈访问右孩子,根 左 右
}
else
{
Pop(S, p);
}
}
return OK;
}
//11 二叉树后序非递归遍历
Status PostOrderTraverseByIteration(BiTree T)//二叉树后序遍历
{
BiTNode *p,*pre = NULL; //p为当前;pre为上次访问结点
StackNode *S;
InitStack(S);//空栈置空
if(T==NULL)
return OK;
Push(S,T);//根先入栈 最后访问 左 右 根
while (!StackEmpty(S))
{
GetTop(S,p);//先读取,不是出栈Pop,满足下面的判断在出栈,意思是判断结点是叶子结点,或 不是叶子结点但被访问过 那就输出p->data并将p出栈,用pre记录p;
if ((p->lchild==NULL&&p->rchild==NULL)||(pre!=NULL&&(pre==p->lchild||pre==p->rchild)))//如果当前结点没有孩子结点或者孩子节点都已被访问过
{
cout<<p->data<<" ";
Pop(S,p);//把当前访问过的元素出栈
pre=p;//pre记录这个刚被访问出栈的元素
}
else
{
if(p->rchild!=NULL)
Push(S,p->rchild);//根循坏外已入栈,现在先压右,在压左,出栈是 左 右 根,便是 后序
if(p->lchild!=NULL)
Push(S,p->lchild);
}
}
return OK;
}
//12 二叉树层序遍历,用到队列了。
Status InitLQueue(LinkQueue &Q)
{
Q.rear=Q.front = new QNode;
Q.front->next = NULL;//头结点需要修改next为NULL;
return OK;
}
Status EnQueue(LinkQueue &Q, BiTree tNode)//入队,仅需将原来的e改成BiTree tNode即可,我们要入栈一个二叉链结点,其实定义中可以定义一个指针* BiTreeNode,字面意思更合理,是Node了,不是Bitree了
{
QueuePtr p;
if(Q.front)
{
p = new QNode;
p->data = tNode;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}
else
{
cout << "链队不存在!" <<endl;
return ERROR;
}
}
Status DeQueue(LinkQueue &Q, BiTree &tNode)//出队
{
if (Q.front == Q.rear)
{
printf("空链队\n");
return ERROR;
}
QueuePtr p;
p = Q.front->next; //p指向队头元素
tNode = p->data;
Q.front->next = p->next; //头结点的next指向p-next(p的后继结点);
if (Q.rear == p)
{
Q.rear = Q.front; //如果只有一个结点,尾指针也要修改;
}
delete p;
return OK;
}
Status GetLQHead(LinkQueue Q, BiTree &tNode)//Q没变不加,tNode需要返回给主函数故加&。//其实本程序没用到这个子函数不用写上
{
if(Q.front != Q.rear)
{
tNode = Q.front->next->data;
return OK;
}
else
{
printf("当前链队为空,无头元素!\n");
return ERROR;
}
}
Status LQisEmpty(LinkQueue Q)
{
if (Q.front == Q.rear)
return 1;
else
return 0;
}
Status BreadthFirstOrder(BiTree T)//层序遍历
{
if(T==NULL)
return OK;
BiTNode *p=T;
LinkQueue Q;
InitLQueue(Q);
EnQueue(Q, p);//根结点先入队
while(!LQisEmpty(Q))
{
DeQueue(Q, p);
cout<<p->data<<" ";//出队一个,后面要把左右孩子入队,如果空了不入队,一直出队直至空队
if(p->lchild!=NULL)
EnQueue(Q, p->lchild);
if(p->rchild!=NULL)
EnQueue(Q, p->rchild);
}
return OK;
}
void main()
{
BiTree BT;
char ch;
do{
system("cls");
printf("创建树,输入0为空树:\n");
CreateBiTree(BT);
cout<<"先序遍历BT: ";
PreOrderTraverse(BT);
cout<<"\n先序迭代BT: ";
PreOrderTraverseByIteration(BT);
cout<<"\n中序遍历BT: ";
InOrderTraverse(BT);
cout<<"\n中序迭代BT: ";
InOrderTraverseByIteration(BT);
cout<<"\n后序遍历BT: ";
PostOrderTraverse(BT);
cout<<"\n后序迭代BT: ";
PostOrderTraverseByIteration(BT);
BiTree NT;
CopyBiTree(BT,NT);
cout<<"\n先序复制BT: ";
PreOrderTraverse(NT);
cout<<"\n层序遍历BT: ";
BreadthFirstOrder(BT);
cout<<"\n二叉深度: "<<GetDeptbBT(BT);
cout<<"\n结点个数: "<<NodeCount(BT);
cout<<"\n叶子个数: "<<LeafNodeCount(BT);
cout<<"\n是否继续测试(输入y或Y继续,任意其他键结束):";
cin>>ch;
}while(ch == 'y' || ch == 'Y');
system("pause");
}