二叉树
二叉树(Binary Tree) 是由n个结点构成的有限集(n≥0),n=0时为空树,n>0时为非空树。对于非空树T:
- 有且仅有一个根结点;
- 除根结点外的其余结点又可分为两个不相交的子集T1和T2,且T1、T2也是二叉树。
简而言之,最多有两个子树的树为二叉树
满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
除了最后一层的节点没有任何子节点外,每层上的所有节点都有两个节点的二叉树。
完全二叉树:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
也就是说,如果把满二叉树从右至左、从下往上删除一些节点,剩余的结构就构成完全二叉树
二叉搜索树:二叉搜索树是一个有序树,其性质如下:
- 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 它的左、右子树也分别为二叉排序树
平衡二叉树(AVL):是一颗高度平衡的二叉搜索树;左右两个子树的高度差绝对值不超过1,且左右两个子树都是平衡二叉树;通过左旋右旋来实现平衡。
C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树
平时使用二叉树一般为链式存储,和链表原理一致:
递归算法
递归算法是一种直接或者间接调用自身函数或者方法的算法。说简单了就是程序自身的调用,就是将原问题不断分解为规模缩小的子问题,然后递归调用方法来表示问题的解。(用同一个方法去解决规模不同的问题)。
递归实现思想步骤:
-
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
-
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
-
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己,缩小问题规模,开始递去,到达终止条件后开始归来,以实现递归的过程。
对称二叉树
题目描述:
给你一个二叉树的根节点 root , 检查它是否轴对称。
思路:比较是否对称就需要最左边的元素和最右边的元素比较,即从两侧开始比较。因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。
使用递归法判断:
- 确定递归函数的参数和返回值:
要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。返回类型则是bool型。
bool compare(TreeNode* left,TreeNode* right)
- 确定终止条件:
终止条件需要判断,首先判断当节点为空的时候。
if(left==nullptr&&right!=nullptr)
return false;
if(left!=nullptr&&right==nullptr)
return false;
if(left==nullptr&&right==nullptr)
return true;
当节点不为空但值不同时也可以直接返回false。
if(left->val!=right->val)
return false;
- 确定单层递归的逻辑
单层递归的逻辑就是处理左右节点都不为空,且数值相同的情况。
首先比较二叉树外侧是否对称,传入左节点的左孩子,右节点的右孩子。
然后比较二叉树内测是否对称,传入左节点的右孩子,右节点的左孩子。
如果左右都对称就返回true ,有一侧不对称就返回false 。
bool out=compare(left->left,right->right);
bool in=compare(left->right,right->left);
return out&∈
完整代码如下:
/**
Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
*/
class Solution {
public:
bool compare(TreeNode* left,TreeNode* right)
{
if(left==nullptr&&right!=nullptr)
return false;
if(left!=nullptr&&right==nullptr)
return false;
if(left==nullptr&&right==nullptr)
return true;
if(left->val!=right->val)
return false;
bool out=compare(left->left,right->right);
bool in=compare(left->right,right->left);
return out&∈
}
bool isSymmetric(TreeNode* root) {
return compare(root->left,root->right);
}
};
翻转二叉树
题目描述:
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
思路:可以使用递归,把每个节点的左右孩子反转一下,达到整体反转二叉树的目的。
-
确定递归函数的参数和返回值
参数就是要传入节点的指针,不需要其他参数。返回值可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode* -
确定终止条件
当遍历到前节点为空的时候,就返回。 -
确定单层递归的逻辑
使用先序遍历,需要先交换左右孩子,然后再反转左右子树
代码实现如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* reverse(TreeNode* root)
{
if(root==nullptr)
return nullptr;
else
{
TreeNode *temp;
temp=root->left;
root->left=root->right;
root->right=temp;
reverse(root->left);
reverse(root->right);
}
return root;
}
TreeNode* invertTree(TreeNode* root) {
return reverse(root);
}
};