数据结构-17.二叉树的层次遍厉-由遍历序列构造二叉树

二叉树层次遍历与构造算法解析
本文详细介绍了二叉树的层次遍历算法,利用链式队列实现,从根节点开始,逐层访问每个节点。同时讨论了如何根据遍历序列来构造二叉树,指出中序遍历结合任意一种遍历方式能唯一确定一棵二叉树。重点在于理解遍历过程及节点的前后继关系。

一.层次遍历:

算法思想:
1.初始化一个辅助队列
2.根结点入队
3.若队列非空,则队头结点出队,访问该结点,并将其左右孩子插入队尾
4.重复3直到队列为空

//二叉树结点(链式存储)
typedef struct BiTNode{
	char data;
	struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

//链式队列结点
typedef struct LinkNode{
	BiTNode *data;		//存指针而不是结点
	struct LinkNode *next;
}LinkNode;

typedef struct{
	LinkNode *front,*rear;
}LinkQueue; 

//层序遍历
void LevelOrder(BiTree T){
	LinkQueue Q;		//由于不确定树的结点有多少,我们用链队列
	InitQueue(Q);		//初始化辅助队列
	BiTree p;		
	EnQueue(Q,T);		//根结点入队
	while(!IsEmpty(Q)){
		Dequeue(Q,p);				//队头结点出队
		visit(p);					//访问出队结点
		if(p->lchild!=NULL)
			Enqueue(Q,p->lchild);	//左孩子入队
		if(p->rchild!=NULL)
			Enqueue(Q,p->rchild);	//右孩子入队
	}
}	

二.由遍历序列构造二叉树:(手算)

只给出一课二叉树的 前/中/后/层 序遍历的一种,不能唯一确定一棵二叉树。
中序+任意一种遍历方式可以确定唯一一棵二叉树。
关键是找到根结点。
由于二叉树有n+1个指针链域,可用来记录前驱后继信息。

数据结构与算法中,常见的由双遍历序列构造二叉树的方法是利用先序序列和中序序列,或者中序序列和后序序列来构建。 ### 由先序序列和中序序列构造二叉树 先序遍历的顺序是根节点 -> 左子树 -> 右子树,中序遍历的顺序是左子树 -> 根节点 -> 右子树。先序序列的第一个元素就是根节点,在中序序列中找到该根节点的位置,就可以划分出左子树和右子树的中序序列,进而根据左右子树的节点数量划分出先序序列中的左右子树部分,然后递归地构造左右子树。 以下是实现该算法的代码: ```c #include <stdio.h> #include <stdlib.h> typedef struct BTNode { char data; struct BTNode *lchild; struct BTNode *rchild; } BTNode; // 由先序序列和中序序列构造二叉树 BTNode* CreateBT1(char* pre, char* in, int n) { BTNode* b; char* p; int k; if (n <= 0) return NULL; b = (BTNode*)malloc(sizeof(BTNode)); // 创建根结点 b->data = *pre; for (p = in; p < in + n; p++) { // 在中序中找等于*pre字符的位置k if (*p == *pre) { break; } } k = p - in; // 确定根结点在in中的位置 b->lchild = CreateBT1(pre + 1, in, k); // 递归构造左子树 b->rchild = CreateBT1(pre + k + 1, p + 1, n - k - 1); // 递归构造右子树 return b; } ``` ### 由中序序列和后序序列构造二叉树 后序遍历的顺序是左子树 -> 右子树 -> 根节点,中序遍历的顺序是左子树 -> 根节点 -> 右子树。后序序列的最后一个元素就是根节点,在中序序列中找到该根节点的位置,同样可以划分出左子树和右子树的中序序列,再根据左右子树的节点数量划分出后序序列中的左右子树部分,最后递归地构造左右子树。 以下是实现该算法的代码: ```c // 由中序序列和后序序列构造二叉树 BTNode* CreateBT2(char* post, char* in, int n) { BTNode* b; char r, *p; int k; if (n <= 0) return NULL; r = *(post + n - 1); // 根结点值 b = (BTNode*)malloc(sizeof(BTNode)); // 创建根结点 b->data = r; for (p = in; p < in + n; p++) { // 在in中查找根结点 if (*p == r) break; } k = p - in; // k为根结点在in中的下标 b->lchild = CreateBT2(post, in, k); // 递归构造左子树 b->rchild = CreateBT2(post + k, p + 1, n - k - 1); // 递归构造右子树 return b; } ``` ### 代码解释 - **`CreateBT1`函数**:接收先序序列`pre`、中序序列`in`和节点数量`n`作为参数。首先判断节点数量是否小于等于 0,如果是则返回`NULL`。然后创建根节点,将先序序列的第一个元素赋值给根节点。接着在中序序列中找到根节点的位置,确定左右子树的节点数量,递归地构造左右子树。 - **`CreateBT2`函数**:接收后序序列`post`、中序序列`in`和节点数量`n`作为参数。同样先判断节点数量是否小于等于 0,若是则返回`NULL`。取后序序列的最后一个元素作为根节点,在中序序列中找到该根节点的位置,划分左右子树的序列,递归构造左右子树。 ### 复杂度分析 - **时间复杂度**:两种方法的时间复杂度均为 $O(n)$,其中 $n$ 是二叉树的节点数量,因为每个节点都会被访问一次。 - **空间复杂度**:递归调用栈的深度为 $O(h)$,其中 $h$ 是二叉树的高度,最坏情况下为 $O(n)$。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值