二叉树的遍历方式——递归与非递归

✅简介:与大家一起加油,希望文章能够帮助各位!!!!

💬保持学习、保持热爱、认真分享、一起进步!!!

一、二叉树的概括 

二叉树可以分为链式二叉树和顺序存储二叉树。

链式二叉树是一种常见的二叉树存储结构,它使用节点和指针来表示二叉树的结构。每个节点包含一个数据元素以及指向其左子树和右子树的指针。节点通过指针连接在一起,形成了一个树结构。链式二叉树灵活性较高,可以动态地进行插入和删除操作,但访问节点的效率稍低。

顺序存储二叉树是使用一维数组来存储二叉树结构的一种表示方法。将二叉树中每个节点的数据元素按照层次顺序依次存储在数组中,用于子节点和父节点之间的关联。通过计算数组下标与树中节点之间的关系,可以在一维数组中有效地表示二叉树的结构。顺序存储二叉树的主要优点是访问节点的效率高,但其缺点是不灵活,无法动态地进行插入和删除操作。

这两种存储方式各有优缺点。

定义了一个结构体类型BiNode,包含节点的值、左子树和右子树三个成员变量;同时,定义了指向结构体类型BiNode的指针类型BiTree

二、顺序二叉树的遍历

顺序存储二叉树在进行查找操作时,可以通过数组下标来定位节点。具体地说,对于数组中索引为i的节点,其左子节点的索引为2*i+1,右子节点的索引为2*i+2,而其父节点的索引为(i-1)/2。而遍历的话只需要使用循环即可。

  

 三、链式二叉树

1.链式二叉树的定义

定义了一个结构体类型BiNode,包含节点的值、左子树和右子树三个成员变量;同时,定义了指向结构体类型BiNode的指针类型BiTree。代码如下:下面结构体里面的value不一定非要是int类型,可以是任意类型。

typedef struct _hh{
	int value;
	struct _hh *lchild,*rchild;
}BiNode,*BiTree;

2.二叉树的遍历方式

2.1递归

2.1.1递归——先序遍历
void PreOrderTraverse(BiTree p)
{
	//如果p指针为空则结束 
	if(!p);
	else{
		//先输出根节点
		printf("%d\t",p->value);
		//接着调用自身,去遍历左子树 
		PreOrderTraverse(p->lchild);
		//等待该层的左子树遍历完全,再调用自身遍历右子树 
		PreOrderTraverse(p->rchild);
	}
}
2.1.2递归——中序遍历 
void PreOrderTraverse(BiTree p)
{
	//如果p指针为空则结束 
	if(!p);
	else{
		//先调用自身,去遍历左子树 
		PreOrderTraverse(p->lchild);
		//等待最后一层左子树为NULL,接着输出上层的根节点
		printf("%d\t",p->value);
		//再调用自身遍历右子树,待右子树遍历完全返回上一级 
		PreOrderTraverse(p->rchild);
	}
}
2.1.3递归——后序遍历
void PostOrderTraverse(BiTree p)
{
    // 如果当前节点不为空
    if (p != NULL) {
        // 后序遍历左子树
        PostOrderTraverse(p->lchild); // 递归调用,遍历当前节点的左子树
        // 后序遍历右子树
        PostOrderTraverse(p->rchild); // 递归调用,遍历当前节点的右子树
        // 输出当前节点的值
        printf("%d\t", p->value);
    }
}

2.2非递归——中序遍历 

通过栈的辅助,我们可以模拟递归的方式实现后序遍历的非递归版本。

栈——定义

下面代码段定义了一个包含数据和指向下一个节点的链栈结构体,通过StackNodeLinkStack两个类型别名,使得使用栈节点和栈指针更加方便和简洁。

typedef struct __StackNode{
	BiTree data;
	struct __StackNode *next;
}StackNode, *LinkStack;
 2.2.1栈的初始化
void InitStack(LinkStack* p)
{
	*p=NULL;
}
2.2.2入栈
bool Push(LinkStack* p,BiTree data)
{
	LinkStack q=(StackNode*)malloc(sizeof(StackNode));
	if(!q) return false;
	q->data=data;
	q->next=*p;	
	*p=q;
	return true;
}
2.2.3出栈
bool Pop(LinkStack* p,BiTree* data)
{
	if(!*p) return false;
	LinkStack q=*p;
	*data=(*p)->data;
		
	*p=(*p)->next;
	free(q);
	return true;
}
2.2.4中序遍历
void InOrder_unrec(BiTree T)
{
	StackNode s;
	LinkStack q;
	q=&s;
	InitStack(&q);
	// 当T不为空或栈不为空时循环 
	while( T || q!=NULL){
		//如果T不为空
		if(T){
//栈顶元素始终都是T的双亲节点,直到T为叶子(叶子->lchild=NULL) 
			Push(&q,T);
			T=T->lchild;
		}else{
//T为空进入else,现在准备出栈,把栈顶元素弹出T,此时变成了原T的双亲 
			Pop(&q,&T);
//此时T的左孩子为空,根据in-oder规则,输出根节点T,然后再以相同的方式遍历他的右孩子
			printf("%d ",T->value);
			//输出根节点后,遍历右孩子 
			T=T->rchild;
		} 
	}
}

总结

对于二叉树的遍历问题,递归方式通常更简洁,可读性更好,更容易去理解;非递归方式则具有更小的空间开销和更高的效率。具体使用哪种方式可以根据实际需求、问题规模和性能要求来选择。

以后也会持续更新!!!

成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。

以上均是个人的理解,如果有不对的地方请各位大佬帮忙斧正!

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

小羊没烦恼~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值