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;
}
};