二叉树的层次、递归与非递归遍历

本文详细介绍了二叉树的概念及其在操作系统、编译系统和数据库系统中的应用。接着,阐述了二叉树与普通树的区别,并列举了二叉树的5种基本形态。重点讲解了二叉树的三种遍历方式——先序遍历、中序遍历和后序遍历,分别给出了递归和非递归的实现方法。最后,展示了层次遍历的实现过程。

  树结构是一类重要的非线性数据结构,树在计算机领域中也得到广泛应用,尤以二叉树最为常用。如在操作系统中,用树来表示文件目录的组织结构,在编译系统中,用树来表示源程序的语法结构,在数据库系统中,树结构也是信息的重要组织形式之一。在这里,我们会详细讲解二叉树。

二叉树( Binary Tree)是n(n≥0)个结点所构成的集合,它或为空树(n=O)或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点;

(2)除根结点以外的其余结点分为两个互不相交的子集T和T,分别称为T的左子树和右子树,且T和T本身又都是二叉树。

二叉树与树一样具有递归性质,二叉树与树的区别主要有以下两点:

(1)二叉树每个结点至多只有两棵子树(即二叉树中不存在度大于2的结点);

(2)二叉树的子树有左右之分,其次序不能任意颠倒。

二叉树的递归定义表明二叉树或为空,或是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。由于这两棵子树也是二叉树,则由二叉树的定义,它们也可以是空树。由此,二叉树可以有5种基本形态,如图所示。

 

遍历二叉树是二叉树最基本的操作,也是二叉树其他各种操作的基础,遍历的实质是对二叉树进行线性化的过程,即遍历的结果是将非线性结构的树中结点排成一个线性序列。由于二叉树的每个结点都可能有两棵子树,因而需要寻找一种规律,以便使二树上的结点能排列在一个线性队列上,从而便于遍历。

二叉树是由3个基本单元组成:根结点、左子树和右子树。因此,若能依次遍历这三部分,便是遍历了整个二叉树。假如从L、D、R分别表示遍历左子树、访问根结点和遍历右子树,则可有DLR、LDR、LRD、DRL、RDL、RLD这6种遍历二叉树的方案。若限定先左后右,则只有前3种情况,分别称之为先(根)序遍历、中(根)序遍历和后(根)序遍历。下面介绍二叉树的遍历:

1.二叉树的递归遍历

(1)先序遍历(根节点、左子树、右子树)

PreOrderTraverse(BiTree T){
	if(T){
		visit(T->data);
		PreOrderTraverse(T->lchild);
		PreOrderTraverse(T->rchild);
	}
}

(2)中序遍历(左子树、根节点、右子树)

InOrderTraverse(BiTree T){
	if(T){
		
		InOrderTraverse(T->lchild);
		visit(T->data);
		InOrderTraverse(T->rchild);
	}
}

(3)后序遍历(左子树、右子树、根节点)

PostOrderTraverse(BiTree T){
	if(T){
		PostOrderTraverse(T->lchild);
		PostOrderTraverse(T->rchild);
		visit(T->data);	
	}	
	} 

2.二叉树的非递归

(1)先序遍历(根节点、左子树、右子树)

void PreOrder2(BiTree T){
	BiTree stack[MAXSIZE], BiTNode;
	int top = -1;
 
	if (T == NULL){
		printf("树空\n");
		return;
	}
	else{
		top++;
		// 仿照一个栈
		stack[top] = T; // 将根节点入栈
		while (top > -1){
			//出栈
			BiTNode = stack[top--];
			printf(" %c ", BiTNode->data);
 
			// 先把右子树放进去,栈是先进去后出,所以下面的左子树先出
			if (BiTNode->rchild != NULL){
				stack[++top] = BiTNode->rchild;  // 入栈
			}
			if (BiTNode->lchild != NULL){
				stack[++top] = BiTNode->lchild;
			}
 
		}
 
	}
}

(2)中序遍历(左子树、根节点、右子树)

void InOrder2(BiTree T){
	BiTree stack[MAXSIZE], BiTNode;
	int top = 0;
	// 判断树是否为空
	if (T == NULL){
		printf("树空\n");
		return;
	}
	BiTNode = T;
 
	while (BiTNode != NULL || top > 0){
 
		// 将所有的左子树节点入栈
		while (BiTNode != NULL){
			stack[++top] = BiTNode;
			BiTNode = BiTNode->lchild;
		}
		//  如果右节点为空的话,执行下列语句
		BiTNode = stack[top--];
		printf(" %c ", BiTNode->data);
 
		// 扫描右节点
		BiTNode = BiTNode->rchild;
	}
 
}

(3)后序遍历(左子树、右子树、根节点)

void PostOrder2(BiTree T){
 
	BiTNode *p = T;
	BiTNode *stack[MAXSIZE];
	int num = 0;
	BiTNode *have_visited = NULL;
 
	while (NULL != p || num>0)
	{
		while (NULL != p)
		{
			stack[num++] = p;
			p = p->lchild;
		}
		p = stack[num - 1];
		if (NULL == p->rchild || have_visited == p->rchild)
		{
			printf(" %c ", p->data);
			num--;
			have_visited = p;
			p = NULL;
		}
		else
		{
			p = p->rchild;
		}
	}
	
}

3.层次遍历

