数据结构(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;
		}
	}
}

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	printf("先序遍历打印二叉树:\n");
	preOrderPrint(T);
	printf("\n");
	
	printf("先序遍历打印二叉树(非递归算法):\n");
	preOrderPrint2(T);
	printf("\n");

    return 0;
}

 

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;
		}
	}
}

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	printf("中序遍历打印二叉树:\n");
	inOrderPrint(T);
	printf("\n");
	
	printf("中序遍历打印二叉树(非递归算法):\n");
	inOrderPrint2(T);
	printf("\n");

    return 0;
}

 

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;				
			}
		}		
	}
}

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	printf("后序遍历打印二叉树:\n");
	postOrderPrint(T);
	printf("\n");

	printf("后序遍历打印二叉树(非递归算法):\n");
	postOrderPrint2(T);
	printf("\n");

    return 0;
}

 

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

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	printf("按层次遍历打印二叉树(非递归算法):\n");
	hierarchicalTraversePrint(T);

    return 0;
}

 

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

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	int depth = getBiTreeDepth(T);
	printf("该二叉树树的深度为%d\n", depth);

    return 0;
}

 

2.2求二叉树的结点数

//求二叉树的节点数
int getBiTreeSize(BiTree T){
	if(!T)
		return 0;
	int leftTreeSize = getBiTreeSize(T->lchild);
	int rightTreeSize = getBiTreeSize(T->rchild);
	return leftTreeSize + rightTreeSize + 1;
}

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	int size = getBiTreeSize(T);
	printf("该二叉树树的结点数为%d\n", size);

    return 0;
}

 

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);
		//}
	}
}

演示:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	int leafNodesNum2 = 0;
	leafNodesNum2 = getBiTreeLeafNodesNum2(T);
	printf("该二叉树树的叶子点数为%d\n", leafNodesNum2);

    return 0;
}

或者:

int main(){
	BiTree T;
	printf("请按先序次序输入二叉树各节点的值,以空格表示空树,以#号结束:\n");
	createBiTreeByPreOrder(T);

	int leafNodesNum = 0;
	getBiTreeLeafNodesNum(T, leafNodesNum);
	printf("该二叉树树的叶子点数为%d\n", leafNodesNum);

    return 0;
}

 

本文中的代码可从这里下载:https://github.com/qingyujean/data-structure

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值