二叉树基本操作之递归和非递归遍历、分支节点数详解

 更新时间:2023年09月25日 08:32:09   作者:小熊不吃香菜  
这篇文章主要介绍了二叉树基本操作之递归和非递归遍历、分支节点数详解,二叉树是由n(n>=0)个结点的有限集合构成,此集合或者为空集,或者由一个根结点及两棵互不相交的左右子树组成,并且左右子树都是二叉树,需要的朋友可以参考下

二叉树的定义

二叉树是由n(n>=0)个结点的有限集合构成,此集合或者为空集,或者由一个根结点及两棵互不相交的左右子树组成,并且左右子树都是二叉树.

递归定义:叉树可以是空集合,根可以有空的左子树或空的右子树。二叉树不是树的特殊情况,它们是两个概念。

typedef char ElemType;
typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

二叉树的遍历

原表达式:a+b*(c-d)-e/f

先序遍历:-+a*b-cd/ef

中序遍历:a+b*c-d-e/f

后序遍历:abcd-*+ef/-

先序递归遍历过程

即先序遍历完成

 
void PreOrderTraverse(BiTree BT)
{
	if(BT)
	{
		if(!(BT->data))
			return;
		printf("%c",BT->data);
		PreOrderTraverse(BT->lchild);
		PreOrderTraverse(BT->rchild);
	}
}

中序遍历和后序遍历同上

层次非递归遍历

该树的层次递归遍历为:ABCDEGF

运用队列来存储树的结点首先A入队,输出A结点,然后队首结点A出队,将A的孩子结点B,C分别入队。访问队首结点B,输出并出队,将B的孩子结点D,E入队。访问队首结点C,输出并出队,C结点只有右孩子,将C的右孩子结点G入队。访问队首结点D,输出并出队,D没有孩子结点,不入队。访问队首结点E,输出并出队,将E的孩子结点F入队。访问队首结点G,输出并出队,G没有孩子结点,不入队。访问队首结点F,输出并出队,F没有孩子结点,不入队。此时队列为空,结束遍历。

void leverTraverse(BiTree BT)
{
	Squeue Q;
	BiTree pt=BT;
	InitQueue(&Q);
	EnQueue(&Q,pt);
	while(!EmptyQueue(Q))
	{
		Dequeue(&Q,&pt);
		printf("%c",pt->data);
		if(pt->lchild)
			EnQueue(&Q,pt->lchild);
		if(pt->rchild)
			EnQueue(&Q,pt->rchild);
	}
}

完整代码:

