404)左叶子之和(复习二叉树的四种遍历)

leetcode上看到一道题,计算给定的二叉树的所有左叶子之和

在这里插入图片描述

在这个二叉树中,有两个左叶子,分别是 9 和 15,所以返回 24

在做这个题之前,准备复习回顾一下二叉树的几种遍历方法。

二叉树的遍历

二叉树的遍历,是从根节点出发,按照某种规则访问树中的所有结点。

四种遍历方法:(前三种的前中后主要由访问根节点的时间决定)

前序遍历:先访问根节点,在访问左节点,最后访问右节点。
中序遍历:先访问左节点,再访问根节点,最后访问右节点。
后序遍历:由左往右先叶子节点访问完左右子树再访问根节点。
层序遍历:由根节点从上而下逐层遍历,从左到右访问。

二叉树树的创建

首先创建一个结构体:

struct TreeNode {
      int val;
      TreeNode *left;
      TreeNode *right;
      TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

然后创建二叉树:
使用vector 向量存储容器来保存传入的数值。
规则为从左到右一层层创建。

TreeNode* CreatTree(vector<int> &num,int n,int index){
    TreeNode* node=nullptr;
    if(index<n && num[index]!=-1){
        TreeNode* newnode=new TreeNode(0);
        newnode->val=num[index];
        newnode->left=newnode->right=nullptr;
        node=newnode;
//先左再右
        node->left=CreatTree(num,n,2*index+1);
        node->right=CreatTree(num,n,2*index+2);
    }
    return node;
}

递归法实现

递归实现前序遍历

void perOrderTreveral(TreeNode* node){
    if(node==nullptr)
        return;
    cout<<node->val<<"  ";
    perOrderTreveral(node->left);
    perOrderTreveral(node->right);
}

递归实现中序遍历

void inOrderTreveral(TreeNode* node){
    if(node==nullptr)
        return;
    inOrderTreveral(node->left);
    cout<<node->val<<"  ";
    inOrderTreveral(node->right);
}

递归实现后序遍历

void postOrderTraveral(TreeNode* node){
    if(node==nullptr)
        return;
    postOrderTraveral(node->left);
    postOrderTraveral(node->right);
    cout<<node->val<<"  ";
}

使用栈实现

栈的前序遍历
stack<TreeNode> Stack; 声明一个栈

void perOrdersatck(TreeNode* node){
    stack<TreeNode*> Stack;//声明一个栈
    TreeNode* treeNode=node;
    while(treeNode!=nullptr||!Stack.empty()){
        while(treeNode!=nullptr){
            cout<<treeNode->val<<"  ";
            Stack.push(treeNode);
            treeNode=treeNode->left;//先左
        }
        if(!Stack.empty()){
            treeNode=Stack.top();
            Stack.pop();
            treeNode=treeNode->right;
        }
    }
}

栈的中序遍历

void inOrderStack(TreeNode* node){
    stack<TreeNode*>Stack;
    TreeNode* treenode=node;
    while(treenode!=nullptr||!Stack.empty()){
        while(treenode!=nullptr){
            Stack.push(treenode);
            treenode=treenode->left;
        }
    if(!Stack.empty()){
        treenode=Stack.top();
        Stack.pop();
        cout<<treenode->val<<"  ";
        treenode=treenode->right;

        }
    }
}

栈的后序遍历
在后序遍历中需要一个变量来标记每次遍历的最后一次访问的节点

void postOrderStack(TreeNode* node){
    stack<TreeNode*>Stack;
    TreeNode* treenode=node;
    TreeNode* lastVist=nullptr;//用于标记每次遍历的最后一次访问的节点
    while(treenode!=nullptr||!Stack.empty()){//节点不为空,入栈,进入下一个左节点
        while(treenode!=nullptr){
            Stack.push(treenode);
            treenode=treenode->left;
        }
    if(!Stack.empty()){
        treenode=Stack.top();//当节点为空后弹出栈顶元素
      /*
        * 这块就是判断treeNode是否有右孩子,
        * 如果没有输出treeNode.data,让lastVisit指向treeNode,并让treeNode为空
        * 如果有右孩子,将当前节点继续入栈,treeNode指向它的右孩子,继续重复循环
        */
        Stack.pop();
        if(treenode->right==nullptr||treenode->right==lastVist)
        {
            cout<<treenode->val<<"  ";
            lastVist=treenode;
            treenode=nullptr;
        }
        else{
            Stack.push(treenode);
            treenode=treenode->right;
        }
        }
    }
}

二叉树的层序遍历

层序遍历,使用队列数据结构
1:声明一个队列
2:将头节点压入队列中
3:每次从队列中出队,记为node,打印值,如果node的left不为空,则node->left入队,如果有孩子不为空则将右孩子入队
4:重复3,知道队列为空

void levelOrder(TreeNode* node){

    /*
      1:声明一个队列
      2:将头节点压入队列中
      3:每次从队列中出队,记为node,打印值,如果node的left不为空,则node->left入队,
      如果有孩子不为空则将右孩子入队
      4:重复3,知道队列为空
    */
    queue<TreeNode* >q;
    q.push(node);
    while(!q.empty()){
        node=q.front();
        q.pop();
        cout<<node->val<<"  ";
        if(node->left!=nullptr)
            q.push(node->left);
        if(node->right!=nullptr)
            q.push(node->right);
    }
}

c++ STL --queue使用方法:

queue模板类定义于头文件
需要两个模板参数,1为元素类型,2为容器类
例如
queue q1;
queue<double*>q2;
操作
入队:q.push(x);将x接到队列末端
出队:q.pop(); 弹出队列的第一个元素,只是弹出,无返回值。
访问队首元素:q.front(); 即最早压入队列的元素
访问队尾元素:q.back(); 即最后被压入的元素
判断队列是否为空: q.empty(); 为空时返回ture
判断队列元素个数: q.size() ;返回元素个数

测试代码mian函数

int main(){
    vector<int>num{3,9,20,6,8,2};
    TreeNode* root=CreatTree(num,num.size(),0);
    cout<<"前序遍历:"<<endl;
    perOrderTreveral(root);
    cout<<endl;
    cout<<"中序遍历:"<<endl;
    inOrderTreveral(root);
    cout<<endl;
    cout<<"后序遍历:"<<endl;
    postOrderTraveral(root);
    cout<<endl;
    cout<<"栈前序遍历:"<<endl;
    perOrdersatck(root);
    cout<<endl;
    cout<<"栈的中序遍历:"<<endl;
    inOrderStack(root);
    cout<<endl;
    cout<<"栈的后序遍历:"<<endl;
    postOrderStack(root);
    cout<<endl;
    cout<<"层序遍历:"<<endl;
    levelOrder(root);
}

树结构如下:
在这里插入图片描述

运行效果如下
效果

题解:

回到这道题,求所有的左叶子之和,首先想到的是直接遍历每个点,判断是否为左叶子。
对于左叶子的判断,根据结构来看,可以得到当一个节点他的左孩子不为空,此节点左孩子的左孩子和右孩子都为空,那么此节点的左孩子为左叶子。
判断如下:

if(treeNode->left!=nullptr&&treeNode->left->left==nullptr&&treeNode->left->right==nullptr)

常规递归

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        if (!root) return 0;
        if (!root->left) return sumOfLeftLeaves(root->right);
        if (!root->left->left && !root->left->right) return root->left->val + sumOfLeftLeaves(root->right);
        return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right);
    }
};

在leetcode看到一个一行解

class Solution {
public:
    int sumOfLeftLeaves(TreeNode* root) {
        return root ? sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right) + (root->left && !root->left->left && !root->left->right ? root->left->val : 0) : 0;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值