数据结构·树
树的特点
-
最小连通图
-
无环
-
有且只有 n − 1 n-1 n−1 条边
树的建立方式
顺序存储
void solve() {cin >> n;for (int i = 0; i<(1<<n); i++) {cin >> value[i + (1 << n)];}
结构体数组
-
使用整型存储父母和孩子的编号信息,结点的权值。
- P1364 医院设置
typedef struct node {int w,l,r,f;
};
vector<node>nodes(109, node());
链式存储
比结构体数组存储更加灵活,不依赖结点编号,且给定输入,父子关系明确。
leetcode的给定输入格式
- 使用结构体存储结点信息,使用指针的形式存储父母和孩子的信息。
* 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) {}
图的存储方式
树作为一种特殊的图,完全可以沿用图的存储方式
以下均为例题
遍历树的应用
-
对于遍历的理解,和递归三部曲的理解。
-
* 101. 对称二叉树:操作两个结点进行遍历,使用后序遍历收集结果。
bool dfs(TreeNode*left,TreeNode*right){if(!left&&right)return false;if(left&&!right)return false;if(!left&&!right)return true;return left->val==right->val&&dfs(left->left,right->right)&&dfs(left->right,right->left);}bool isSymmetric(TreeNode* root) {if(!root)return true;return dfs(root->left,root->right);}
- 104.二叉树的最大深度:后序遍历。
int dfs(TreeNode* root){if(!root)return 0;return max(dfs(root->left),dfs(root->right))+1;}int maxDepth(TreeNode* root) {return dfs(root); }
- 111.二叉树的最小深度:后序遍历,但是只有叶子结点才算深度,所以遍历空结点会干扰最后答案,干脆不遍历空结点,空结点设置为
INT_MAX
。终止条件也改为叶子结点。y
int dfs(TreeNode*root){if(!root->left&&!root->right)return 1;int left=INT_MAX,right=INT_MAX;if(root->left)left=dfs(root->left);if(root->right)right=dfs(root->right);return min(left,right)+1;}int minDepth(TreeNode* root) {if(!root)return 0;return dfs(root);}
222.完全二叉树的节点个数:后序遍历或者BFS。
int dfs(TreeNode*root){if(!root)return 0;return dfs(root->left)+dfs(root->right)+1;}int countNodes(TreeNode* root) {return dfs(root);}
- 110. 平衡二叉树:本质是比较高度。可以用
pair<int,int>
分别表示子树的高度和子树是否满足平衡二叉树,也可以用特殊值-1
处理。
int dfs(TreeNode* root){if(!root)return 0;int left=dfs(root->left);int right=dfs(root->right);if(left==-1||right==-1)return -1;if(left-right>=2||right-left>=2){return -1;}return max(left,right)+1;}bool isBalanced(TreeNode* root) {if(dfs(root)!=-1)return true;return false;}
- 257. 二叉树的所有路径:回溯,注意
to_string
函数的使用。还用了一点终止条件控制和带条件的遍历。
vector<string>res;void dfs(TreeNode* root,string s){if(!root)return;if(!root->left&&!root->right){res.push_back(s);}if(root->left){string tmp(s);tmp+="->";tmp+=to_string(root->left->val);dfs(root->left,tmp);} if(root->right){string tmp(s);tmp+="->";tmp+=to_string(root->right->val);dfs(root->right,tmp);}}vector<string> binaryTreePaths(TreeNode* root) {string s;s+=to_string(root->val);dfs(root,s);return res;}
- 404.左叶子之和:使用后序遍历。特殊判断是否存在左叶子结点。
int dfs(TreeNode* root){if(!root)return 0;int value=0;if(root->left){if(!root->left->left&&!root->left->right){value+=root->left->val;}}return value+dfs(root->left)+dfs(root->right);}int sumOfLeftLeaves(TreeNode* root) {return dfs(root);}
- 513.找树左下角的值:设置全局变量,然后dfs即可。
int ans=0;int max_depth=0;void dfs(TreeNode* root,int depth){if(!root)return;if(!root->left&&!root->right){if(depth>max_depth){max_depth=depth;ans=root->val;}}dfs(root->left,depth+1);dfs(root->right,depth+1);}int findBottomLeftValue(TreeNode* root) {dfs(root,1);return ans;}
- 112. 路径总和:后序遍历。
bool dfs(TreeNode* root,int sum,int targetSum){if(!root->left&&!root->right){if(sum==targetSum){return true;}return false;}bool left=false,right=false;if(root->left)left=dfs(root->left,sum+root->left->val,targetSum);if(root->right)right=dfs(root->right,sum+root->right->val,targetSum);return left||right;}bool hasPathSum(TreeNode* root, int targetSum) {if(!root)return false;return dfs(root,root->val,targetSum);}
TreeNode*dfs(vector<int>& inorder,vector<int>& postorder){if(inorder.size()==0)return nullptr;if(inorder.size()==1){TreeNode*node=new TreeNode(inorder[0]);return node;}int value=postorder[postorder.size()-1];TreeNode*root=new TreeNode(value);int idx=-1;for(int i=0;i<inorder.size();i++){if(inorder[i]==value){idx=i;break;}}vector<int>inorder_left(inorder.begin(),inorder.begin()+idx);vector<int>inorder_right(inorder.begin()+idx+1,inorder.end());vector<int>postorder_left(postorder.begin(),postorder.begin()+idx);vector<int>postorder_right(postorder.begin()+idx,postorder.end()-1);root->left=dfs(inorder_left,postorder_left);root->right=dfs(inorder_right,postorder_right);return root;}TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {return dfs(inorder,postorder);}