// erchashu.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#define MAXSIZE 50
int max=0;
typedef char ElemType;
typedef struct BiTNode{
	ElemType data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
typedef struct SQueue{
	BiTree *base;
	int front;
	int rear;
}Squeue;
void InitBiTree(BiTree *BT)
{
	*BT=NULL;
}
void PreCreatBiTree(BiTree *BT)
{
	ElemType ch;
	printf("输入数据:\n");
	getchar();
	ch=getchar();
	if(ch=='#')
		*BT=NULL;
	else
	{
		*BT=(BiTree)malloc(sizeof(BiTNode));
		(*BT)->data=ch;
		PreCreatBiTree(&(*BT)->lchild);
		PreCreatBiTree(&(*BT)->rchild);
	}
}
void PreOrderTraverse(BiTree BT)
{
	if(BT)
	{
		if(!(BT->data))
			return;
		printf("%c",BT->data);
		PreOrderTraverse(BT->lchild);
		PreOrderTraverse(BT->rchild);
	}
}
void InOrderTraverse(BiTree BT)
{
	if(BT)
	{
		if(!(BT->data))
			return;
		InOrderTraverse(BT->lchild);
		printf("%c",BT->data);
		InOrderTraverse(BT->rchild);
	}
}
void PostOrderTraverse(BiTree BT)
{
	if(BT)
	{
		if(!(BT->data))
			return;
		PostOrderTraverse(BT->lchild);
		PostOrderTraverse(BT->rchild);
		printf("%c",BT->data);
	}
}
void InitQueue(Squeue *Q)
{
	(*Q).base=(BiTree *)malloc(sizeof(BiTNode)*MAXSIZE);
	(*Q).front=(*Q).rear=0;
}
void EnQueue(Squeue *Q,BiTree BT)
{
	(*Q).base[(*Q).rear++]=BT;
}
int EmptyQueue(Squeue Q)
{
	if(Q.front==Q.rear)
		return 1;
	return 0;
}
void Dequeue(Squeue *Q,BiTree *pt)
{
	if((*Q).front==(*Q).rear)
		return;
	*pt=(*Q).base[(*Q).front];
	(*Q).front=((*Q).front +1) % MAXSIZE;
}
void leverTraverse(BiTree BT)
{
	Squeue Q;
	BiTree pt=BT;
	InitQueue(&Q);
	EnQueue(&Q,pt);
	while(!EmptyQueue(Q))
	{
		Dequeue(&Q,&pt);
		printf("%c",pt->data);
		if(pt->lchild)
			EnQueue(&Q,pt->lchild);
		if(pt->rchild)
			EnQueue(&Q,pt->rchild);
	}
}
void NRPreOrderTraverse(BiTree BT)
{
	BiTree pt=BT,stack[MAXSIZE];
	int top=0;
	while(pt || top)
	{
		if(pt)
		{
			printf("%c",pt->data);
			stack[top++]=pt;
			pt=pt->lchild;
		}
		else
		{
			pt=stack[--top];
			pt=pt->rchild;
		}
	}
}
int BiTreedepth(BiTree BT,int depth)
{
	if(BT)
	{
		if(BT->lchild)
			BiTreedepth(BT->lchild,depth+1);
		if(BT->rchild)
			BiTreedepth(BT->rchild,depth+1);
	}
	if(depth>max)
		max=depth;
	return depth;
}
int LeafNumber(BiTree BT)
{
	if(!BT)
		return 0;
	else
	{
		if((!BT->lchild) && (!BT->rchild))
			return 1;
		else
			return LeafNumber(BT->lchild)+LeafNumber(BT->rchild);
	}
}
int singleBiTree(BiTree BT)
{
	if(!BT)
		return 0;
	else
	{
		if(BT->lchild && !BT->rchild)
			return singleBiTree(BT->lchild)+1;
		else
		{
			if(!BT->lchild && BT->rchild)
				return singleBiTree(BT->lchild)+1;
			else
				return singleBiTree(BT->lchild)+singleBiTree(BT->rchild);
		}
	}
}
int doubleBiTree(BiTree BT)
{
	int book=0;
	if(!BT)
		return 0;
	if(BT->lchild && BT->rchild)
		book=1;
	return book+doubleBiTree(BT->lchild)+doubleBiTree(BT->rchild);
}
void revoluteBiTree(BiTree *BT)
{
	BiTree T;
	if(!(*BT)->lchild && !(*BT)->rchild)
		return;
	else
	{
		T=(*BT)->lchild;
		(*BT)->lchild=(*BT)->rchild;
		(*BT)->rchild=T;
	}
	if((*BT)->lchild)
	{
		revoluteBiTree(&(*BT)->lchild);
	}
	if((*BT)->rchild)
	{
		revoluteBiTree(&(*BT)->rchild);
	}
}
int main(int argc, char* argv[])
{
	BiTree BT;
	int tmp;
	int flag=1,select;
	InitBiTree(&BT);
	while(flag)
	{
		printf("\n请选择:\n");
		printf("0. 先序创建二叉树用#代表空结点\n");
		printf("1. 先序遍历\n");
		printf("2. 中序遍历\n");
		printf("3. 后序遍历\n");
		printf("4. 非递归层次遍历\n");
		printf("5. 非递归先序遍历\n");
		printf("6. 二叉树高度\n");
		printf("7. 叶结点数目\n");
		printf("8. 单分支结点数目\n");
		printf("9. 双分支结点数目\n");
		printf("10. 交换二叉树\n");
		printf("11.退出程序\n");
		printf("请输入要执行的操作:\n");
		scanf("%d",&select);
		switch(select)
		{
			case 0:
				PreCreatBiTree(&BT);
				break;
			case 1:
				printf("\n先序遍历为:\n");
				PreOrderTraverse(BT);
				break;
			case 2:
				printf("\n中序遍历为:\n");
				InOrderTraverse(BT);
				break;
			case 3:
				printf("\n后序遍历为:\n");
				PostOrderTraverse(BT);
				break;
			case 4:
				printf("\n层次非递归遍历为:\n");
				leverTraverse(BT);
				break;
			case 5:
				printf("\n先序非递归遍历为:\n");
				NRPreOrderTraverse(BT);
				break;
			case 6:
				printf("\n高度为:   ");
				BiTreedepth(BT,1);
				printf("%d\n",max);
				break;
			case 7:
				printf("\n叶结点数目为: ");
				tmp=LeafNumber(BT);
				printf("%d\n",tmp);
				break;
			case 8:
				printf("\n单分支结点数目为: ");
				tmp=singleBiTree(BT);
				printf("%d\n",tmp);
				break;
			case 9:
				printf("\n双分支结点数目为: ");
				tmp=doubleBiTree(BT);
				printf("%d\n",tmp);
				break;
			case 10:
				printf("\n已交换二叉树\n");
				revoluteBiTree(&BT);
				break;
			default:
				flag=0;
				printf("Press any key to exit!\n");
				break;
		}
	}
	printf("\n");
	return 0;
}
 

到此这篇关于二叉树基本操作之递归和非递归遍历、分支节点数详解的文章就介绍到这了,更多相关二叉树基本操作内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现一个简易聊天室流程

    Java实现一个简易聊天室流程

    这篇文章主要介绍了我的java课程设计一个多人聊天室(socket+多线程)本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-11-11
  • Java AQS中闭锁CountDownLatch的使用

    Java AQS中闭锁CountDownLatch的使用

    CountDownLatch 是一个同步工具类,用来协调多个线程之间的同步,它能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。被将利用CountDownLatch实现网络同步请求,异步同时获取商品信息组装,感兴趣的可以了解一下
    2023-02-02
  • Springboot整合minio实现文件服务的教程详解

    Springboot整合minio实现文件服务的教程详解

    这篇文章主要介绍了Springboot整合minio实现文件服务的教程,文中的示例代码讲解详细,对我们的工作或学习有一定帮助,需要的可以参考一下
    2022-06-06
  • Springboot使用Junit测试没有插入数据的原因

    Springboot使用Junit测试没有插入数据的原因

    这篇文章主要介绍了Springboot使用Junit测试没有插入数据的原因,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-04-04
  • Java设计模式之策略模式详解

    Java设计模式之策略模式详解

    这篇文章主要为大家详细介绍了Java设计模式之策略模式,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • MQ的消息模型及在工作上应用场景

    MQ的消息模型及在工作上应用场景

    这篇文章主要介绍了MQ的消息模型及在工作上应用场景,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • 详解使用IntelliJ IDEA新建Java Web后端resfulAPI模板

    详解使用IntelliJ IDEA新建Java Web后端resfulAPI模板

    这篇文章主要介绍了详解使用IntelliJ IDEA新建Java Web后端resfulAPI模板,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-08-08
  • Jmeter如何获取jtl文件中所有的请求报文详解

    Jmeter如何获取jtl文件中所有的请求报文详解

    JMeter的可以创建一个包含测试运行结果的文本文件,这些通常称为JTL文件,因为这是默认扩展名,但可以使用任何扩展名,这篇文章主要给大家介绍了关于Jmeter如何获取jtl文件中所有的请求报文的相关资料,需要的朋友可以参考下
    2021-09-09
  • Android设备如何保证数据同步写入磁盘的实现

    Android设备如何保证数据同步写入磁盘的实现

    这篇文章主要介绍了Android设备如何保证数据同步写入磁盘的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • java实现监控rtsp流转flv方法实例(前端播放,前后端代码都有)

    java实现监控rtsp流转flv方法实例(前端播放,前后端代码都有)

    这篇文章主要给大家介绍了关于java实现监控rtsp流转flv的相关资料,文中介绍的是前端播放,前后端代码都有,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-06-06

最新评论