理论基础
二叉树的种类
满二叉树
完全二叉树
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^(h-1) 个节点。
二叉搜索树:是一个有序树
若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
它的左、右子树也分别为二叉排序树
平衡二叉搜索树
又被称为AVL(Adelson-Velsky and Landis)树,且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
C++中map、set、multimap、multiset的底层实现都是平衡二叉搜索树;
而unordered_map、unordered_set,unordered_map、unordered_map底层实现是哈希表。
存储方式
二叉树分为链式存储(指针)和顺序存储(数组)
链式存储(指针)
顺序存储(数组)
用数组来存储二叉树如何遍历的呢?
如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。
但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。
二叉树的遍历方式
深度优先遍历:先往深走,遇到叶子节点再往回走。
广度优先遍历:一层一层的去遍历。
二叉树的定义
顺序存储就是用数组存储,
链式存储二叉树节点的定义方式
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
二叉树的递归遍历
前序遍历:
确定递归函数的参数和返回值:
要打印出前序遍历节点的数值,所以参数里需要传入vector来存放节点的数值,不需要返回值,因此递归函数的返回类型为void;
void traversal(TreeNode* cur, vector<int>& vec)
确定终止条件:
当遍历的节点为空时,那么本层递归结束,所以如果当前遍历的节点为空,就直接return。
if (cur == NULL) return;
确定单层递归的逻辑:
前序遍历:就是中左右,先取中节点的数值,然后左节点和右节点
vec.push_back(cur->val); // 中
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
前序遍历完整代码:
class Solution {
public:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
vec.push_back(cur->val); // 中
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
};
中序遍历:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
vec.push_back(cur->val); // 中
traversal(cur->right, vec); // 右
}
后序遍历:
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
vec.push_back(cur->val); // 中
}
二叉树的迭代遍历
把二叉树的元素放入数组,使用栈数据结构,
前序遍历:中左右
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == nullptr) return result;
st.push(root);
while(!st.empty()) {
TreeNode* node = st.top(); //中
st.pop();
result.push_back(node->val);
if (node->right) st.push(node->right);//右
if (node->left) st.push(node->left);//左
}
return result;
}
};
中序遍历:左中右
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == nullptr) return result;
st.push(root);
while(!st.empty()) {
TreeNode* node = st.top(); //中
st.pop();
result.push_back(node->val);
if (node->left) st.push(node->left);//左
if (node->right) st.push(node->right);//右
}
return result;
}
};
后序遍历:左右中
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
stack<TreeNode*> st;
if (root == nullptr) return result;
st.push(root);
while (!st.empty()) {
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if (node->left) st.push(node->left);
if (node->right) st.push(node->right);
}
reverse(result.begin(), result.end());
return result;
}
};