树的深度优先搜索和广度优先搜索
- 树的深度优先搜索:
前序遍历:根-左-右
中序遍历:左-根-右
后序遍历:左-右-根
循环将根节点的左子树压入栈中(并visit),直到没有左结点。将栈顶结点弹出,并遍历右子树
代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
//前序遍历
vector<int> res;
TreeNode *p = root;
stack<TreeNode *> s;
while(p!=NULL || !s.empty()){
while(p!=NULL){
res.push_back(p->val); //访问结点
s.push(p);
p = p->left;
}
if(!s.empty()){
p = s.top();
s.pop();
p = p->right;
}
}
return res;
}
};
循环将根节点的左子树的结点压入栈中,直到左子树遍历到底,然后弹出栈顶(visit),并遍历它的右子树
代码:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
//前序遍历
vector<int> res;
TreeNode *p = root;
stack<TreeNode *> s;
while(p!=NULL || !s.empty()){
while(p!=NULL){
s.push(p);
p = p->left;
}
if(!s.empty()){
p = s.top();
res.push_back(p->val); //访问结点
s.pop();
p = p->right;
}
}
return res;
}
};
访问过左右结点后,才能访问根节点,所以需要另外设置一个pre结点,来记录当前结点是否访问过。对于当前节点首先要判断其(如果含有右结点且右结点还未被访问过,需要遍历右结点),如果没有右结点或者右结点已经被访问过了,当前结点就可以被(visit),注意要更新pre指针,并将cur置为NULL
代码:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode *root) {
TreeNode * cur = root,*pre = NULL;
stack<TreeNode *> s;
vector<int> res;
while(cur!=NULL || !s.empty()){
while(cur!=NULL){
s.push(cur);
cur = cur->left;
}
if(!s.empty()){
cur = s.top();
//如果存在右结点,且右结点没有被访问过,先遍历右结点
if(cur->right!=NULL && cur->right!=pre){
cur = cur->right;
}else{
//左右结点都被访问过了之后,访问根节点
s.pop();
res.push_back(cur->val);
pre = cur;
cur = NULL;
}
}
}
return res;
}
};
- 树的广度优先搜索:
// 用queue实现的BFS
void BFS(Node *pRoot)
{
if (pRoot==NULL)
return;
queue<Node*> Q;
Q.push(pRoot);
while(!Q.empty())
{
Node *node = Q.front();
cout<<node->nVal<<"->";
if (node->pLeft!=NULL)
{
Q.push(node->pLeft);
}
if (node->pRight!=NULL)
{
Q.push(node->pRight);
}
Q.pop();
}
cout<<endl;
}
树的深度遍历的应用
sum-root-to-leaf-numbers
- 从栈中获取当前节点,如果是叶节点(进行相应处理–加到最后结果上即可),直接只需要弹出即可。
- 如果当前节点有左子树或者右子树,压入栈中即可。
- 循环步骤一和二
代码:
/**
- Definition for binary tree
- struct TreeNode {
- int val;
- TreeNode *left;
- TreeNode *right;
- TreeNode(int x) : val(x), left(NULL), right(NULL) {}
- };
*/
class Solution {
public:
int sumNumbers(TreeNode *root) {
if(root==NULL)
return 0;
int res = 0;
stack<TreeNode *> s;
TreeNode *p;
s.push(root);
while(!s.empty()){
p = s.top();
s.pop(); //对于当前节点
//如果是叶节点
if(p->left==NULL && p->right==NULL){
res +=p->val;
}
//否则,进行深度遍历的同时,更新节点的值
if(p->left!=NULL){
p->left->val += 10*(p->val);
s.push(p->left);
}
if(p->right!=NULL){
p->right->val += 10*(p->val);
s.push(p->right);
}
}
return res;
}
};
采用递归方式,思路更简洁:
sum保存上层得到的结果
- 对于当前节点如果为叶节点,直接返回即可
- 否则要分别遍历左子树和右子树(到叶节点)得到的结果的和
代码:
class Solution {
public:
int sumNumbers(TreeNode *root) {
//采用递归的方式
if(root==NULL)
return 0;
return dfsOrder(root, 0);
}
int dfsOrder(TreeNode *root, int sum){
if(root==NULL)
return 0;
sum = sum *10 + root->val;
if(root->left==NULL && root->right==NULL)
return sum;
return dfsOrder(root->left, sum)+dfsOrder(root->right,sum);
}
};