二叉树的基本性质
遍历:递归和迭代
(自己调用自己,有终止条件和返回值)(不停循环,利用栈的性质)
在迭代中,前序遍历是可以一边访问节点一边处理节点而中序遍历要先访问到最左边的节点,再开始处理节点,然后进行中右节点的访问。
层序遍历
迭代,栈先入后出,适合的是深度优先遍历
层序,队先进先出,适合的是广度优先遍历
翻转二叉树
递归里,前序,后序遍历只需要调整顺序即可,但是中序就需要两次指向左。
有一个错误,写成了root->left=reverse(root->left);应该是reverse(root->left);
class Solution {
public:
TreeNode* reverse(TreeNode* root){
if(root == nullptr) return root;
reverse(root->left);
swap(root->left,root->right);
reverse(root->left);
return root;
}
TreeNode* invertTree(TreeNode* root) {
return reverse(root);
}
};
迭代里,前序,后序,中序都没问题。
因为迭代用栈来遍历,把一个个结点都放进去了,而不是靠指针来遍历,避免了递归法中翻转了两次的情况。
572.subtree of anthor tree
这道题让我重新意识到自己的写的迭代法是错的!!每次会遇到问题:
Line 172: Char 16: runtime error: reference binding to misaligned address 0xbebebebebebec0b6 for type 'TreeNode *', which requires 8 byte alignment (stl_deque.h)
是因为代码写错啦!!
当你把根结点放进入的时候,开启while循环。拿出栈顶的时候,要判断是空结点还是数值结点,不要pop啊!!或者pop之后,if else那里不要pop!!
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
stack<TreeNode*> sta;
sta.push(root);
while(!sta.empty()){
TreeNode* node = sta.top();
//sta.pop();
if(node != nullptr){
sta.pop();
if(node->left) sta.push(node->left);
if(node->right) sta.push(node->right);
sta.push(node);
sta.push(NULL);
}
else{
sta.pop();
TreeNode* midnode = sta.top();
sta.pop();
if(compare(midnode,subRoot))
return true;
//if(midnode->val == subRoot->val){
//return compare(midnode,subRoot);
//}
else
continue;
}
}
return false;
}
class Solution {
public:
bool compare(TreeNode* cur,TreeNode* subcur){
if(cur == NULL && subcur == NULL) return true;
else if(cur != NULL && subcur == NULL) return false;
else if(cur == NULL && subcur != NULL) return false;
else if(cur->val != subcur->val) return false;
else{
return (compare(cur->left,subcur->left) && compare(cur->right,subcur->right));
}
}
bool isSubtree(TreeNode* root, TreeNode* subRoot) {
if(root == nullptr) return false;
else if(compare(root,subRoot)){
return true;
}
return (isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot));
}
};
完全二叉树的结点个数
1.完全二叉树的概念
2.层序遍历其实也是一个结点一个结点的加。时间复杂度O(n)
3.如果利用完全二叉树的特性,且节省时间的话,利用的是当前结点一直到最左边的高度等于一直到右边的高度,中间的结点不用算,所以节省了时间。O(logn*logn)
4.思考清楚递归的时候终止条件是找到符合条件3的子树,不然的话就一直递归。
二叉树的最大深度,最小深度的深入思考
1.关于递归顺序,前序迭代中左右本质上算的是深度,所以我一开始思考的时候,先想到的是后序遍历,左右中算的高度,之所以也通过了最大深度这道题是因为最大深度和这个树的高度是一样的答案。
2.真正算深度的话,是前序遍历哦,用回溯法。
3.层序遍历,每到一层高度就+1.
4.note最小深度和最大深度不一样的地方就是会出现一个特殊的树
平衡二叉树
1.平衡二叉树的概念:所有子树的左右高度差不超过1
2. 求深度可以从上到下去查:前序遍历(中左右),而高度从下到上去查:后序遍历(左右中),又涉及到了和上面的题一样的思考点
3. 利用递归函数返回值判断是否是平衡二叉树,如果是-1的话,则不是,则从左就开始返回-1,一直传回中结点。不是-1的话,就一直返回正常的高度值。
4. 层序遍历可以求深度,但是求不了高度。
二叉树的所有路径
这道题也和求最大深度一样可以用回溯法。
1.回溯法,调用的是void traversal(TreeNode* cur, vector_int &path)
2.递归,调用的是void traversal(TreeNode* cur, vector_int path),递归本身就包含回溯了。
思考:最大深度里的回溯(TreeNode* cur, int depth+1)传递的是一个数值,不涉及到指针,&数组复制。