數據結構(13)二叉樹的動態鏈表存儲和遍歷的實現

參考書籍:數據結構(C語言版)嚴蔚敏吳偉民編著清華大學出版社

本文中的代碼可從這裏下載:https://github.com/qingyujean/data-structure

1.動態二叉鏈表存儲即遍歷的實現

1.1.動態二叉鏈表的定義

 

#include<stdio.h>
#include<stdlib.h>
#define NULL 0
typedef char TElemType;
//動態二叉鏈表
typedef struct BiTNode{
	TElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

 

測試用例:

測試按先序序列輸入:abc..de.g..f...#,點號代表空樹,#爲輸入結束符

另外下面的算法有使用到棧的,棧的相關實現如下:

 

#define MAXSIZE 100
typedef BiTNode* SElemType;
typedef struct SqStack{
	SElemType data[MAXSIZE];
	int top;//指向棧頂元素
}SqStack;

//初始化空棧
void initStack(SqStack &s){
	s.top = 0;
}

//判棧空
bool isEmpty(SqStack s){
	if(s.top == 0){
		//printf("是空棧\n");//
		return true;
	}else{
		return false;
	}
}

//判棧滿
bool isFull(SqStack s){
	if(s.top == MAXSIZE){
		return true;
	}
	else{
		return false;
	}
}

//取棧頂元素
void getTopElem(SqStack s, SElemType &e){
	if(!isEmpty(s))
		e = s.data[s.top-1];
	else
		printf("此棧爲空棧,取棧頂元素失敗\n");
}

//入棧
void push(SqStack &s, SElemType e){
	if(!isFull(s)){
		s.data[s.top] = e;
		s.top++;
	}else
		printf("此棧已滿,入棧操作失敗\n");
}

//出棧
void pop(SqStack &s, SElemType &e){
	if(!isEmpty(s)){
		e = s.data[s.top-1];
		s.top--;
	}
	else
		printf("此棧爲空棧,出棧操作失敗\n");
}

更詳細的棧實現請參見我的另一篇博文:數據結構(5)--棧的定義以及相關操作的實現http://blog.csdn.net/u010366748/article/details/50639195

 

1.2按先序序列輸入創建二叉樹的遞歸算法

 

//利用先序序列建立一顆二叉樹,先序序列讀入:'a', 'b', 'c', '.', '.', 'd', 'e', '.', 'g', '.', '.', 'f', '.', '.', '.' 
//,'.'代表空樹
//測試用例:abc..de.g..f...#
void createBiTreeByPreOrder(BiTree &T){
	//按先序次序輸入二叉樹中節點的值(一個字符),點號字符表示空樹,構造二叉鏈表表示的二叉樹
	//注意:若輸入的字符數(不含#號)爲n個,則相應的空樹即點號就應該有n+1個
	char ch;
	scanf("%c", &ch);
	//printf("test:%c\n", ch);
	if(ch != '#'){
		if(ch == '.'){
			T = NULL;
		}else{
			T = (BiTNode *)malloc(sizeof(BiTNode));
			T->data = ch;
			createBiTreeByPreOrder(T->lchild);
			createBiTreeByPreOrder(T->rchild);
		}
	}
}

 

1.3先序遍歷二叉樹的遞歸算法

 

 

//先序遍歷打印二叉樹的遞歸算法(根、左、右)
void preOrderPrint(BiTree T){
	if(T){
		printf("%c ", T->data);
		preOrderPrint(T->lchild);
		preOrderPrint(T->rchild);
	}
}

 

1.4先序遍歷二叉樹的非遞歸算法

 

 

//先序遍歷打印二叉樹的非遞歸算法(根、左、右)
void preOrderPrint2(BiTree T){
	SqStack s;
	initStack(s);
	BiTNode *p = T;	
	while(p || !isEmpty(s)){		
		if(p){
			printf("%c ", p->data);
			push(s, p);
			p = p->lchild;
		}else{
			//printStack(s);
			pop(s, p);//棧頂指針(當前層的根節點指針)彈出
			p = p->rchild;
		}
	}
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	printf("先序遍歷打印二叉樹:\n");
	preOrderPrint(T);
	printf("\n");
	
	printf("先序遍歷打印二叉樹(非遞歸算法):\n");
	preOrderPrint2(T);
	printf("\n");
}

 

 

 

 

 

1.5中序遍歷二叉樹的遞歸算法

 

//中序遍歷打印二叉樹的遞歸算法(左、根、右)
void inOrderPrint(BiTree T){
	if(T){
		inOrderPrint(T->lchild);
		printf("%c ", T->data);		
		inOrderPrint(T->rchild);
	}
}

 

 

 

1.6中序遍歷二叉樹的非遞歸算法

 

 

//中序遍歷打印二叉樹的非遞歸算法(左、根、右)
void inOrderPrint2(BiTree T){
	SqStack s;
	initStack(s);
	BiTNode *p = T;	
	while(p || !isEmpty(s)){
		if(p){
			push(s, p);
			p = p->lchild;
		}else{
			pop(s, p);//棧頂指針(當前層的根節點指針)彈出
			printf("%c ", p->data);			
			p = p->rchild;
		}
	}
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	printf("中序遍歷打印二叉樹:\n");
	inOrderPrint(T);
	printf("\n");
	
	printf("中序遍歷打印二叉樹(非遞歸算法):\n");
	inOrderPrint2(T);
	printf("\n");
}

 

 

 

 

 

1.7後序遍歷二叉樹的遞歸算法

 

 

//後序遍歷打印二叉樹的遞歸算法(左、右、根)
void postOrderPrint(BiTree T){
	if(T){
		postOrderPrint(T->lchild);
		postOrderPrint(T->rchild);
		printf("%c ", T->data);
	}
}

 

 

 

1.8後序遍歷二叉樹的非遞歸算法

 

 

//後序遍歷打印二叉樹的非遞歸算法(左、右、根)
void postOrderPrint2(BiTree T){
	SqStack s;
	initStack(s);
	BiTNode *p = T;
	while(p || !isEmpty(s)){
		if(p){
			push(s, p);
			p = p->lchild;
		}else{ 
			BiTNode *top;
			getTopElem(s, top);//取得棧頂元素
			if(top->data > 0){//棧頂元素的右子樹還沒有被訪問過
				p = top->rchild;
				top->data = -top->data;//賦右子樹已遍歷標誌
				
			}else{//棧頂元素的右子樹已經訪問過了
				printf("%c ", -top->data);
				pop(s, top);
				//p = NULL;				
			}
		}		
	}
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	printf("後序遍歷打印二叉樹:\n");
	postOrderPrint(T);
	printf("\n");

	printf("後序遍歷打印二叉樹(非遞歸算法):\n");
	postOrderPrint2(T);
	printf("\n");
}

 

 

 

 

 

1.9按層次遍歷二叉樹的非遞歸算法

 

 

typedef BiTNode* QElemType;
typedef struct{
	QElemType data[20];
	int f;//指向隊頭元素
	int r;//指向對尾元素的下一個位置
}SqQueue;
//初始化一個空隊列
void initQueue(SqQueue &Q){
	Q.f = Q.r = 0;
}

//按層次遍歷(從上到下,從左到右),
void hierarchicalTraversePrint(BiTree T){
	//QElemType queue[20];//維護一個順序隊列,用來按層次存放每個實節點,實際上是一個廣度優先搜索
	//int f = 0, r = 0;//隊頭隊尾
	SqQueue Q;//維護一個順序隊列,用來按層次存放每個實節點,實際上是一個廣度優先搜索
	initQueue(Q);
	//注意,不能寫成int f, r = 0;否則f沒有被賦值
	if(T){
		//queue[0] = T;//根節點入隊
		Q.data[Q.r] = T;//根節點入隊
		Q.r++;
	}
	while(Q.f != Q.r){
		//先將隊頭元素的左孩子依次入隊
		if(Q.data[Q.f]->lchild){
			Q.data[Q.r] = Q.data[Q.f]->lchild;
			Q.r++;
		}
		//將隊頭元素的右孩子依次入隊
		if(Q.data[Q.f]->rchild){
			Q.data[Q.r] = Q.data[Q.f]->rchild;
			Q.r++;
		}
		//然後打印(訪問)隊頭元素,並將隊頭元素出隊		
		printf("%c ", Q.data[Q.f]->data);
		Q.f++;//隊頭元素出隊
	}
	printf("\n");
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	printf("按層次遍歷打印二叉樹(非遞歸算法):\n");
	hierarchicalTraversePrint(T);
}

 

 

 

 

 

2.遍歷二叉樹的應用

2.1求二叉樹的深度

 

 

//求二叉樹的深度
int getBiTreeDepth(BiTree T){
	if(!T){
		return 0;
	}
	int leftTreeDepth = getBiTreeDepth(T->lchild);
	int rightTreeDepth = getBiTreeDepth(T->rchild);
	return leftTreeDepth > rightTreeDepth ? (leftTreeDepth+1) : (rightTreeDepth+1);
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	int depth = getBiTreeDepth(T);
	printf("該二叉樹樹的深度爲%d\n", depth);
}

 

 

 

 

 

2.2求二叉樹的結點數

 

 

//求二叉樹的節點數
int getBiTreeSize(BiTree T){
	if(!T)
		return 0;
	int leftTreeSize = getBiTreeSize(T->lchild);
	int rightTreeSize = getBiTreeSize(T->rchild);
	return leftTreeSize + rightTreeSize + 1;
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	int size = getBiTreeSize(T);
	printf("該二叉樹樹的結點數爲%d\n", size);
}

 

 

 

 

 

2.3求二叉樹的葉子節點數

 

 

//先序遍歷求葉子節點數
int getBiTreeLeafNodesNum2(BiTree T){
	if(T){
		if(!T->lchild && !T->rchild)
			return 1;
		else{
			int leftTreeLeafNodesNum = getBiTreeLeafNodesNum2(T->lchild);
			int rightTreeLeafNodesNum = getBiTreeLeafNodesNum2(T->rchild);
			return leftTreeLeafNodesNum + rightTreeLeafNodesNum;
		}
	}else{
		return 0;
	}
}


或者:

 

 

//先序遍歷求葉子節點數
void getBiTreeLeafNodesNum(BiTree T, int &count){
	if(T){
		if(!T->lchild && !T->rchild)
			count++;
		//else{
			getBiTreeLeafNodesNum(T->lchild, count);
			getBiTreeLeafNodesNum(T->rchild, count);
		//}
	}
}

演示:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	int leafNodesNum2 = 0;
	leafNodesNum2 = getBiTreeLeafNodesNum2(T);
	printf("該二叉樹樹的葉子點數爲%d\n", leafNodesNum2);
}

或者:

 

 

void main(){
	BiTree T;
	printf("請按先序次序輸入二叉樹各節點的值,以空格表示空樹,以#號結束:\n");
	createBiTreeByPreOrder(T);

	int leafNodesNum = 0;
	getBiTreeLeafNodesNum(T, leafNodesNum);
	printf("該二叉樹樹的葉子點數爲%d\n", leafNodesNum);
}

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章