数据结构代码题----树的应用代码题Day02

数据结构代码题—树的应用

一句学习树结构的算法题的思路:

若要学会递归,则要学会递归

题目01

二叉树至下而上,从右向左的层次遍历算法

题目分析

题目的算法代码实现需要建立在层次遍历序列的基础上,基于上一篇文章的最后一题便是层次遍历二叉树的实现。链接如下:

层次遍历算法最后一题

根据以上的基础遍历代码,我们对其进行改进,由于要求如下:

  1. 从上而下----------层次遍历可以保证
  2. 从右至左----------需要一个辅助数据结构进行设计

其实现的要求图如下:

数据结构代码题----树的应用代码题Day02_第1张图片
总的来说执行过程就是:

  1. 根节点入队
  2. 队列不为空–根节点出队-----入栈
  3. 对根节点的左右子树的NULL进行判断,
  4. 不为NULL则进入队列,入栈
  5. 循环执行以上过程

其实现代码如下:

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、递归求解

思路概括:

  1. 若根节点为NULL,则直接返回0;----无数据
  2. 若左子树不为NULL,则递归去求左子树的高度,
  3. 若右子树不为NULL,则递归去求右子树的高度。
  4. 得到左子树和右子树的高度,
  5. 根据二叉树的高度定义:左子树和右子树中高度较大者为二叉树的高度
  6. 因此对其进行左子树和右子树高度的判断,return deep(较大者)+1;
  7. +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的话,真的是很难直到里面实现的原理。因此下面介绍下求二叉树高度的非递归算法实现。

算法思想

  1. 首先我们需要采用层次遍历的算法(四种遍历方式,对于本题求高度,只有层次遍历最适合)
  2. 设置一个变量level表示二叉树的层数,
  3. 设置一个last指向遍历的当前层的最后一个结点

同时对于层次遍历的代码,相信大家都不会陌生,上一篇文章就给出了相关的层次遍历代码设计,同时这里选择类循环的方式进行实现队列

  1. 其实现方式是设置两个指针front和rear进行实现,
  2. 下面的层次遍历代码与上一篇的基础层次遍历算法相同。

图解:
数据结构代码题----树的应用代码题Day02_第2张图片

主要层序遍历基础代码如下:


	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);
		}
	}
}

相比较之下,两种层次遍历代码的思想相同。为方便解题,这里采用第一种进行实现,下一步便是如何对第一种层序遍历代码进行改造。

改造思路

  1. 使用last指向当前层次的最后结点
  2. 对last指向结点的起点—last = front
  3. 对last指向结点的终进行设计,last=rear

实现过程图如下:
数据结构代码题----树的应用代码题Day02_第3张图片

从而有改进的设计高度的算法核心如下:

	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是一棵链式结构存储的二叉树,编写一个树中所有结点的左右子树进行交换的函数。【考研真题】

算法分析

算法实现图解:
数据结构代码题----树的应用代码题Day02_第4张图片
思路:

  1. 在对于一个问题进行具体的操作无法对其进行定义时,需要用到抽象的方法进行设计,抽象-----最佳体现便是递归
  2. 递归的交换左右子树
  3. 先交换根节点的左右子树
  4. 做交换第二层的结点

这里引出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】
或点击下面链接跳转闲鱼进行咨询

闲鱼链接

数据结构代码题----树的应用代码题Day02_第5张图片

你可能感兴趣的:(二叉树,二叉树层序遍历,数据结构,算法)