1. 程式人生 > >二叉樹先序後序遞迴建立,前中後序層次非遞迴遍歷,以及統計葉子結點個數以及樹的深度

二叉樹先序後序遞迴建立,前中後序層次非遞迴遍歷,以及統計葉子結點個數以及樹的深度

下面的程式碼實現了二叉樹的先序或者後序遞迴建立,然後實現了二叉樹的非遞迴的先序中序後序遍歷,還有層次遍歷,以及統計樹的葉子結點個數和樹的深度。其中非遞迴的先中後序遍歷用到了鏈棧,層次遍歷用到了佇列。

程式設計平臺為Visual Studio 2012,語言為C,但不是純C,比如用到了C++的引用機制以及變數的隨時定義(在純C中,變數必須在函式一開始的地方全部宣告)。

// 二叉樹非遞迴遍歷.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdlib.h>
#include <string.h>
char string[100];
int len;
int flag=1;

//二叉樹結點結構定義
typedef struct  BiTNode 
{
	char data;
	struct BiTNode *lchild;
	struct BiTNode *rchild;
} BiTNode, *BiTree;

//鏈棧結點定義
typedef struct StNode
{
	BiTree t;
	struct StNode *next;
}StNode, *StackPtr;

//鏈棧定義
typedef struct LinkStack
{
	StackPtr top;
	int count;
} LinkStack, *StLink;

//初始化鏈棧
void InitStack(StLink &S)
{
	S=(LinkStack*) malloc(sizeof(LinkStack));
	if(!S)  exit(EXIT_FAILURE);
	S->top=NULL;
	S->count=0;
}
//為鏈棧插入新的棧頂元素
void Push(StLink &S,BiTree e)
{
	StackPtr s=(StackPtr) malloc(sizeof(StNode));
	s->next=S->top;
	s->t=e;
	S->top=s;
	S->count++;
}
//出棧
void Pop(StLink &S,BiTree &e)
{
	StackPtr p;
	if(S->count==0) return;
	e=S->top->t;
	p=S->top;
	S->top=S->top->next;
	free(p);
	S->count--;
}
//得到鏈棧的棧頂元素
int Getpop(StLink &S,BiTree &e)
{
	StackPtr p;
	if(S->count==0) return 0;
	e=S->top->t;
	return 1;
}

//佇列連結串列結構,佇列結點結構域棧一樣,故不重複定義
typedef struct 
{
	StackPtr front, rear; //對頭,隊尾指標
	int count;
}LinkQueue, *QuLink;

//初始化佇列
void InitQueue(QuLink &Q)
{
	Q=(QuLink)malloc(sizeof(LinkQueue));
	if(!Q) exit(EXIT_FAILURE);
	Q->front=NULL;
	Q->rear=NULL;
	Q->count=0;
}
//入隊,該佇列為左頭右尾,所以入隊是在最右邊插入
void EnQueue(QuLink &Q,BiTree e)
{
	StackPtr q=(StackPtr)malloc(sizeof(StNode));
	if(!q) exit(EXIT_FAILURE);
	q->t=e;
	q->next=NULL;
	if(Q->count==0) //如果此時是空隊
	{
		Q->rear=Q->front=q;
	}
	else
	{
		Q->rear->next=q;
		Q->rear=q;
	}
	Q->count++;
}

//出隊,從最左邊出隊
void DeQueue(QuLink &Q,BiTree &e)
{
	StackPtr q;
	if(Q->count==0)
		return;
	if(Q->count==1)
	{
		q=Q->front;
		e=q->t;
		free(q);
		Q->front=Q->rear=NULL;
		Q->count=0;
		return;
	}
	q=Q->front;
	e=q->t;
	Q->front=q->next;
	free(q);
	Q->count--;
}

//先序遞迴定義二叉樹,空樹用#代替
void PreCreateBiTree(BiTree &T)
{
	char ch;
	scanf_s("%c",&ch,1);
	if(ch=='#')
		T=NULL;
	else
	{
		T=(BiTree) malloc(sizeof(BiTNode));
		if(!T) exit(EXIT_FAILURE);
		T->data=ch;
		PreCreateBiTree(T->lchild);
		PreCreateBiTree(T->rchild);
	}
}
//後序序列遞迴定義二叉樹
void PostCreateBiTree(BiTree &T)
{
	if(flag==1)
	{
		scanf_s("%s",string,100);
		len=strlen(string);
		flag=0;
	}
	if(string[--len]=='#')
		T=NULL;
	else
	{
		T=(BiTree)malloc(sizeof(BiTNode));
		if(!T) exit(EXIT_FAILURE);
		T->data=string[len];
		PostCreateBiTree(T->rchild);
		PostCreateBiTree(T->lchild);
	}
}

//非遞迴先序遍歷二叉樹1
void PreOrderTraverse_nonRecursion(BiTree T)
{
	StLink S;
	BiTree p;
	InitStack(S);
	Push(S,T); //根指標進棧
	while(S->count!=0)
	{
		while(Getpop(S,p)&&p)  { printf("%c",p->data); Push(S,p->lchild);} //向左走到盡頭
		Pop(S,p); //空指標退棧
		if(S->count!=0)
		{
			Pop(S,p); //取出子樹根結點,因為以後訪問右子樹的時候已經不需要記錄根結點
			Push(S,p->rchild); //右孩子入棧
		}
	}
}

