内代码已上传GitHub:点击我 去GitHub查看代码
写在前面 : 昨天学习了《数据结构与算法分析-C语言版》里的二叉树, 但...只看概念总觉得知识量太大,于是找了些简单题动手做做。
104. 二叉树的最大深度
思路
找二叉树的最大深度,首先我能想到的就是递归。递归深度 + 1则 深度计数 + 1,并保存最大深度。
还是自己题做的少,这题在传参的时候由于max值需要更新, 所以cnt计数需要指针传值...下面看代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void find(struct TreeNode* node, int *cnt, int *max){
// 空节点直接返回
if(node == NULL) return;
// 该节点非空 计数加一 更新当前深度
(*cnt)++;
// 更新最大深度
if(*cnt > *max){
*max = *cnt;
}
//进入下一层
find(node -> left, cnt, max);
find(node -> right, cnt, max);
// 当前深度搜索完毕,返回上一深度 计数减一
(*cnt)--;
}
int maxDepth(struct TreeNode* root){
// cnt记录深度 max记录最大深度
int cnt, max;
cnt = max = 0;
// 遍历树
find(root, &cnt, &max);
return max;
}
上面的递归过程写的很清楚了,每次向下搜索节点,cnt++。当当前深度搜索完毕, 返回上一深度,cnt--;用// 空节点直接返回 if(node == NULL) return;
判定搜索到NULL节点,且判定需要在cnt++前。
108. 将有序数组转换为二叉搜索树
写这道题的时候,可真是遇到不少坑:
什么是二叉搜索树? 翻了翻书, 原来是 左节点值 < 右节点值 的树。
什么是高度平衡二叉树? 这题题干里写了,高度平衡二叉树是指一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1。
是否有唯一性? 如果只看二叉搜索树的定义, 那结果多了去了。再加上高度平衡二叉树的定义,那也只是要求 abs(l - r) <= 1。如果数组元素个数是奇数,那取中间元素为root节点,那高度差可以为0,但是如果数组元素个数是偶数,这时候选中间的两个元素其一即可。所以这题的答案 没有唯一性 。
思路:
根据以上的基础,模仿二分查找递归的生成高度平衡二叉搜索树就行了。
- 如果右边界定义为index + 1, 则偶数个数时选取靠右的元素。如果右边界定义为index, 则偶数个数是选取靠左的元素。
同样的,递归过程也要进行相应的修改:
// 左右节点递归生成
p -> left = Create(nums, left, mid - 1);
p -> right = Create(nums, mid + 1, right);
/**
*偶选右
p -> left = Create(nums, left, mid);
p -> right = Create(nums, mid + 1, right);
*/
-
注意树叶的判定:
完整代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* Create(int* nums, int left, int right){
// left > right 即已经Create到树叶了
if(left > right) return NULL;
/**
*偶选右
*left > right 即已经Create到树叶了
if(left == right) return NULL;
*/
// 新节点
struct TreeNode* p = (struct TreeNode*)malloc(sizeof(struct TreeNode));
// 中间值下标
int mid = (left + right) / 2;
p -> val = nums[mid];
// 左右节点递归生成
p -> left = Create(nums, left, mid - 1);
p -> right = Create(nums, mid + 1, right);
/**
*偶选右
p -> left = Create(nums, left, mid);
p -> right = Create(nums, mid + 1, right);
*/
return p;
}
struct TreeNode* sortedArrayToBST(int* nums, int numsSize){
// 已经有序了,所以直接二分,递归
// 偶选左
return Create(nums, 0, numsSize - 1);
// 偶选右
//return Create(nums, 0, numsSize);
}
110. 平衡二叉树
上一题刚刚写完生成高度平衡二叉搜索树,这题就要我们来判定一棵树是不是高度平衡二叉树......
这题的解决在我看来仍然用到了 递归 的思想
思路:
头节点有两个子节点, 那我们如果要判定这两子树的高度差绝对值不超过1,可以先去判定这两子树各自的子树的高度。同样的,要想知道整棵树的高度,首先我们要遍历到树叶。树叶可以看作本题最小的子树,高度为1。
上图的 9 和 20这两子树 , 9这棵树的高度为1, 20的高度为2。这时整棵树的高度时这两子树高度的最大值,所以高度为2.
我们在递归到树叶这一层时开始返回,返回过程中如果已经判定到高度差不符合要求,可直接返回特定值,避免后续继续深入递归。
完整代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
// dfs 记录 l r深度 比较后返回
int judge(struct TreeNode* root){
// 访问到叶子,返回1
if(!root) return 1;
// 左子树深度 , 右子树深度
int l, r;
// 分别搜索左右子树 不是高度平衡二叉树, 返回 -1 否则返回子树高度
return ((l = judge(root -> left)) == -1
|| (r = judge(root -> right)) == -1
|| l - r > 1 || l - r < -1
)
? -1 : 1 + (l > r ? l : r);
}
bool isBalanced(struct TreeNode* root){
return judge(root) != -1;
}
以上代码需要注意的就是:
这里 前两个judge 继续递归,但如果其中一个返回-1都会使其余表达式失效,可以避免做多余的递归。如果前面的条件都不满足,说明高度差满足,则返回 1 + 子树最大高度。
226. 翻转二叉树
这题看备注好像很难是不是...其实很简单...就dfs同时交换子节点就行了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
// 翻转
void reverse(struct TreeNode* node){
// 其实直接node就行,但是我不想做多余的翻转
if(node && (node -> left || node -> right)){
struct TreeNode* temp = node -> left;
node ->left = node -> right;
node -> right = temp;
}else
return;
reverse(node -> left);
reverse(node -> right);
}
struct TreeNode* invertTree(struct TreeNode* root){
//翻转 ----- DFS
reverse(root);
return root;
}
注意:
一开始我直接写的 if(node)
, 也AC了。但是其实没必要交换两个NULL节点, 所以加了些限定条件。
这题难度非常小,用来当递归入门题都行23333.
617. 合并二叉树
思路:
题目的意思就是只要对应位置有一棵树节点非空,把对应节点值相加赋给新的树的对应节点。
解法还是先遍历,直接先序遍历吧,遍历到哪个节点就处理哪个节点,全部遍历一遍之后也就合并完成了。
完整代码:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
// 合并
struct TreeNode* Merge(struct TreeNode* t1, struct TreeNode* t2){
// t1 t2 有一个不为空
if(t1 || t2){
// 新节点
struct TreeNode* newp = (struct TreeNode*)malloc(sizeof(struct TreeNode));
// 置空
newp -> left = newp -> right = NULL;
// 相加
newp -> val = (t1 ? t1 -> val : 0) + (t2 ? t2 -> val : 0);
// 左指针
newp -> left = Merge(t1 ? t1 -> left : NULL, t2 ? t2 -> left : NULL);
// 右指针
newp -> right = Merge(t1 ? t1 -> right : NULL, t2 ? t2 -> right : NULL);
// 返回合并后当前树
return newp;
}else{
// 都为空返回NULL
return NULL;
}
}
struct TreeNode* mergeTrees(struct TreeNode* t1, struct TreeNode* t2){
// 合并二叉树 ----- 递归
return Merge(t1, t2);
}
总结:
做完这5题,感觉树的简单操作很多都可以依靠递归来完成。
二叉树 、 二叉搜索树、 二叉高度平衡树。 扩展了一些知识。
树的相关操作还是基于 节点。熟悉链表操作的话,一开始接触树不会太难。
时间不多,就选一些发了出来,继续学习,继续刷题!
如果有看不懂的,私信我!!!
~^^
每天进步一点,加油!
END