一句学习树结构的算法题的思路:
若要学会递归,则要学会递归
题目01
二叉树至下而上,从右向左的层次遍历算法
题目分析
题目的算法代码实现需要建立在层次遍历序列的基础上,基于上一篇文章的最后一题便是层次遍历二叉树的实现。链接如下:
层次遍历算法最后一题
根据以上的基础遍历代码,我们对其进行改进,由于要求如下:
其实现的要求图如下:
其实现代码如下:
typedef struct TNode{
ElemType data;
struct TNode* lchild, *rchild;
}TNODE,*BiTree;
//改进层次遍历算法
void levelOrder(BiTree * root){
InitStack(S);
InitQueue(Q);//初始化队列
BiTree * p = root;
if(p != NULL){
EnterQueue(Q,p);//入队列
while(! isEmpty(Q)){//队列不为空
DeQueue(Q,p);//出队列
push(S,p);//压入栈中
if(p->lchild != NULL){
EnterQueue(Q,p->lchild);//若左子树不为NULL,入队列左子树
}
if(p->rchild != NULL){
EnterQueue(Q,p->rchild);//若右子树不为NULL,入队列右子树
}
}
}
//进行从右至左的输出
while(! isEmpty(S)){
pop(S,p);
visit(p->data);//进行访问
}
}
相比于之前的基础层次遍历序列,其改进的地方就是在下面:
DeQueue(Q,p);//出队列
push(S,p);//压入栈中
//进行从右至左的输出
while(! isEmpty(S)){
pop(S,p);
visit(p->data);//进行访问
}
因此这里总结出一条重要的应对树结构的算法题的思路:
根据基础的四种遍历方式的递归或者非递归的现有算法模块进行修改,设置符合题目要求的算法。
题目02
假设二叉树采用二叉链表存储,设计一个算法求二叉树的高度(递归和非递归实现)
题目分析
根据题目的要求,需要对二叉树的高度进行递归和非递归的求解操作,因此下面将分别对二叉树的高度进行递归和非递归进行求解。
1、递归求解
思路概括:
根据上述的分析得到的二叉树递归求高度的算法代码如下:
//二叉树递归求高度
int GetHeightByBiTree(BiTree * root){
//第一种情况,判断是否为空
if(root == NULL){
return 0;//注意!,这里也是作为递归的出口
}
//递归获取左右子树的高度
int depth_Left = GetHeightByBiTree(root->lchild);
int depth_Right = GetHeightByBiTree(root->rchild);
//进行比较,较大者为子树的高度
if(depth_Left < depth_Right){
return depth_Right+1;//+1代表跟结点也为一层
}else{
//这里包括了depth_Left == depth_Right的情况
return depth_Left+1;
}
}
2、非递归实现
针对上述的递归实现,递归的算法代码简单,但是理解起来,有难度,如果旁边没有编辑器进行Debug的话,真的是很难直到里面实现的原理。因此下面介绍下求二叉树高度的非递归算法实现。
算法思想
同时对于层次遍历的代码,相信大家都不会陌生,上一篇文章就给出了相关的层次遍历代码设计,同时这里选择类循环的方式进行实现队列。
主要层序遍历基础代码如下:
if(root == NULL){
return 0;
}
int front = -1;
int rear = -1;
BiTreeNode Q[MAXSIZE];//定义一个队列
//入队列
rear++;
Q[rear] = root;//入队列,先加后赋值
while(front < rear){//这里判断队列有元素的条件为front
//之前的isEmpty不同
p = Q[++front];//出队列
if(p->lchild != NULL){//若左子树不为空,入队列
Q[++rear] = p->lchild;
}
if(p->rchild != NULL){
Q[++rear] = p->rchild;
}
}
这里为方便比较,也贴出了上一篇的基础的层次遍历代码:
typedef struct TNode{
ElemType data;
struct TNode* lchild, *rchild;
}TNODE,*BiTree;
//层次遍历代码
void BehindTraverse(BiTree root){
if(root == NULL){
return ;
}
InitQueue(Q);//初始化队列
TNODE *p;
//根节点如队列
EnterQueue(Q,root);
while(!isEmpty(Q)){
DeQueue(Q,p);//出队列
visit(p->data);//访问数据
//有左子树入队列
if(p->lchild != NULL){
EnterQueue(Q,p->lchild);
}
//右子树入队列
if(p->rchild != NULL){
EnterQueue(Q,p->rchild);
}
}
}
相比较之下,两种层次遍历代码的思想相同。为方便解题,这里采用第一种进行实现,下一步便是如何对第一种层序遍历代码进行改造。
改造思路
从而有改进的设计高度的算法核心如下:
if(front == last){
level++;
last = rear;
}
从而得到完整的非递归统计二叉树高度的代码如下:
//类循环层序遍历基础代码
int GetDepthByBitree(BiTree * root){
if(root == NULL){//root为null,返回0
return 0;
}
int front = -1;
int rear = -1;
int last = 0;
int level = 0;//设置初始化变量
BiTreeNode Q[MAXSIZE];//定义一个队列
BiTree * p;//操作指针
//根节点入队列
Q[++rear] = root;//入队列,先加后入队列才可以
while(front < rear){//表示队列有数据
p = Q[++front];//出队列
if(p->lchild != NULL){//若左子树不为NULL
Q[++rear] = p->lchild;
}
if(p->rchild != NULL){//若右子树不为NULL
Q[++rear] = p->rchild;
}
//进行结点的终点设置
//表示来到了某一层的最后一个结点,若没有到最后一个结点,下面不执行
if(front == last){
level++;
last = rear;
}
}
return level;
}
到此为止,非递归和递归求二叉树高度的代码如上!!!
题目03
设树B是一棵链式结构存储的二叉树,编写一个树中所有结点的左右子树进行交换的函数。【考研真题】
算法分析
这里引出C语言中最为频繁的交换代码内容:
//以a和b交换为例子
int temp = a;
a = b;
b = temp;
其采用递归的方法进行设计代码如下:
//递归的交换结点
void Swap_BiTree(BiTree * root){
BiTree * temp;
if(root == NULL){
return ;
}
if(root != NULL){
//不为空
swap(root->lchild);//交换左子树
swap(root->rchild);//交换右子树
//开始交换
temp = root->lchild;
root->lchild = root->rchild;
root->rchild = temp;
}
}
注:
个人代码问题或需要程序编写辅导服务等问题请加闲鱼【代码无bug】
或点击下面链接跳转闲鱼进行咨询
闲鱼链接