#include <stdio.h>
#include <malloc.h>#include <stdlib.h>
#define STACK_INT_SIZE 100 //存儲空間初始分配量
#define STACKINCREMENT 10 //存儲空間分配增量
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -2
typedef char TElemType;
typedef int Status;
typedef char SElemType;
//二叉樹的二叉鏈表存儲表示
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild, *rchild; //左右孩子指針
}BiTNode, *BiTree;
//用於存儲二叉樹結點的棧
typedef struct
{
BiTree *base;
BiTree *top;
int stacksize; //當前已分配的存儲空間
}SqStack;
//定義鏈式隊列結點
typedef struct QNode
{
BiTree Queuedata;
struct QNode * next;
}QNode,* QueuePtr;
//定義鏈式隊列
typedef struct
{
QueuePtr front; //
QueuePtr rear;
}LinkQueue;
//創建存儲二叉樹結點的空棧
Status InitStack(SqStack &S)
{
S.base = (BiTree *) malloc(sizeof(BiTree));
if(!S.base) exit(OVERFLOW);
S.top = S.base;
S.stacksize = STACK_INT_SIZE;
return OK;
}
//存儲二叉樹結點的棧的取棧頂元素
Status GetTop(SqStack &S, BiTree &e)
{
//若棧不空,則用e返回S的棧頂元素
if(S.top == S.base) return ERROR;
e = *(S.top-1);
return OK;
}
//存儲二叉樹結點的棧的入棧操作
Status Push(SqStack &S, BiTree e)
{
//插入元素e爲棧頂元素
if(S.top - S.base >= S.stacksize)
{ //若棧滿,則追加存儲空間
S.base = (BiTree *) realloc(S.base, (S.stacksize + STACKINCREMENT)*sizeof(BiTree));
if(!S.base) return ERROR;
S.top = S.base + S.stacksize;
S.stacksize += STACKINCREMENT;
}
*S.top = e;
S.top++;
return OK;
}
//用於存儲二叉樹結點的棧出棧操作
Status Pop(SqStack &S,BiTree &e)
{
//刪除S的棧頂元素,並用e返回
if(S.base == S.top) return ERROR;
S.top--;
e = *S.top;
return OK;
}
//判斷存儲二叉樹結點的棧是否爲空
Status StackEmpty(SqStack S)
{
// 若棧S爲空棧,則返回TRUE,否則返回FALSE
if(S.top == S.base) return TRUE;
else return FALSE;
}
//先序順序創建一顆二叉樹
Status PreOrderCreateBiTree(BiTree &T)
{
//按先序次序輸入二叉樹中結點的值
//構造二叉鏈表表示的二叉樹T
char ch;
scanf("%c",&ch);
if(ch == '0') T = NULL;
else
{
//if(!(T = (BiTree ) malloc(sizeof(BiTree)))) exit(OVERFLOW);//作用和下一語句的作用相同,注意兩者的區別
if(!(T = (BiTNode* ) malloc(sizeof(BiTNode)))) exit(OVERFLOW);
T->data = ch; //生成根結點
PreOrderCreateBiTree(T->lchild); //構造左子樹
PreOrderCreateBiTree(T->rchild); //構造右子樹
}
return OK;
} //CreateBiTree
//遞歸先序遍歷二叉樹
void PreOrder ( BiTree bt )
{
if ( bt )
{
printf("%c",bt->data); //先訪問根節點
PreOrder ( bt->lchild );//遍歷左子樹
PreOrder ( bt->rchild ); //遍歷右子樹
}
}
//遞歸中序遍歷二叉樹
void Inorder ( BiTree bt )
{
if ( bt )
{
Inorder ( bt->lchild ); //遍歷左子樹
printf("%c",bt->data);//訪問根節點
Inorder ( bt->rchild );//遍歷右子樹
}
}
//遞歸後序遍歷二叉樹
void LastOrder ( BiTree bt )
{
if ( bt )
{
LastOrder( bt->lchild );//遍歷左子樹
LastOrder( bt->rchild );//遍歷右子樹
printf("%c",bt->data);//訪問根節點
}
}
//非遞歸先序遍歷二叉樹 方法一:
Status PreOrderTraverse(BiTree T)
{
SqStack s;
BiTree P=T;
InitStack(s);
while ( P!=NULL || !StackEmpty(s))
{
if (P!=NULL)
{
printf("%c",P->data);
Push(s,P); //訪問完之後將根節點入棧
P=P->lchild;
}
else
{
Pop(s,P);
P=P->rchild;
}
}
return OK;
}
//非遞歸先序遍歷二叉樹 方法二:
Status PreOrderTraverse2(BiTree T)
{
SqStack s;
BiTree P=T;
InitStack(s);
Push(s,P); //先將根節點入棧
while ( !StackEmpty(s))
{
Pop(s,P);
if (P!=NULL)
{
printf("%c",P->data);//訪問根節點
Push(s,P->rchild);// 先進棧,後訪問,所以這裏先讓右子樹進棧
Push(s,P->lchild);
}
}
return OK;
}
//非遞歸中序遍歷二叉樹
Status InOrderTraverse(BiTree T)
{
//中序遍歷二叉樹T的非遞歸算法,對每個數據元素調用函數Visit,也就是printf()函數
SqStack S;
InitStack(S);
BiTree p;
p = T;
/**/
while(p || !StackEmpty(S))
{
if(p)
{
Push(S,p);
p = p->lchild; //根指針進棧,遍歷左子樹
}
else
{ //根指針退棧,訪問根結點,遍歷右子樹
Pop(S,p);
printf("%c",p->data);
p = p->rchild;
}
}//while
/*和上面的while開始的操作完全等同,可以視爲方法二:
Push(S,p);
while (!StackEmpty(S))
{
while (GetTop(S,p) && p)
{
Push(S,p->lchild);
}
Pop(S,p);
if (!StackEmpty(S))
{
Pop(S,p);
printf("%c",p->data);
Push(S,p->rchild);
}
}
*/
return OK;
} //InOrderTraverse
/**/
//非遞歸後序遍歷二叉樹 :
Status LastOrderTraverse(BiTree T)
{
//後序遍歷時,分別從左子樹和右子樹共兩次返回根結點,
//只有從右子樹返回時才訪問根結點,所以增加一個棧標記到達結點的次序。
SqStack s,tag;//定義兩個棧,一個是存儲二叉樹結點的棧,一個是存儲標誌位的棧
//stack2 tag ;
BiTree f,m,n,P=T; //m,n是標誌位。f是中間變量,用於檢測標誌位是m還是n的
m=(BiTNode*)malloc(sizeof(BiTNode)); //注意:此處必須先創建結點,然後再賦值
m->data=1;
m->lchild=NULL;
m->rchild=NULL;
n=(BiTNode*)malloc(sizeof(BiTNode));//注意:此處必須先創建結點,然後再賦值
n->data=2;
n->lchild=NULL;
n->rchild=NULL;
InitStack(s);//此棧用來存放結點
InitStack(tag);//此棧用來存放標誌位,從左子樹返回根節點時爲1,從右子樹返回根節點時爲2
while (P ||!StackEmpty(s))
{
if (P)
{
Push(s,P);
Push(tag,m);//第一次入棧操作
P=P->lchild;
}
else
{
Pop(s,P);
Pop(tag,f);
if (f==m)
{
// 從左子樹返回,二次入棧,然後p轉右子樹
Push(s,P);
Push( tag, n);//第二次入棧
P=P->rchild;
}
else
{
// 從右子樹返回(二次出棧),訪問根結點,p轉上層
printf("%c",P->data);
P=NULL; // 必須的,使下一步繼續退棧
}
}
}
return OK;
}
//初始化一個帶頭結點的隊列
Status InitQueue(LinkQueue &Q)
{
Q.front=(QNode*)malloc(sizeof(QNode));
if (!Q.front)
exit(OVERFLOW);
Q.rear=Q.front;
Q.front->next=NULL;
return OK;
}
//入隊列
Status EnQueue(LinkQueue &Q,BiTree e)
{
QueuePtr s=(QueuePtr)malloc(sizeof(QNode));
if (!s)
exit(OVERFLOW);
s->Queuedata=e;
s->next=NULL;
Q.rear->next=s;
Q.rear=s;
return OK;
}
//出隊
int DelQueue(LinkQueue &Q, BiTree &e)
{
char data1;
QueuePtr s;
s=Q.front->next;//注意:該隊列爲帶頭結點,所以剛開始出隊列時,應該去front的next
e=s->Queuedata;//獲取對頭記錄的數據域,類型爲BiTree
data1=e->data;//獲取BiTree類型的數據域,類型爲char
Q.front->next=s->next;
if(Q.rear==s)//隊列中只有一個元素
Q.rear=Q.front;
free(s);
return TRUE;
}
//隊列的判斷空操作
Status QueueEmpty(LinkQueue Q)
{
//隊列帶頭結點,所以需要判斷Q.front->next
if (Q.front->next==NULL)
return OK;
else return ERROR;
}
//按層次遍歷
Status HierarchyBiTree(BiTree bt)
{
LinkQueue Q; // 保存當前節點的左右孩子的隊列
InitQueue(Q); // 初始化隊列
BiTree p = bt; // 臨時保存樹根Root到指針p中
if (bt == NULL) return ERROR; //樹爲空則返回
EnQueue(Q,p); //先將根節點入隊列
while (!QueueEmpty(Q)) // 若隊列不空,則層序遍歷
{ DelQueue(Q, p); // 出隊列
printf("%C",p->data);// 訪問當前節點
if (p->lchild)
EnQueue(Q, p->lchild); // 若存在左孩子,左孩子進隊列
if (p->rchild)
EnQueue(Q, p->rchild); // 若存在右孩子,右孩子進隊列
}
//DelQueue(Q,p); // 釋放隊列空間
return OK;
}
//求葉子節點個數
int sum=0;//此處一定要定義爲全局變量,因爲遞歸調用退出函數的時候局部變量會銷燬
int SumLefts(BiTree bt)
{
if (bt!=NULL)
{
if (bt->lchild==NULL && bt->rchild==NULL)
{
//printf("%4c",bt->data);
sum++;
}
sum=SumLefts(bt->lchild);
sum=SumLefts(bt->rchild);
}
return(sum);
}
void main()
{ //注意創建二叉樹時,用先序順序創建
printf("請輸入先序建立二叉樹所需要的數據(例如ABD0000):");
BiTree t;
PreOrderCreateBiTree(t); //利用先序順序創建二叉樹
printf("先序遍歷輸出爲:");
//PreOrder(t);//先序遞歸遍歷
PreOrderTraverse(t);//先序非遞歸遍歷
printf("\n");
printf("中序遍歷輸出爲:");
//InOrderTraverse(t);//中序非遞歸遍歷
Inorder(t);//中序遞歸遍歷
printf("\n");
printf("後序遍歷輸出爲:");
//LastOrder(t);//後序遞歸遍歷
LastOrderTraverse(t);//後序非遞歸遍歷
printf("\n");
printf("按層次遍歷輸出爲:");
HierarchyBiTree(t);//層次遍歷,從上到下,從左到右
printf("\n");
printf("該二叉樹中葉子節點個數爲:");
int leaves=SumLefts(t);
printf("%d",leaves);
printf("\n");
}