基础算法与数据结构(二) 树(1)基础二叉树
树的基本数据结构
1
2
3
4
5
6
7
8
9
10
11
12
//tree
struct normalTreeNode {
int val;
TreeNode* sons[];
};
//binary tree
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
树的基本概念
- 根、子树、叶结点
- 节点的度、分支节点、孩子、双亲、子孙、深度
- 二叉树:每个节点至多只有两棵子树(度不大于2)
二叉树的典型架构
二叉树的性质
二叉树可以使用数组存储。
- 在二叉树的第i层上最多只有2^(i-1)个结点
- 深度为k的二叉树至多有2^k - 1 个结点
- 对任何一棵二叉树T,如果其终端结点数为n0,度为2的节点数为n2,则n0=n2+1
- 具有n个结点的完全二叉树的深度为[log2n]+1
二叉树的遍历
二叉树的遍历分为三种: 前序(root-left-right)、中序(left-root-right)、后序(left-right-root) (以root所在的位置为基准)
三种遍历均可用递归和非递归的方式进行,前序中序的非递归主要用一个栈来模拟递归的出入顺序,代码分别如下 所有结果都存在vector中返回 括号内数字为对应leetCode题目编号
- 前序(144)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
//递归 vector<int> route; void PreOrderTraversal(TreeNode* root){ if(!root){ route.push_back(root->val); PreOrderTraversal(root->left); PreOrderTraversal(root->right); } } //非递归 vector<int> PreOrderTraversal(TreeNode* root){ vector<int> route; stack<TreeNode*> s; TreeNode* cur = root; while(cur || s.empty()){ while(cur){ route.push_back(cur->val); s.push(cur); //go to the most left cur = cur->left; } if(!s.empty()){ cur = s.top(); s.pop(); //back to right cur = cur->right; } } return route; }
- 中序(94)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
//递归 vector<int> route; void InOrderTraversal(TreeNode* root){ if(!root){ InOrderTraversal(root->left); route.push_back(root->val); InOrderTraversal(root->right); } } //非递归 vector<int> InOrderTraversal(TreeNode* root){ vector<int> route; stack<TreeNode*> s; TreeNode* cur = root; while(cur || s.empty()){ while(cur){ s.push(cur); //go to the most left cur = cur->left; } if(!s.empty()){ cur = s.top(); s.pop(); route.push_back(cur->val); //back to right cur = cur->right; } } return route; }
- 后序(145)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
//递归 vector<int> route; void PostOrderTraversal(TreeNode* root){ if(!root){ PostOrderTraversal(root->left); PostOrderTraversal(root->right); route.push_back(root->val); } } //非递归 vector<int> PostOrderTraversal(TreeNode* root){ stack<TreeNode> s; vector<int> ans; TreeNode* pre,cur; pre = NULL; if(root == NULL) return ans; s.push(root); while(!s.empty()){ cur = s.top(); //要么左右均为空,那么就是叶子节点放入route,或者前一个是左结点或者右结点回溯回来的,此时也是已经访问过左右放入父节点 if((!cur->left&&!cur->right) || (pre && (pre == cur->left || pre == cur->right))){ s.pop(); ans.push_back(cur.val); pre = cur; }else{ //向栈内先放右,再放左,先进后出 if(cur->right) s.push(cur->right); if(cur->left) s.push(cur->left); } } return ans; }
二叉树典型题
一般二叉树的题目都可以用递归的方法解决。(例如 求树的深度,树的最浅深度以及最深度等问题)
翻转二叉树 (leetCode 226)
这道题有一句名言那。。。
Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.!
分别翻转左右即可。。
1
2
3
4
5
6
7
8
9
10
TreeNode* invertTree(TreeNode* root) {
if(root==NULL) return NULL;
root->left = invertTree(root->left);
root->right = invertTree(root->right);
TreeNode* tmp = root->left;
root->left = root->right;
root->right = tmp;
return root;
}
利用前序/中序构造二叉树
根据前序中序的特征可以来模拟写出程序。
先找到前序中的第一个,然后利用这个在中序中找到这个值,然后这个值之前的在左子树中,之后的在右子树中,然后分别递归再次利用这个方法继续建树。
同样的可以利用中序/后序构建二叉树。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder){
if(preorder.empty() || inorder.empty()) return NULL;
TreeNode* root = new TreeNode(preorder[0]);
if(preorder.size()==1 && inorder.size()==1) return root;
int inOrderNum = FindNode(inorder,preorder[0]);
vector<int> a(preorder.begin()+1,preorder.begin()+inOrderNum+1);
vector<int> b(inorder.begin(),inorder.begin()+inOrderNum+1);
vector<int> c(preorder.begin()+inOrderNum+1,preorder.end());
vector<int> d(inorder.begin()+inOrderNum+1,inorder.end());
root->left = buildTree(a,b);
root->right = buildTree(c,d);
return root;
}
int FindNode(vector<int> &v,int target){
int size = v.size();
for(int i=0;i<size;i++){
if(v[i] == target) return i;
}
return -1;
}
This post is licensed under CC BY 4.0 by the author.