void Level_traversal(BiTree T){
 
	if (T == NULL){
		printf("树空\n");
		return;
	}
 
	BiTree stack[MAXSIZE], BiTNode;
	BiTNode = T;
	int front = 0;  // 使用 front, rear模拟队列
	int rear = 0;
 
	stack[rear++] = BiTNode;
 
	while (front != rear){
 
		BiTNode = stack[front++]; // 模拟队列,先获取front当前元素,然后在指向 front ++ 位元素
		printf(" %c ", BiTNode->data);
		
		// 左右子树入队列
		if (BiTNode->lchild != NULL){
			stack[rear++] = BiTNode->lchild;
		}
 
		if (BiTNode->rchild != NULL){
			stack[rear++] = BiTNode->rchild;
		}
	}
 
}

完整代码如下:

#include <stdio.h>
#include <stdlib.h>
 
#define MAXSIZE 100
 
 
// 二叉树的实现
 
// 定义 二叉树的 结构体
typedef struct BiTNode{
	char data;
	struct BiTNode *lchild;
	struct BiTNode *rchild;
}BiTNode, *BiTree;
 
// 依据前序遍历创建二叉树
 
BiTree CreateBiTree(){
	BiTNode *T = NULL;
	char c;
	scanf("%c", &c); 
 
	if (c != '#'){
		T = (BiTNode*)malloc(sizeof(BiTNode));
		T->data = c;
 
		T->lchild = CreateBiTree(); // 递归创建
		T->rchild = CreateBiTree();
	}
	else{
		T = NULL;
	}
 
	return T;
}
 
 
// 递归前序遍历二叉树
void PreOrder1(BiTree T){
	if (T != NULL){
		printf(" %c ", T->data);
		PreOrder1(T->lchild);
		PreOrder1(T->rchild);
	}
}
 
// 非递归前序遍历二叉树
void PreOrder2(BiTree T){
	BiTree stack[MAXSIZE], BiTNode;
	int top = -1;
 
	if (T == NULL){
		printf("树空\n");
		return;
	}
	else{
		top++;
		// 仿照一个栈
		stack[top] = T; // 将根节点入栈
		while (top > -1){
			//出栈
			BiTNode = stack[top--];
			printf(" %c ", BiTNode->data);
 
			// 先把右子树放进去,栈是先进去后出,所以下面的左子树先出
			if (BiTNode->rchild != NULL){
				stack[++top] = BiTNode->rchild;  // 入栈
			}
			if (BiTNode->lchild != NULL){
				stack[++top] = BiTNode->lchild;
			}
 
		}
 
	}
}
 
 
// 递归中序遍历二叉树
void InOrder1(BiTree T){
	if (T != NULL){
		InOrder1(T->lchild);
		printf(" %c ", T->data);
		InOrder1(T->rchild);
	}
}
 
// 非递归实现中序遍历二叉树
void InOrder2(BiTree T){
	BiTree stack[MAXSIZE], BiTNode;
	int top = 0;
	// 判断树是否为空
	if (T == NULL){
		printf("树空\n");
		return;
	}
	BiTNode = T;
 
	while (BiTNode != NULL || top > 0){
 
		// 将所有的左子树节点入栈
		while (BiTNode != NULL){
			stack[++top] = BiTNode;
			BiTNode = BiTNode->lchild;
		}
		//  如果右节点为空的话,执行下列语句
		BiTNode = stack[top--];
		printf(" %c ", BiTNode->data);
 
		// 扫描右节点
		BiTNode = BiTNode->rchild;
	}
 
}
 
 
// 递归后序遍历二叉树
void PostOrder1(BiTree T){
	if (T != NULL){
		PostOrder1(T->lchild);
		PostOrder1(T->rchild);
		printf(" %c ", T->data);
		
	}
}
 
// 非递归实现后序遍历
void PostOrder2(BiTree T){
 
	BiTNode *p = T;
	BiTNode *stack[MAXSIZE];
	int num = 0;
	BiTNode *have_visited = NULL;
 
	while (NULL != p || num>0)
	{
		while (NULL != p)
		{
			stack[num++] = p;
			p = p->lchild;
		}
		p = stack[num - 1];
		if (NULL == p->rchild || have_visited == p->rchild)
		{
			printf(" %c ", p->data);
			num--;
			have_visited = p;
			p = NULL;
		}
		else
		{
			p = p->rchild;
		}
	}
	
}

// 层次遍历,打印出二叉树的值
void Level_traversal(BiTree T){
 
	if (T == NULL){
		printf("树空\n");
		return;
	}
 
	BiTree stack[MAXSIZE], BiTNode;
	BiTNode = T;
	int front = 0;  // 使用 front, rear模拟队列
	int rear = 0;
 
	stack[rear++] = BiTNode;
 
	while (front != rear){
 
		BiTNode = stack[front++]; // 模拟队列,先获取front当前元素,然后在指向 front ++ 位元素
		printf(" %c ", BiTNode->data);
		
		// 左右子树入队列
		if (BiTNode->lchild != NULL){
			stack[rear++] = BiTNode->lchild;
		}
 
		if (BiTNode->rchild != NULL){
			stack[rear++] = BiTNode->rchild;
		}
	}
 
}
 
 
int main(){
 
	printf("请按先序输入二叉树:\n");
	BiTree T = CreateBiTree();
	printf("递归前序遍历:\n");
	PreOrder1(T);
	printf("\n");
	printf("递归中序遍历:\n");
	InOrder1(T);
	printf("\n");
	printf("递归后序遍历:\n");
	PostOrder1(T);
	printf("\n");
 
	printf("非递归实现前序遍历:\n");
	PreOrder2(T);
	printf("\n");
 
	printf("非递归实现中序遍历:\n");
	InOrder2(T);
	printf("\n");
 
	printf("非递归实现后序遍历:\n");
	PostOrder2(T);
	printf("\n");
 
	printf("层次遍历:\n");
	Level_traversal(T);
	printf("\n");

	return 0;
}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑟士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值