后序遍历在出入栈是,是先将左孩子进栈,处理完毕后出栈,再将右孩子入栈,最后再处理根结点。所以在非递归的后序遍历过程中,栈的深度即为当前的深度。利用这个特性,只需要遍历代码中记录最大深度即可。
/**
* 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:
int maxDepth(TreeNode* root) {
/*
本算法使用非递归的后序遍历。利用非递归的后序遍历算法的特性,对于一个节点:先把左入栈,随后出栈,再让右出栈。
这样保证在遍历过程中,栈的高度为树的深度。所以遍历就完了,加一句记录最大深度的代码即可。
时间复杂度为O(n),其中n为树节点个数。
空间复杂度为O(n),其中n为树的深度。好吧好像和递归的没什么区别。当作学习了
*/
stack<TreeNode*> S;
TreeNode* p = root,*r = NULL; //p为工作指针,r指向最近访问的节点。
int height = 0; //一开始树的深度记做 0
while(p||!S.empty()){ //当p为空(访问完某一点后才会被置空)或栈为空(开始或没有树结点时为空)才会退出循环。
if(p){ //走到最左边
S.push(p);
height = max(height,(int)S.size()); //栈的深度为当前节点的深度,记录那个最大的
p = p->left;
}else{
p = S.top(); //读取栈顶指针(非出栈)
if(p->right&&p->right!=r) //如果当前节点没有右孩子或者右孩子没被访问过的话
p = p->right;
else{
S.pop();
//visit(p->data);
r = p; //记录最近访问的指针
p = NULL; //每次出栈 == 遍历完以该结点为根的子树,需要将p设置为NULL,为了后面要退出循环。
}
}
}
return height;
}
};
接下来是一些比较常规的方法。
深度优先搜索二叉树的深度优先遍历有三种,前中后。下面这种方法和上面差不多,用的是后序遍历。只不过是递归和非递归的区别而已。
在思考树的递归时,不用想那么复杂,因为树本身就是一个递归定义的数据结构,思考时考虑典型的三个节点(根,左孩子,右孩子)即可
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL)return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
在访问到叶子结点时,return max(0,0)+1;
- 时空复杂度同上非递归版本
就是层次遍历
写了一半发现没有官方来的简洁明了,所以下面是官方代码。
官方代码通过增加一个sz变量,记录到每一层的个数。
class Solution {
public:
int maxDepth(TreeNode* root) {
if (root == nullptr) return 0;
queue<TreeNode*> Q;
Q.push(root);
int ans = 0;
while (!Q.empty()) {
int sz = Q.size();
while (sz > 0) { //分为内外循环,内循环每次只处理一层结点。
TreeNode* node = Q.front();Q.pop();
if (node->left) Q.push(node->left);
if (node->right) Q.push(node->right);
sz -= 1;
}
ans += 1;
}
return ans;
}
};
时间复杂度:O(n)。n 为二叉树的节点个数。每个节点只会被访问一次。
空间复杂度:O(n)。此方法空间的消耗取决于队列存储的元素数量。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)