目录
C++二叉树的一些基础
树节点的结构体
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}//无参构造
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}// 一个带有一个参数 x 的构造函数。它将 val 初始化为提供的值 x,并将 left 和 right 指针都设置为 nullptr
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
单独创建树节
#include <iostream>
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->right->left = new TreeNode(4);
root->right->right = new TreeNode(5);
return 0;
}
使用数组层次遍历建立二叉树
对于树的空节点,数组应该设置为NULL
vector<int>v = { 3,9,20,NULL,NULL,15,7 };// 在 C++中,NULL 被定义为整形常量 0
TreeNode* buildTree(vector<int>& nums)//层次遍历建立二叉树
{
if (nums.empty()) return nullptr;
TreeNode* root = new TreeNode(nums.front());
vector<TreeNode*> q = { root };
int i = 1;
while (!q.empty() && i < nums.size())
{
TreeNode* cur = q.front();
//q.assign(q.begin() + 1, q.end());
q.erase(q.begin());
if (i < nums.size())
{
cur->left = new TreeNode(nums[i++]);//层次遍历下,一个根节点的子节点按数组读取的顺序,左在前,右在后
q.push_back(cur->left);//将cur->left作为根节点添加到q中下次使用
}
if (i < nums.size())
{
cur->right = new TreeNode(nums[i++]);
q.push_back(cur->right);
}
}
return root;
}
层次遍历打印输出二叉树
广度优先
void levelOrderPrint(TreeNode* root)//层次遍历打印输出树,广度优先搜索
{
if (!root) return;//空树
vector<TreeNode*> q = { root };
while (!q.empty())
{
int size = q.size();
for (int i = 0; i < size; i++)
{
TreeNode* cur = q.front();
//q.assign(q.begin() + 1, q.end());
//q.front()与q.begin()的区别,q.front()返回头部的元素,q.begin()返回迭代器
q.erase(q.begin());
cout << cur->val << " ";
if (cur->left)
q.push_back(cur->left);
if (cur->right)
q.push_back(cur->right);
}
cout << endl;
}
}
二叉树的深度优先遍历(Depth-First Search, DFS)包括三种基本的方式:先序遍历(Pre-order Traversal)、中序遍历(In-order Traversal)和后序遍历(Post-order Traversal)。
先序,中序,后序遍历输出二叉树
void preOrderTraversal(TreeNode* root) {
if (root == nullptr) {
return;
}
cout << root->val << " ";
preOrderTraversal(root->left);
preOrderTraversal(root->right);
}
void inOrderTraversal(TreeNode* root) {
if (root == nullptr) {
return;
}
inOrderTraversal(root->left);
cout << root->val << " ";
inOrderTraversal(root->right);
}
void postOrderTraversal(TreeNode* root) {
if (root == nullptr) {
return;
}
postOrderTraversal(root->left);
postOrderTraversal(root->right);
cout << root->val << " ";
}
计算二叉树最大深度
递归,深度优先
int maxDepth(TreeNode* root)
{
if (root == nullptr) return 0;
int leftDepth = maxDepth(root->left);
int rightDepth = maxDepth(root->right);
return max(leftDepth, rightDepth) + 1;
}
计算二叉树中指定层的节点数量
使用递归,深度优先
int countNodesAtLevel(TreeNode* root, int level)
{
if(root == nullptr) return 0;
if(level == 0) return 1;
return countNodesAtLevel(root->left, level - 1) + countNodesAtLevel(root->right, level - 1);
}
判断两棵树 的叶子节点是否相似(值 和 顺序)
872.叶子相似的树
递归,深度优先
void dfs(vector<int> &v, TreeNode* root)
{
if (root->left == nullptr && root->right == nullptr)
{
v.push_back(root->val);
}
else
{
if (root->left != nullptr)
{
dfs(v, root->left);
}
if (root->right != nullptr)
{
dfs(v, root->right);
}
}
}
//什么时候递归结束呢,当节点左右指针都是空,即遇到叶子节点,递归结束
bool leafSimilar(TreeNode* root1, TreeNode* root2)//872.叶子相似的树
{
vector<int> v1;
dfs(v1, root1);
vector<int> v2;
dfs(v2, root2);
return v1 == v2;//vector容器支持比较操作
}
改进
void dfs(vector<int> &v, TreeNode* root)
{
if(root == nullptr) return;//如果返回类型是void,直接return;
if (root->left == nullptr && root->right == nullptr)
{
v.push_back(root->val);
}
dfs(v, root->left);
dfs(v, root->right);
}
1448.统计二叉树中好节点的数目
给你一棵根为 root 的二叉树,请你返回二叉树中好节点的数目。
「好节点」X 定义为:从根到该节点 X 所经过的节点中,没有任何节点的值大于 X 的值。
示例 1:
输入:root = [3,1,4,3,null,1,5]
输出:4
解释:图中蓝色节点为好节点。
根节点 (3) 永远是个好节点。
节点 4 -> (3,4) 是路径中的最大值。
节点 5 -> (3,4,5) 是路径中的最大值。
节点 3 -> (3,1,3) 是路径中的最大值。
示例 2:
输入:root = [3,3,null,4,2]
输出:3
解释:节点 2 -> (3, 3, 2) 不是好节点,因为 “3” 比它大。
示例 3:
输入:root = [1]
输出:1
解释:根节点是好节点。
int dfs_1448(TreeNode* root, int path_max)
{
if (root == nullptr) return 0;
int res = 0;
if (root->val >= path_max)
{
res++;
path_max = root->val;
}
res += dfs_1448(root->left, path_max) + dfs_1448(root->right, path_max);
return res;
}
int goodNodes(TreeNode* root)//1448.统计二叉树中好节点的数目
{
return dfs_1448(root, INT_MIN);//INT_MIN是最小int
}
void test1448()
{
vector<int>v1 = { 3,1,4,3,NULL,1,5 };
TreeNode* tree1 = buildTree(v1);
int num = goodNodes(tree1);
cout << "num " << num << endl;
cout << INT_MIN << endl;
}
错误版本
int dfs_1448(TreeNode* root, int path_max)
{
if (root == nullptr) return 0;
int res = 0;
if (root->val >= path_max)
{
res++;
path_max = root->val;
}
if(root->left != nullptr )
{
int res1 = dfs_1448(root->left,max);
}
if(root->right != nullptr)
{
int res2 = dfs_1448(root->right,max);
}
res = res + res1 + res2;
return res;
}
//错误原因:res1 和 res2 在递归调用 dfs 之后才会返回,你不能在当前函数的这一层直接使用它们
所以以后先递归调用,然后判断比较好
那么改进上一道题872.叶子相似的树
437.路径总和III
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
可以从任意节点开始计数,只要向下就行
这题用两次循环
一次从任意结点开始
一次向下遍历求和
int dfs_437(TreeNode* root, int targetSum)
{
if (root == nullptr) return 0;
int num = 0;
if (root->val == targetSum)
{
num++;
//path = 0;
}
num += dfs_437(root->left, targetSum - root->val);
num += dfs_437(root->right, targetSum - root->val);
//递归内部的数不会被记录,所以每次递归都要想办法把变化的数传下去
//这里需要传递的变量有两个,num,targetSum - root->val
//如果计算节点值累加,累加的数无法传递,只能用目标值递减的办法targetSum - root->val
return num;
}
int pathSum(TreeNode* root, int targetSum)//437.路径总和III
{
if (root == nullptr) return 0;
int num = dfs_437(root, targetSum);
num += pathSum(root->left, targetSum);//相当于第一层循环
num += pathSum(root->right, targetSum);
return num;
}
void test437()
{
vector<int>v1 = { 10,5,-3,3,2,NULL ,11,3,-2,NULL,1 };
TreeNode* tree1 = buildTree(v1);
int num = 8;
int path_num = pathSum(tree1, num);
cout << "path_num " << path_num << endl;
}
100.相同的树
判断两棵树是否相同
bool isSameTree(TreeNode* p, TreeNode* q)//100.相同的树
{
if (p == nullptr && q == nullptr) return true;
else if (p == nullptr || q == nullptr)
{
return false;
}
else if (p->val != q->val)
{
return false;
}
else
{
return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
}
226.翻转二叉树
TreeNode* invertTree(TreeNode* root) //226.翻转二叉树
{
if (root == nullptr) return root;
TreeNode* temp;
temp = root->left;
root->left = root->right;
root->right = temp;
invertTree(root->left);
invertTree(root->right);
return root;
}
101.对称二叉树
bool dfs_101(TreeNode* node1, TreeNode* node2)
{
if (node1 == nullptr && node2 == nullptr) return true;
else if (node1 == nullptr || node2 == nullptr) return false;
else
{
return node1->val == node2->val&& dfs_101(node1->left, node2->right)&& dfs_101(node1->right, node2->left);
}
}
bool isSymmetric(TreeNode* root)//101.对称二叉树
{
TreeNode* left = root->left;
TreeNode* right = root->right;
return dfs_101(left, right);
}
112.路经总和
bool hasPathSum(TreeNode* root, int targetSum)//112.路经总和
{
if (root == nullptr) return false;
else if (root->left == nullptr && root->right == nullptr)//找到叶子节点
{
return root->val == targetSum;
}
else
{
return hasPathSum(root->left, targetSum - root->val) || hasPathSum(root->right, targetSum - root->val);
}
}
129.求根节点到叶节点数字之和
给你一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。
叶节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12
从根到叶子节点路径 1->3 代表数字 13
因此,数字总和 = 12 + 13 = 25
int dfs_129(TreeNode* root,int prevSum)
{
if (root == nullptr) return 0;
int sum = root->val + prevSum * 10;
if (root->left == nullptr && root->right == nullptr)
{
return sum;
}
else
{
return dfs_129(root->left,sum) + dfs_129(root->right,sum);
}
}
int sumNumbers(TreeNode* root) //129.求根节点到叶节点数字之和
{
return dfs_129(root, 0);
}
有一个思考,在dfs中的return sum;之后是否就结束了整个递归
答案是没有,只是结束了这层递归,把结果返回给了上层递归,整个递归在遍历完整个树才结束
/////////////////////////////////////层次遍历///////////////////////////////////
199.二叉树的右视图
vector<int> rightSideView(TreeNode* root) //199.二叉树的右视图
{
vector<int> v;
if (root == nullptr) return {};
vector<TreeNode*> q = { root };
while (!q.empty())
{
int size = q.size();
for (int i = 0; i < size; i++)
{
TreeNode* cur = q.front();
cout << cur->val << " ";
q.erase(q.begin());
if (i == size - 1)
v.push_back(cur->val);//这一层末尾节点值就是需要的
if (cur->left)
q.push_back(cur->left);//将下一层的节点加入队列
if (cur->right)
q.push_back(cur->right);
}
cout << endl;
}
return v;
}
637.二叉树的层平均值
vector<double> averageOfLevels(TreeNode* root) //637.二叉树的层平均值
{
vector<double> v;
if (root == nullptr) return {};
vector<TreeNode*> q = { root };
while (!q.empty())
{
int size = q.size();
double sum = 0;
for (int i = 0; i < size; i++)
{
TreeNode* cur = q.front();
cout << cur->val << " ";
q.erase(q.begin());
sum += cur->val;
if (cur->left)
q.push_back(cur->left);//将下一层的节点加入队列
if (cur->right)
q.push_back(cur->right);
}
cout << endl;
v.push_back(sum / size);
}
return v;
}
102.二叉树的层次遍历
vector<vector<int>> levelOrder(TreeNode* root) //102.二叉树的层次遍历
{
vector<vector<int>> v;
if (root == nullptr) return {};
vector<TreeNode*> q = { root };
while (!q.empty())
{
vector<int> temp;
cout <<"size " << size << endl;
cout <<"q.size() " << q.size() << endl;
int size = q.size();
for (int i = 0; i < size; i++)
//for (int i = 0; i < q.size(); i++)
{
TreeNode* cur = q.front();
cout << cur->val << " ";
q.erase(q.begin());
temp.push_back(cur->val);
if (cur->left)
q.push_back(cur->left);
if (cur->right)
q.push_back(cur->right);
}
cout << endl;
v.push_back(temp);
}
return v;
}
找了半天的一个BUG
int size = q.size();
for (int i = 0; i < size; i++) {}
和
for (int i = 0; i < q.size(); i++){}有什么区别
第二种是错误的,因为如果循环体内q改变,那么每次循环,条件都会变
第一种size不会改变
744

被折叠的 条评论
为什么被折叠?



