#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");
}
