1. 树的节点定义
每个节点都指向一个parent(根节点除外),每个节点可以有一个左孩子,一个右孩子。
struct Node{
Node* parent = NULL;
Node* left_child = NULL;
Node* right_child = NULL;
int data = -1;
Node(int e){
data = e;
}
Node* InsertAsLC(int e){
//插入左节点
Node* lc = new Node(e);
this->left_child = lc;
this->left_child->parent = this;
return lc;
}
Node* InsertAsRC(int e){
//插入左节点
Node* rc = new Node(e);
this->right_child = rc;
this->right_child->parent = this;
return rc;
}
int size(){
// 返回树的规模
if(!this)
return 0;
if(!left_child && !right_child)
return 1;
return 1+left_child->size()+right_child->size();
}
};
2. 树的遍历
2.1 先序遍历
先访问根节点,再访问左孩子,最后访问右孩子:
2.1.1 递归解法
void preorder_traverse(Node* root){
//树的先序遍历
if(root == NULL)
return;
cout<<root->data<<"$";
preorder_traverse(root->left_child);
preorder_traverse(root->right_child);
}
2.1.2 迭代解法
先令根节点入栈。在栈空之前,每次取top节点,使右孩子入栈、左孩子入栈。
stack<Node*> Stack;
Stack.push(root);
while(!Stack.empty()){
Node* top = Stack.top();
cout<<top->data<<"&";
Stack.pop();
if(top->right_child)
Stack.push(top->right_child);
if(top->left_child)
Stack.push(top->left_child);
2.2 中序遍历
先访问左孩子,然后访问父亲,然后访问右孩子。
2.2.1 递归方法
2.2.2 中序遍历下的直接后继
当该节点有右孩子,那么就是右边子树一直向左找到的那个节点:
如果该节点没有右孩子,那么就是该节点作为右孩子一直向左上找parent,最后一步再向右上走一步:
Node* succ(){
if(this->right_child){
//有右孩子
Node* r = this->right_child;
while(r->left_child){
r = r->left_child;
}
return r;
}
else{
//只有左孩子
Node* l = this;
while(l->parent != NULL && l->parent->right_child == l){
//向左上迈一步
l = l->parent;
}
return l->parent;
}
}
2.3 后序遍历
举例:表达式树就是后序遍历
2.4 层次遍历
例子:
void level_traverse(Node* root){
//树的先序遍历
queue<Node*> Q;
Q.push(root);
while(!Q.empty()){
Node* front = Q.front();
cout<<front->data<<"*";
Q.pop();
if(front->left_child)
Q.push(front->left_child);
if(front->right_child)
Q.push(front->right_child);
}
}
3. 二叉树重建
3.1 [前序 | 后序] + 中序
Leetcode: 重建二叉树 https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
if(preorder.size() == 0) //别忘记递归停止条件
return NULL;
if(preorder.size() == 1) {
TreeNode* root = new TreeNode(preorder[0]);
return root;
}
vector<int> preorder_left; //左子树的先序遍历
vector<int> preorder_right; //右子树的先序遍历
vector<int> inorder_left; //左子树的中序遍历
vector<int> inorder_right; //右子树的中序遍历
int mid = preorder[0];
TreeNode* root = new TreeNode(mid);
int mid_pos; //root在中序遍历的位置
for(int i = 0;i < inorder.size(); i++){
if(inorder[i] == mid){
mid_pos = i;
break;
}
}
int left_len = mid_pos;
for(int i=1;i<1+left_len;i++)
preorder_left.push_back(preorder[i]);
for(int i = 1+left_len; i<preorder.size();i++)
preorder_right.push_back(preorder[i]);
for(int i = 0;i<left_len;i++)
inorder_left.push_back(inorder[i]);
for(int i= left_len + 1;i<inorder.size();i++)
inorder_right.push_back(inorder[i]);
TreeNode* left_tree = buildTree(preorder_left,inorder_left);
TreeNode* right_tree = buildTree(preorder_right,inorder_right);
root->left = left_tree;
root->right = right_tree;
return root;
}
};