二叉树理论基础
二叉树主要种类:
1.满二叉树:每层都满,有k层,结点为2^k - 1个
2.完全二叉树:除底层外每层都满,底层从左到右是连续的
3.二叉搜索树:左子树的值小于右子树
4.平衡二叉搜索树:二叉搜索树的基础上左右子树高度差小于1
map中的key 和set中的元素都是有序的,因为map和set的底层实现就是平衡二叉搜索树
二叉树存储方式
线性存储:用数组存放元素,下标为i的结点左孩子下标为2*i+1,右孩子为2*i+2
链式存储:每个结点包含一个元素,一个指向左孩子的指针,一个指向右孩子的指针
二叉树遍历方式
(与图论里的两种遍历方式一致)
深度优先搜索:一般用递归(栈)实现,前序、中序、后序遍历都是dfs;也可以使用迭代法
广度优先搜索:层序遍历,使用队列。
二叉树的定义
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x), left(nullptr), right(nullptr) {}
}
144.二叉树的前序遍历
题目内容:给你二叉树的根节点 root
,返回它节点值的 前序 遍历。
(递归法)
递归遍历三部曲:
1.确定函数的参数和返回值
2.确定终止条件
3.确定单层递归的逻辑
我的代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
//递归
vector<int> vec;
if(root != nullptr) {
vec.push_back(root -> val);
}
if(root != nullptr) {
vector<int> lef = preorderTraversal(root -> left);
vec.insert(vec.end(), lef.begin(), lef.end());
vector<int> rig = preorderTraversal(root -> right);
vec.insert(vec.end(), rig.begin(), rig.end());
}
return vec;
}
};
反思:该函数有返回值,返回值是一个容器,所以要建一个容器来承接递归的返回值。
会写前序遍历递归法后,写中序和后序无非就是换下语句顺序罢了。
(迭代法)
迭代法主要使用一个栈,根结点入栈,根结点出栈再读取数值,然后再分别压入右孩子和左孩子(注意压入的顺序,先读取左孩子的值就得让左孩子后入栈);左孩子出栈并读取数值,再把左孩子的右子树和左子树压入栈,以此类推。
我的代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
//迭代
vector<int> vec;
stack<TreeNode*> st;
if(root != nullptr) {
st.push(root);
}
while(!st.empty()) {
TreeNode* cur = st.top();
st.pop();
if(cur != nullptr) {
if(cur -> val >= -100 && cur -> val <= 100) {
vec.push_back(cur -> val);
}
}
if(cur -> right) {
st.push(cur -> right);
}
if(cur -> left) {
st.push(cur -> left);
}
}
return vec;
}
};
94.二叉树的中序遍历
我的代码:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> vec;
if(root != nullptr) {
vector<int> lef = inorderTraversal(root -> left);
vec.insert(vec.end(), lef.begin(), lef.end());
vec.push_back(root -> val);
vector<int> rig = inorderTraversal(root -> right);
vec.insert(vec.end(), rig.begin(), rig.end());
}
return vec;
}
};
145.二叉树的后序遍历
(递归法)
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> vec;
if(root != nullptr) {
vector<int> lres = postorderTraversal(root -> left);
vec.insert(vec.end(), lres.begin(), lres.end());
vector<int> rres = postorderTraversal(root -> right);
vec.insert(vec.end(), rres.begin(), rres.end());
vec.push_back(root -> val);
}
return vec;
}
};
(迭代法)
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<struct TreeNode*> st;
vector<int> vec;
if(root != nullptr) {
st.push(root);
}
while( !st.empty() ) {
TreeNode* new_node = st.top();
st.pop();
if (new_node -> val >= -100 && new_node -> val <= 100){
vec.push_back(new_node -> val);
}
if(new_node -> left != nullptr) {
st.push(new_node -> left);
}
if(new_node ->right != nullptr) {
st.push(new_node -> right);
}
}
reverse(vec.begin(), vec.end());
return vec;
}
};
后序遍历迭代法实际上是前序遍历迭代法交换代码顺序再翻转数组就好了,具体表现为先让数组按“根右左”的顺序存储,再reverse翻转一下变成“左右根”就可以了。