树的定义,想必大家都不陌生,在树正式进入前,我们需要回顾一下二叉树的几种遍历方法,尤其很多题目都是围绕树的递归遍历进行考察。
树的递归遍历
#include <iostream>
#include <vector>
using namespace std;
struct Node{
int val;
Node * left;
Node * right;
Node(int x) :val(x), left(nullptr), right(nullptr){};
};
Node* createTree(vector<int> tree, int start){
if (tree[start] == -1) {
return NULL;
}
Node* root = new Node(tree[start]);
int lnode = 2*start + 1;
int rnode = 2*start + 2;
if ( lnode > tree.size() - 1) {
root -> left = NULL;
}
else{
root -> left = createTree(tree, lnode);
}
if (rnode > tree.size() - 1) {
root -> right =NULL;
}
else{
root -> right = createTree(tree, rnode);
}
return root;
}
/*void creatBinaryTree(Node * &root){ //树的创建
int x;
cin >> x;
if (x == -1){
root = nullptr;
return;
}
root = new Node(x);
creatBinaryTree(root->left);
creatBinaryTree(root->right);
}*/
void visit(Node *T){ //树的访问
if (T->val != -1)
cout << T->val << " ";
}
/**递归方式遍历**/
//先序递归遍历
void preOrder(Node * root){
if (root != nullptr){
visit(root);
preOrder(root->left);
preOrder(root->right);
}
}
//中序递归遍历
void inOrder(Node * root){
if (root != nullptr){
inOrder(root->left);
visit(root);
inOrder(root->right);
}
}
//后序递归遍历
void postOrder(Node * root){
if (root != nullptr){
postOrder(root->left);
postOrder(root->right);
visit(root);
}
}
int main(){
vector<int> tree = {10, 5, 15, -1, -1, 6, 20};
Node* root = createTree(tree, 0);
preOrder(root);
cout << endl;
inOrder(root);
cout << endl;
postOrder(root);
}
树的非递归遍历
LeetCode144. 二叉树的前序遍历
思路:栈压入根节点,进行判空循环,设置一个指针p,其元素为栈顶元素,出栈之后,将指针p所指的元素压入容器res中;如果p节点有右孩子,则将右孩子入栈,之后再看p节点是否有左孩子,再将其左孩子入栈,先右后左的顺序是因为栈后进先出的规则;直到栈为空,结束循环。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL) return res;
TreeNode* p = NULL;
s.push(root);
while(!s.empty()){
p = s.top();
s.pop();
res.push_back(p->val);
if(p->right) s.push(p->right);
if(p->left) s.push(p->left);
}
return res;
}
};
LeetCode94. 二叉树的中序遍历
思路:初始化p指针为根节点,设置循环条件为p指针不为空或栈s不为空;如果p指针不为空,则将p节点入栈,p指针变为其左孩子;若p指针为空,则另p指针为栈顶节点并出栈,将p指针所对应的元素压入容器中,p指针变为其右孩子。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL) return res;
TreeNode* p = root;
while(p || !s.empty()){
if(p){
s.push(p);
p = p->left;
}
else{
p = s.top();
s.pop();
res.push_back(p->val);
p = p->right;
}
}
return res;
}
};
LeetCode145. 二叉树的后序遍历
思路:栈压入根节点,进行判空循环,设置一个指针p,其元素为栈顶元素,出栈之后,将指针p所指的元素压入容器res的开头,这样依次插入的元素在容器中是逆序的;如果p节点有左孩子,则将左孩子入栈,之后再看p节点是否有右孩子,再将其右孩子入栈;直到栈为空,结束循环。
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*> s;
vector<int> res;
if(root == NULL) return res;
TreeNode* p = NULL;
s.push(root);
while(!s.empty()){
p = s.top();
s.pop();
res.insert(res.begin(), p->val);
if(p->left) s.push(p->left);
if(p->right) s.push(p->right);
}
return res;
}
};
LeetCode102. 二叉树的层序遍历 && 剑指 Offer 32 - II. 从上到下打印二叉树 II
思路:根节点入队,进行判空循环;队头元素出队,依次判断队头元素左右孩子是否存在,存在则依次入队,我们会设置一个end来标记一层的最后一个节点,作为一层遍历的结束标志,结束后,会将一层的信息压入res容器中并清空临时存放容器。
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
vector<int> tmp;
queue<TreeNode*> q;
TreeNode* end = root; //标记一层的最后一个节点
if (root == NULL) return res;
q.push(root);
while(!q.empty()){
tmp.push_back(q.front()->val);
if(q.front()->left != NULL) q.push(q.front()->left);
if(q.front()->right != NULL) q.push(q.front()->right);
if(q.front() == end){ //一层遍历结束
end = q.back();
res.push_back(tmp);
tmp.clear();
}
q.pop();
}
return res;
}
};