1.二叉树的前序遍历
二叉树的前序遍历比较简单,但是在力扣上写这个接口需要注意几个点:
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
}
- preorderTraversal 的返回值是动态开辟的数组,里面存放的是前序遍历的顺序
- int* returnSize 这个参数记录的是遍历到的数据个数,因为函数的返回值只能有一个,所以我们通它来记录,当用户需要数据个数时,直接查看该指针变量即可
代码:
int TreeSize(struct TreeNode* root){
if(root == NULL)
return 0;
return TreeSize(root->left) + TreeSize(root->right) + 1;
}
void _preOrder(struct TreeNode* root, int* a,int* i){
if(root == NULL)
return;
a[*i] = root->val; //记录当前节点,到数组中
(*i)++; //数组下标+1
_preOrder(root->left,a,i); //接着遍历左子树
_preOrder(root->right,a,i); //然后遍历右子树
}
//returensize是记录数组的元素个数,我们要返回给用户的是遍历数的数组
int* preorderTraversal(struct TreeNode* root, int* returnSize) {
*returnSize = TreeSize(root);//遍历树,得到数据个数
int* a = (int*)malloc(sizeof(int) * (*returnSize));//动态开辟数组空间
int i = 0;
_preOrder(root ,a,&i);//前序遍历
return a;
}
2.检查两棵树是否相同
思路:
利用前序遍历,先比较当前节点是否相同,紧接着比较左子树与右子树
代码:
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
if(p == NULL && q == NULL) //如果pq都为NULL,返回真
return true;
if(p == NULL || q == NULL) //代码到这里,只有2种可能,1.pq其中一个为NULL,2两个都不为NULL
//如果其中一个为NULL,说明另一个一定不是NULL,则pq不相等,不用
return false; //比较了,返回false
if(p->val != q->val) // 代码到这,说明pq都不为NULL,直接比较即可
return false; //比较qp相等没有用意义,要看它们不相等,可以直接出结果
return isSameTree(q->left,p->left) //在比较左右子树,右子树
&& isSameTree(q->right,p->right);
}
3.对称二叉树
思路:
观察示例一:一颗对称的二叉树,我的左子树根节点 == 你的右子树根节点、我的右子树根节点 == 你的左子树根节点。有一个地方不符合此规则,则此树不是对称二叉树
所以示例一是一颗对称二叉树,我们代码则使用递归的方法,先比较当前两棵树的根节点是否相同,在比较这两颗树的左右子树是否对称
代码:
bool _isSymmetric(struct TreeNode* q,struct TreeNode* p)
{
//先比较当前两颗子树的根节点是都相同
if(p == NULL && q == NULL)
return true;
if(p == NULL || q == NULL) //代码到这里,只有2种可能,1.pq其中一个为NULL,2两个都不为NULL
return false;
if(p->val != q->val)// 比较根节点是否相同
return false;
return _isSymmetric(q->left,p->right) //q节点的左子树,与p节点的右子树比
&& _isSymmetric(q->right,p->left); //q节点的右子树,与p节点的左子树比
}
bool isSymmetric(struct TreeNode* root) {
return _isSymmetric(root->left,root->right);
}
4.另一棵树的子树
思路:
题目给出了root树与subRoot树,让我们看看sybRoot树是否是root树中的一个子树
1.那么我们首先要做的是:如何找出root树的所有子树?
其实这个很简单,我们只需要遍历到root树的每一个节点就相当于找到了root树的所有子树,因为每一个节点都是某棵树的根节点,通过根节点自然得到了一节树
2.找到了所有子树之后我们要做的自然依次与subRoot树比较,看有没有相同的树了
我们前面已经写过检查两颗树是否相同,直接移植过来就可以
代码:
bool isSameTree(struct TreeNode* p, struct TreeNode* q) {
if(p == NULL && q == NULL)
return true;
if(p == NULL || q == NULL)
return false;
if(p->val != q->val)
return false;
return isSameTree(q->left,p->left)
&& isSameTree(q->right,p->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
if(root == NULL)//subRoot树上的节点数量范围是[1, 1000],所以当遍历到的子树为NULL时返回false
return false;
//当某一个子树的根节点与subRoot根节点相同时,开始比较两棵树是否相同
//当两颗树相同则直接出结果,不用接着去找了,返回ture
if(root->val == subRoot->val &&
isSameTree(root,subRoot))
return true;
//接着去遍历左子树与右子树,一边找到了就不用再继续找了,整体就是前序遍历的去遍历每一颗子树
return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}
5.二叉树的构建及遍历
利用,用户输入的数组先构建一颗二叉树,在进行中序遍历即可
代码:
#include <stdio.h>
#include<stdlib.h>
typedef char BTDataType;
typedef struct BinaryTreeNode {
BTDataType _data;
struct BinaryTreeNode* _left;
struct BinaryTreeNode* _right;
} BTNode;
BTNode* BuyNode(BTDataType x) {
BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));
if (newnode == NULL) {
perror("Buynode()::malloc()");
return newnode;
}
newnode->_data = x;
newnode->_left = NULL;
newnode->_right = NULL;
return newnode;
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root) {
if (root == NULL) {
return;
}
BinaryTreeInOrder(root->_left);//左子树
printf("%c ", root->_data);//根节点
BinaryTreeInOrder(root->_right);
}
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a,int* pi) {
//根,左子树,右子树
if (a[(*pi)] == '#') {
(*pi)++;
return NULL;
}
BTNode* newnode = BuyNode(a[(*pi)++]);
newnode->_left = BinaryTreeCreate(a,pi);
newnode->_right = BinaryTreeCreate(a,pi);
return newnode;
}
int main() {
char arr[101];
scanf("%s",arr);
int count = 0;
BTNode* tree = BinaryTreeCreate(arr,&count); //构建二叉树
BinaryTreeInOrder(tree); //中序遍历二叉树
return 0;
}
6.翻转二叉树
思路:
依旧是使用递归,先翻转左子树,在翻转右子树。由于翻转后,左右子树的根节点没有动,最后在将根节点翻转即可完成当前树的翻转
代码:
void _invertTree(struct TreeNode* root)
{
if(root == NULL)
return;
_invertTree(root->left); //翻转左子树
_invertTree(root->right); //翻转右子树
//在将自己左右子树的根节点交换,即可完成翻转
struct TreeNode* temp = root->left;
root->left = root->right;
root->right = temp;
}
struct TreeNode* invertTree(struct TreeNode* root) {
_invertTree(root);
return root;
}
7.平衡二叉树
平衡二叉树: 每个节点的左右子树的深度相差不超过1
思路:
遍历二叉树的每一个节点,算它们的高度差超过1吗,超过就不是平衡二叉树
代码:
int TreeHight(struct TreeNode* root)//求高度
{
if(root == NULL)
return 0;
int left = TreeHight(root->left);
int right = TreeHight(root->right);
return left > right ? left + 1 : right + 1;
}
//走前序遍历,依次遍历每个节点,并求节点左子树与右子树的高度差 >1?
bool isBalanced(struct TreeNode* root) {
if(root == NULL)
return true;
//比较当前节点左右子树高度差
int left = TreeHight(root->left);
int right = TreeHight(root->right);
if(abs(left-right) > 1)
return false;
if(isBalanced(root->left) == 0) //遍历左子树
return false;
if(isBalanced(root->right) == 0) //遍历右子树
return false;
return true; //代码到这说明它就是一颗平衡二叉树
}