//非遞迴中序遍歷二叉樹1
void InOrderTraverse_nonRecursion(BiTree T)
{
	StLink S;
	BiTree p;
	InitStack(S);
	Push(S,T); //根指標進棧
	while(S->count!=0)
	{
		while(Getpop(S,p)&&p) Push(S,p->lchild); //向左走到盡頭
		Pop(S,p); //空指標退棧
		if(S->count!=0)
		{
			Pop(S,p); //取出子樹根結點,因為以後訪問右子樹的時候已經不需要記錄根結點
			printf("%c",p->data); //訪問結點
			Push(S,p->rchild); //右孩子入棧
		}
	}
}

//非遞迴後序遍歷二叉樹1
void PostOrderTraverse_nonRecursion(BiTree T)
{
	StLink S;
	BiTree p;
	int tag[100]={0};//標誌位,為0表示右子樹還沒遍歷,為1表示右子樹已經遍歷
	InitStack(S);
	Push(S,T); //根指標進棧
	while(S->count!=0)
	{
		while(Getpop(S,p)&&p) { Push(S,p->lchild); tag[S->count]=0;} //向左走到盡頭,同時設定標誌位
		Pop(S,p); //空指標退棧
		if(S->count!=0)
		{
			while(tag[S->count]==1) //迴圈把已經遍歷過右子樹的根結點都遍歷了
			{
				Pop(S,p);
				printf("%c",p->data);
			}
			if(S->count==0) break; //如果已經遍歷完,就退出迴圈
			//遍歷右子樹,先改變標誌位為,然後將棧頂結點右孩子壓棧,同時設定其標誌位
			Getpop(S,p);
			tag[S->count]=1;
			p=p->rchild;
			Push(S,p);
			tag[S->count]=0;
		}
	}
}

//非遞迴先序遍歷二叉樹2
void PreOrderTraverse_nonRecursion2(BiTree T)
{
	StLink S;
	BiTree p;
	InitStack(S);
	p=T;
	while(p||S->count!=0)
	{
		if(p) {Push(S,p); printf("%c",p->data); p=p->lchild;}
		else
		{
			Pop(S,p);
			p=p->rchild;
		}
	}
}

//非遞迴中序遍歷二叉樹2
void InOrderTraverse_nonRecursion2(BiTree T)
{
	StLink S;
	BiTree p;
	InitStack(S);
	p=T;
	while(p||S->count!=0)
	{
		if(p) {Push(S,p); p=p->lchild;}
		else
		{
			Pop(S,p);
			printf("%c",p->data);
			p=p->rchild;
		}
	}
}

//非遞迴層次遍歷二叉樹,使用佇列先進先出
void FloorOrderTraverse_nonRecursion(BiTree T)
{
	QuLink Q;
	BiTree p;
	InitQueue(Q);
	EnQueue(Q,T);//根結點入隊
	while(Q->count!=0)
	{
		DeQueue(Q,p);
		printf("%c",p->data);
		if(p->lchild) EnQueue(Q,p->lchild);
		if(p->rchild) EnQueue(Q,p->rchild);
	}
}

//統計葉子結點個數
void CountLeaf(BiTree T,int &num)
{
	if(T==NULL) return;
	if(T->lchild==NULL&&T->rchild==NULL) num++; //這裡也可以直接把葉子結點輸出
	else
	{
		CountLeaf(T->lchild,num);
		CountLeaf(T->rchild,num);
	}
}

//計算二叉樹樹深度
int CalBiTreeDeep(BiTree T)
{
	int deep=0;
	if(T==NULL) return 0;
	int dl=CalBiTreeDeep(T->lchild);
	int dr=CalBiTreeDeep(T->rchild);
	return 1+(dl>dr?dl:dr);
}
int _tmain(int argc, _TCHAR* argv[])
{
	BiTree T;
	int num=0;
	int deep;
	//printf("%s\n","請後序輸入二叉樹序列");
	//PostCreateBiTree(T);
	printf("%s\n","請先序序輸入二叉樹序列");
	PreCreateBiTree(T);
	printf("%s\n","非遞迴先序1輸出為:");
	PreOrderTraverse_nonRecursion(T);
	puts("");//換行
	printf("%s\n","非遞迴先序2輸出為:");
	PreOrderTraverse_nonRecursion2(T);
	puts("");
	printf("%s\n","非遞迴中序1輸出為:");
	InOrderTraverse_nonRecursion(T);
	puts("");
	printf("%s\n","非遞迴中序2輸出為:");
	InOrderTraverse_nonRecursion2(T);
	puts("");
	printf("%s\n","非遞迴後序輸出為:");
	PostOrderTraverse_nonRecursion(T);
	puts("");
	printf("%s\n","非遞迴按層次遍歷二叉樹輸出為:");
	FloorOrderTraverse_nonRecursion(T);
	puts("");
	CountLeaf(T,num);
	printf("%s%d\n","該二叉樹的葉子結點總數為:",num);
	deep=CalBiTreeDeep(T);
	printf("%s%d\n","該二叉樹的數深度為:",deep);
	return 0;
}

輸入下圖表示的二叉樹:


執行結果為: