二叉树的遍历

建立如下图所示的二叉树,以下所有的遍历操作均基于该二叉树
在这里插入图片描述

先来用递归的方式遍历二叉树
因二叉树的存储与建立均可用递归方式,且二叉树与递归息息相关,故用递归方式遍历二叉树简单明了,二叉树的遍历方式如下:

  • 先序 根左右
  • 中序 左根有
  • 后序 左右根
  • 层次遍历 只用非递归方式实现

先序遍历(递归):

void preOrder(LPTREE root) {
	if (root) {
		//printCurrentNode()访问根 再依次递归调用本身访问左孩子和右孩子
		printCurrentNode(root);	//该函数在后文有定义 用于打印节点信息
		preOrder(root->LChild);
		preOrder(root->RChild);
	}
}

中序遍历(递归):

//中序遍历按根左右顺序 先访问左孩子 当无左孩子输出结点信息  再访问右孩子
void midOrder(LPTREE root) {
	if (root) {
		midOrder(root->LChild);
		printCurrentNode(root);
		midOrder(root->RChild);
	}
}

后序遍历(递归):

void lastOrder(LPTREE root) {
	if (root) {
		lastOrder(root->LChild);
		lastOrder(root->RChild);
		printCurrentNode(root);
	}
}

以上三种递归遍历较为简单,真正的难点在于非递归遍历,需要借助栈来实现,栈又会涉及到结构体,非递归遍历最考验基本功

先来定义节点信息,如下(上为图示,下为代码):
在这里插入图片描述

typedef struct treeNode {
	char data;
	struct treeNode* LChild;
	struct treeNode* RChild;
} TREE, * LPTREE;

先序非递归遍历的实现如下:

void preOrderByStack(LPTREE root) {
	if (root == NULL) return;
	LPTREE stack[10];	//规定栈的规模
	int stackTop = -1;	//定义栈底指针
	LPTREE pMove = root;	//pMove为工作指针
	while (stackTop!=-1||pMove) {	//当栈有元素或工作指针不为空可进入循环
		while (pMove) {	//找到最下层左孩子
			printf("%c\t", pMove->data);
			stack[++stackTop] = pMove;
			pMove = pMove->LChild;
		}
		if (stackTop!=-1) {		//该节点子树为空  出栈
			pMove = stack[stackTop--];
			pMove = pMove->RChild;	//指针指向当前节点的右孩子
		}
	}
}

中序非递归遍历实现如下:

void midOrderByStack(LPTREE root) {
	if (root == NULL) return;
	struct treeNode* stack[10];
	int stackTop = -1;
	LPTREE pMove = root;
	while (stackTop!=-1||pMove) {
		while (pMove) {
			stack[++stackTop] = pMove;
			pMove = pMove->LChild;
		}
		if (stackTop != -1) {
			pMove = stack[stackTop--];
			printf("%c\t", pMove->data);
			pMove = pMove->RChild;
		}
	}
}

后序非递归遍历实现如下:

void lastOrderByStack(LPTREE root) {
	if (root == NULL)	return;
	LPTREE stack[10];
	int stackTop = -1;
	LPTREE pMove = root;
	LPTREE pLastVisit = NULL;//访问标记
	while (pMove) {	//先找到最下端的左孩子	一旦为空即退出循环 
		stack[++stackTop] = pMove;
		pMove = pMove->LChild;
	}
	while (stackTop!=-1) {
		pMove = stack[stackTop--];
		if (pMove->RChild == NULL || pMove->RChild == pLastVisit) {
			printf("%c\t", pMove->data);	//右孩子存在或访问过 打印当前节点 
			pLastVisit = pMove;				//标记当前节点的访问状态  为已访问 
		} else {	//若右孩子存在且未访问过  指针指向右孩子 
			stack[++stackTop] = pMove;
			pMove = pMove->RChild;
			while (pMove) {	//假若右孩子有左子树  则右孩子的左孩子入栈 
				stack[++stackTop] = pMove;
				pMove = pMove->LChild;
			}
		}
	}
}

层次遍历代码如下:

void levelOrder(LPTREE root){
	if(!root) return;
	int front=-1,rear=-1; 	//front指向队首 rear指队尾
	LPTREE pMove=root;
	LPTREE Q[10];	//创建辅助队列 层次遍历需要借助队列实现 
	Q[++rear]=root;
	while(front!=rear){
		pMove=Q[++front];	//出队
		printf("%c\t",pMove->data);
		if(pMove->LChild){
			Q[++rear]=pMove->LChild;
		} 
		if(pMove->RChild) {
			Q[++rear]=pMove->RChild;
		}
	}
} 

求结点的度算法如下:
算法思想:采用任意一种遍历 以下选用先序遍历 设置一个计数变量cnt(conut的缩写) 记录当前节点的子结点数,若判断当前节点的左右孩子是否存在,若存在则累加

void countNum(LPTREE root){
	if(!root) return;
	int cnt=0;
	if(root->LChild) ++cnt;
	if(root->RChild) ++cnt;
	printf("节点%c的度为%d\n",root->data,cnt);
	if(root->LChild)
		countNum(root->LChild);
	if(root->RChild)
		countNum(root->RChild); 
} 

完整代码如下:

#include<stdio.h>
#include<cstring>
#include<cstdlib>
typedef struct treeNode {
	char data;
	struct treeNode* LChild;
	struct treeNode* RChild;
} TREE, * LPTREE;

LPTREE createNode(char data) {	//插入字符数据 
	LPTREE newNode = (LPTREE)malloc(sizeof(TREE));	//创建节点 分配节点空间 
	newNode->data = data;
	newNode->LChild = NULL;
	newNode->RChild = NULL;
	return newNode;
}

void insertNode(LPTREE parentNode, LPTREE LChild, LPTREE RChild) {
	parentNode->LChild = LChild;
	parentNode->RChild = RChild;
}
void printCurrentNode(LPTREE currentData) {
	printf("%c\t", currentData->data);
}
//先序递归
void preOrder(LPTREE root) {
	if (root) {
		printCurrentNode(root);
		preOrder(root->LChild);
		preOrder(root->RChild);
	}
}
//中序递归
void midOrder(LPTREE root) {
	if (root) {
		midOrder(root->LChild);
		printCurrentNode(root);
		midOrder(root->RChild);
	}
}
//后序递归
void lastOrder(LPTREE root) {
	if (root) {
		lastOrder(root->LChild);
		lastOrder(root->RChild);
		printCurrentNode(root);
	}
}
//先序朴素
void preOrderByStack(LPTREE root) {
	if (root == NULL) return;
	LPTREE stack[10];
	int stackTop = -1;
	LPTREE pMove = root;
	while (stackTop!=-1||pMove) {
		while (pMove) {
			printf("%c\t", pMove->data);
			stack[++stackTop] = pMove;
			pMove = pMove->LChild;
		}
		if (stackTop!=-1) {
			pMove = stack[stackTop--];
			pMove = pMove->RChild;	//指针指向当前节点的右孩子
		}
	}
}
//中序朴素
void midOrderByStack(LPTREE root) {
	if (root == NULL) return;
	struct treeNode* stack[10];
	int stackTop = -1;
	LPTREE pMove = root;
	while (stackTop!=-1||pMove) {
		while (pMove) {
			stack[++stackTop] = pMove;
			pMove = pMove->LChild;
		}
		if (stackTop != -1) {
			pMove = stack[stackTop--];
			printf("%c\t", pMove->data);
			pMove = pMove->RChild;
		}
	}
}
//后序朴素
void lastOrderByStack(LPTREE root) {
	if (root == NULL)	return;
	LPTREE stack[10];
	int stackTop = -1;
	LPTREE pMove = root;
	LPTREE pLastVisit = NULL;//访问标记
	while (pMove) {	//先找到最下端的左孩子	一旦为空即退出循环 
		stack[++stackTop] = pMove;
		pMove = pMove->LChild;
	}
	while (stackTop!=-1) {
		pMove = stack[stackTop--];
		if (pMove->RChild == NULL || pMove->RChild == pLastVisit) {
			printf("%c\t", pMove->data);	//右孩子存在或访问过 打印当前节点 
			pLastVisit = pMove;				//标记当前节点的访问状态  为已访问 
		} else {	//若右孩子存在且未访问过  指针指向右孩子 
			stack[++stackTop] = pMove;
			pMove = pMove->RChild;
			while (pMove) {	//假若右孩子有左子树  则右孩子的左孩子入栈 
				stack[++stackTop] = pMove;
				pMove = pMove->LChild;
			}
		}
	}
}

//层次遍历
void levelOrder(LPTREE root){
	if(!root) return;
	int front=-1,rear=-1; 
	LPTREE pMove=root;
	LPTREE Q[10];	//创建辅助队列 层次遍历需要借助队列实现 
	Q[++rear]=root;
	while(front!=rear){
		pMove=Q[++front];	//出队
		printf("%c\t",pMove->data);
		if(pMove->LChild){
			Q[++rear]=pMove->LChild;
		} 
		if(pMove->RChild) {
			Q[++rear]=pMove->RChild;
		}
	}
} 

//计算结点的度  思想:遍历二叉树 判断结点是否有子结点 有则累加 每次输出
void countNum(LPTREE root){
	if(!root) return;
	int cnt=0;
	if(root->LChild) ++cnt;
	if(root->RChild) ++cnt;
	printf("节点%c的度为%d\n",root->data,cnt);
	if(root->LChild)
		countNum(root->LChild);
	if(root->RChild)
		countNum(root->RChild); 
} 

//主函数
int main() {
	LPTREE A = createNode('A');
	LPTREE B = createNode('B');
	LPTREE C = createNode('C');
	LPTREE D = createNode('D');
	LPTREE E = createNode('E');
	LPTREE F = createNode('F');
	LPTREE G = createNode('G');
	insertNode(A, B, C);
	insertNode(B, D, NULL);
	insertNode(D, NULL, G);
	insertNode(C, E, F);
	printf("先序遍历(递归):\n");
	preOrder(A);	//从A开始先序遍历
	printf("\n先序遍历(非递归):\n");
	preOrderByStack(A);
	printf("\n中序遍历(递归):\n");
	midOrder(A);
	printf("\n中序遍历(非递归):\n");
	midOrderByStack(A);
	printf("\n后序遍历(递归):\n");
	lastOrder(A);
	printf("\n后序遍历(非递归):\n");
	lastOrderByStack(A);
	printf("\n层次遍历:\n");
	levelOrder(A);
	printf("\n");
	countNum(A);
}

最终效果图如下:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值