二叉树(C语言)这里记录了二叉树的一些基本概念。下面是在LeetCode上刷的有关二叉树的习题,在此做个记录。
LeetCode104.二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
题意容易理解,即找到最深的结点的层数。在曾经的数据结构课上,老师讲过一个求树的繁茂度的算法,繁茂度即树的最大宽度×最大深度,是利用层序遍历的思想,在遍历某一层的结点时,将下一层的结点数记录下来,这样求得最大宽度,每遍历一层便做个记录,得到最大深度。求繁茂度的代码如下:
#include #include typedef struct BINode
{
char data;
struct BINode *lchild,*rchild;
}BiNode,*BiTree;
BiTree create()
{
BiTree T;
char ch;
scanf("%c",&ch);
if(ch=='.') T=NULL;
else
{
T=(BiTree)malloc(sizeof(BiNode));
T->data=ch;
T->lchild=create();
T->rchild=create();
}
return T;
}
int main()
{
BiTree Root=create();//先构造一棵树,假设结点数小于10。
//在遍历当前层的同时,把下一层的结点数记录下来。
int curNode=1,nxtNode=0;//curNode为当前层次的结点数,nxtNode为下一层的节点数。
int front=0,end=0;//队列头和尾
BiTree queue[10],pTemp;//定义队列和中间变量 ,队列的容量不能数的结点数
queue[end++]=Root;//头结点进队列
int width=1,higth=0;
while(end != front)
{
pTemp=queue[front++];
if(pTemp->lchild != NULL)
{
queue[end++]=pTemp->lchild;
nxtNode++; //记录下一层的结点数
}
if(pTemp->rchild != NULL)
{
queue[end++]=pTemp->rchild;
nxtNode++; //记录下一层的结点数
}
curNode--;
if(curNode == 0)//curNode为0表示当前层次已经遍历完了
{
curNode=nxtNode;//把下一层的结点数赋给CurNode
if(nxtNode>width)
width=nxtNode;//nxtNode为每一层的宽度,求其最大值
higth++;//高度+1
nxtNode=0;//将nxtNode归零,再继续求下一层的结点数。
}
}
printf("%d",width*higth);
return 0;
}
我开始是想用这种方法来解题,但写代码的时候就隐约感觉队列的容量不够。果然提交之后提示我数组越界了,我将队列定义到函数外,开了很大的数组但仍旧通不过。在网上看大神的题解,用了递归的方法:
根结点的最大深度=max(左子树的最大深度,右子树的最大深度)+1。
左子树的最大深度和右子树的最大深度再分别递归调用这个公式来求出。当递归到空节点时,返回0结束递归;递归到叶子结点时返回1。代码如下:
int maxDepth(struct TreeNode* root) {
if(root==NULL)
return 0;
int left=maxDepth(root->left);
int right=maxDepth(root->right);
return (left>right?left:right)+1;
}
递归在二叉树中是非常实用的解题方法,遇到题是首先考虑适不适合用递归,递归可以减少代码量,使逻辑清晰明了。
LeetCode654.最大二叉树
给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下:
二叉树的根是数组中的最大元素。
左子树是通过数组中最大值左边部分构造出的最大二叉树。
右子树是通过数组中最大值右边部分构造出的最大二叉树。
通过给定的数组构建最大二叉树,并且输出这个树的根节点。
Example 1:
输入: [3,2,1,6,0,5]
输出: 返回下面这棵树的根节点6:
6
/ \
3 5
\ /
2 0
\
1
本题乍一看以为是二叉排序树,但仔细看其实是二分查找的变式。还是使用递归的方法来构造这棵特殊的树,找到当前序列中的最大值作为根节点,左右子树再分别从最大值的左右两边寻找最大值插入。复刻了二分查找的思想。代码如下:
struct TreeNode* construct(int nums[],int left,int right)
{
if(left>right)
return NULL; //表明结点已经插入完毕。
int max=nums[left],i;
int index=left;
for(i=left+1;i<=right;i++) //找到当前序列中的最大值
{
if(nums[i]>max)
{
max=nums[i];
index=i; //记录下最大值的索引,方便下一步递归。
}
}
struct TreeNode *T=(struct TreeNode*)malloc(sizeof(struct TreeNode));
T->val=max; //插入节点
T->left=construct(nums,left,index-1); //左子树由最大值左边的序列来构造
T->right=construct(nums,index+1,right); //右子树由最大值右边的序列来构造
return T;
}
struct TreeNode* constructMaximumBinaryTree(int* nums, int numsSize) {
return construct(nums,0,numsSize-1); //第一次递归,将整个数组传递进去。
}
LeetCode617.合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。
你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/ \
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
要合并的两棵二叉树,必须都当完全二叉树来操作,一些没有值的结点也要考虑到,这样就不会漏掉结点,还是利用递归的方法,将tree1当做母树,tree2往tree1上累加。累加时,必须保证两个结点的在各自树中的位置相同,必须同是第三层第三个节点或第四层第一个节点这样子。若两个结点都不为空,则将tree2上的结点值加到tree1上,若一个为空一个不为空,则将不为空的结点代替tree1的结点。若都为空,跟一个为空另一个不为空处理方法相同。代码如下(Java版,C语言类似):
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if (t1==null)
return t2;
if (t2==null)
return t1;
t1.val=t1.val+t2.val;
t1.left = mergeTrees(t1.left,t2.left);
t1.right = mergeTrees(t1.right,t2.right);
return t1;
}
}