---------------------这片博客主要是总结二叉树部分的练习
主要有另个部分,一是二叉树链式结构、极其功能。二是相关而查实OJ。
-------------前言
(1)二叉树链式结构极其功能:
①链表的构建:
typedef int TreeDataType;
typedef struct TreeNode{
TreeDataType * data;
struct TreeNode* left;
struct TreeNode* right;
}TNode;
TNode* MyCreateTreeNode(char tmp); //初始化二叉树~
九个节点的开辟。
②链接:
为了检验我们是否链接成功,我们需要去遍历一遍二叉树.
③前中后序遍历:
前序遍历递归图:
中序、后序代码依旧变更不多,也就不再多画图>
④二叉树节点个数:
求二叉树节点的个数,需要去遍历一遍二叉树,那么选什么遍历容易些呢? 答案是后序。
求二叉树节点的个数有三种方法,其中很第一种和第二种的思想差多,就是环一种写法。最后一种就是传址变量++。
在求完二叉树节点个数,也不能忘了 也可以求叶子节点个数
⑤叶子节点个数:
什么是叶子呢? 度为0 的节点,就叫做叶子节点。所以在求叶子节点的是时候就有思路了。
没有叶子就返回0,有叶子就返回1。总共有多少,就把左右子树相加。
⑥第k层 节点个数问题:
最后结果:
⑦ 二叉树寻找值为x 的节点:
⑧需借用队列的 层序遍历:
层序遍历 也是 二叉树遍历的一种,但它较为复杂。
层序遍历的思想很简单:
没层 从左到右依次遍历。但需要借助队列实现。
注:入一个数据 剔除一个数据 并保留下一个数据方便入。
即可以,达到层序遍历的效果。
倒入数据开始前,需要值得注意的是>_
⑨判断是否是完全二叉树:
要判断二叉树,是否是完全二叉树,就需要写下每层的层序。因此,层序遍历能帮助我们去判断二叉树的形状。
与层序遍历不同的是,需要把NULL 也放入队列,如果遇到NULL 就退出。
所以,在遇到第一个NULL 后就去寻找 队列剩下元素 是否含有节点>_
很明显我们构建的树并不是完全二叉树。
如果我们在C的右子树 添加一个节点,并把G、H分别链接到D 的右边、E的左边。
⑩二叉树的销毁:
因为每个节点都是malloc开辟的。所以在销毁的时候,需要free掉每一个节点。
为了方便找寻下一个节点。所以采用后序遍历,一一free掉。
vesion1:
void BinaryTreeDestory(TNode* root)
{
if (root == NULL)
return;
BinaryTreeDestory(root->left);
BinaryTreeDestory(root->right);
free(root);
}
手动置空
vesion2:
通过传二级指针进去置空
//通过里面改外面
void BinaryTreeDestory2(TNode** proot)
{
if ((*proot) == NULL)
return;
//取地址不要忘了~!
BinaryTreeDestory2(&(*proot)->left);
BinaryTreeDestory2(&(*proot)->right);
free(*proot);
*proot = NULL;
}
也就成了完全二叉树了~
上面也就简单谈了二叉树链式结构的一些功能。到此为止……
(2)二叉树的OJ习题
OJ习题列表:
1.单值二叉树https://leetcode.cn/problems/univalued-binary-tree/2.二叉树的最大深度https://leetcode.cn/problems/maximum-depth-of-binary-tree/3.翻转二叉树https://leetcode.cn/problems/invert-binary-tree/4.相同的树https://leetcode.cn/problems/same-tree/5.对称二叉树https://leetcode.cn/problems/symmetric-tree/
6.平衡二叉树https://leetcode.cn/problems/subtree-of-another-tree/7.另一棵树的子树https://leetcode.cn/problems/subtree-of-another-tree/8.二叉树遍历https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking如果读者已经对上面的题了如指掌,也就不必再往下翻,见愚之见
OJ习题回顾:
1.单值二叉树:
bool isUnivalTree(struct TreeNode* root){
if(root == NULL)
return true;
if(root->left&&root->left->val!=root->val)
return false;
if(root->right&&root->right->val!=root->val)
return false;
return isUnivalTree(root->left)
&& isUnivalTree(root->right);
}
2.二叉树的最大深度
图示清晰地解释了,二叉树深度的遍历是后序。
左右子树递归回来,那边高度高,就加哪边。
int maxDepth(struct TreeNode* root){
if(root == NULL)
return 0;
int leftDepth=maxDepth(root->left);
int rightDepth=maxDepth(root->right);
return leftDepth>rightDepth? leftDepth+1:rightDepth+1;
}
3.翻转二叉树:
struct TreeNode* invertTree(struct TreeNode* root){
if(root == NULL)
return NULL;
//开始交换
struct TreeNode* tmp=root->right;
root->right=root->left;
root->left=tmp;
//递归左
invertTree(root->left);
//递归右
invertTree(root->right);
return root;
}
4.相同的树
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(p->left,q->left)
&& isSameTree(p->right,q->right);
}
5.对称二叉树:
bool isSameTree(struct TreeNode* left, struct TreeNode* right){
//叶子空树对称
if(left==NULL && right==NULL)
return true;
//如果他们一个为空另外一个不为空 结构不同
if(left==NULL || right==NULL)
return false;
//节点数值不相等
if(left->val != right->val)
return false;
//递归左右子树~
return isSameTree(left->left,right->right)
&& isSameTree(left->right,right->left);
}
bool isSymmetric(struct TreeNode* root){
if(root == NULL)
return true;
return isSameTree(root->left,root->right);
}
6.平衡二叉树:
首先分别求得左右子树的高度:
int maxDepth(struct TreeNode* root){
if(root == NULL)
return 0;
int leftDepth=maxDepth(root->left);
int rightDepth=maxDepth(root->right);
return leftDepth>rightDepth? leftDepth+1:rightDepth+1;
}
bool isBalanced(struct TreeNode* root){
if(root == NULL)
return true;
int leftmaxdepth=maxDepth(root->left);
int rightmaxdepth=maxDepth(root->right);
return abs(leftmaxdepth-rightmaxdepth) <2
&&isBalanced(root->left) //多颗子树也要满足
&&isBalanced(root->right);
}
此代码 的时间复杂度为最坏为O(N^2),因为有重复计算。
注:递归算法的时间复杂度=递归次数*每次递归函数的次数。
那如何提高效率呢?提升到O(N)?
把高度和是否为平衡树一起 进行判断
bool _isBalanced(struct TreeNode* root,int* ph)
{
//最后一层为空 肯定是平衡的
if(root ==NULL)
{
*ph=0;
return true;
}
//左右子树的高度
int lefthigh=0;
//如果递归的子树 不是平衡树也直接返回
if(_isBalanced(root->left,&lefthigh) == false)
return false;
int righthigh=0;
if(_isBalanced(root->right,&righthigh) == false)
return false;
*ph=fmax(righthigh,lefthigh)+1;
//保证自己是平衡树
return abs(righthigh-lefthigh)<2;
}
bool isBalanced(struct TreeNode* root){
int high=0;
return _isBalanced(root,&high);
}
7.另一颗子树
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(p->left,q->left)
&& _isSameTree(p->right,q->right);
}
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot){
if(root == NULL)
return false;
//遍历S的树 和t比较
//先比较自己
if(_isSameTree(root,subRoot)) //---->每个节点去做根
return true;
//再去递归他的左右子树
return isSubtree(root->left,subRoot)
|| isSubtree(root->right,subRoot);
}
8.二叉树遍历
还原的二叉树。
二叉树的链式:
typedef char TreeDataType;
typedef struct TreeNode
{
TreeDataType data;
struct TreeNode* left;
struct TreeNode* right;
}TNode;
函数参数要将str 的内容放入到 二叉树里,用i 来访问str 的内容。因此要传地址,对唯一的i进行更新。
TNode* MycreatTreeNode(char* a,int* pi)
{
if(a[*pi]=='#')
{
(*pi)++;
return NULL;
}
//构建根
TNode* newnode=(TNode*)malloc(sizeof(TNode));
newnode->data=a[*pi];
(*pi)++;
//构建左右子树
newnode->left= MycreatTreeNode(a,pi);
newnode->right= MycreatTreeNode(a,pi);
return newnode;
}
void InorderTree(TNode* root)
{
// 中序打印
if(root==NULL)
return;
InorderTree(root-left);
printf("%c ",root->data);
InorderTree(root-right);
}
也就做完啦~
这是今天的内容,希望对诸位能有收获。
祝你好运~