二叉树学习记录贴;
一、二叉树学习路线
基本上就是要搞清楚不同二叉树的概念,以及与一般数据结构的对比。学会二叉树的基本操作以及常见的面试常考题,如判断是否为平衡二叉树等。
二、基本概念
二叉树是一种 树形数据结构,它的每个结点最多有 两个子结点,分别称为 左子结点 和 右子结点。
对于上图的树状结构需要知道几个基本概念:
(1)每个节点下方直接相连的节点称为子节点,上方直接相连的节点称为父节点。比方说节点 3
的父节点是 1
,左子节点是 5
,右子节点是 6
;节点 5
的父节点是 3
,左子节点是 7
,没有右子节点。
(2)以子节点为根的树称为子树。比方说节点 3
的左子树是节点 5
和 7
组成的树,右子树是节点 6
和 8
组成的树。
(3)最上方那个没有父节点的节点 1
为根节点,称最下层没有子节点的节点 4
、7
、8
为叶子节点。
(4)称从根节点到最下方叶子节点经过的节点个数为二叉树的最大深度/高度,上面这棵树的最大深度是 4
,即从根节点 1
到叶子节点 7
或 8
的路径上的节点个数。
三、不同的树结构
(1)满二叉树
满二叉树就是每一层节点都是满的,整棵树像一个正三角形。设满二叉树的深度为n,则满二叉树的节点个数 = 2^n- 1; 满二叉树是一种特殊的完全二叉树。
(2)完全二叉树
完全二叉树是指,二叉树的每一层的节点都紧凑靠左排列,且除了最后一层,其他每层都必须是满的。完全二叉树的左右子树也是完全二叉树。
(3)二叉搜索树
对于树中的每个节点,其左子树的每个节点的值都要小于这个节点的值,右子树的每个节点的值都要大于这个节点的值。
对根节点,其值为7,那么它的左子树的下的每个节点的值都必然小于7,右子树下的每个节点的值都必然大于7。
(4)高度平衡二叉树
高度平衡二叉树是一种特殊的二叉树,它的「每个节点」的左右子树的高度差不超过 1。
要注意是每个节点,而不仅仅是根节点。
比如下面这棵二叉树,根节点 1
的左子树高度是 2,右子树高度是 3;节点 2
的左子树高度是 1,右子树高度是 0;节点 3
的左子树高度是 2,右子树高度是 1,以此类推,每个节点的左右子树高度差都不超过 1,所以这是一棵高度平衡的二叉树:
下面这棵树就不是高度平衡的二叉树,因为节点 2
的左子树高度是 2,右子树高度是 0,高度差超过 1,不符合条件:
(5)红黑树
红黑树是一种 自平衡二叉搜索树(BST),通过在每个节点增加一个表示颜色的位(红/黑),来保证树的平衡性。它的查找、插入、删除操作的 时间复杂度都为 O(log n)。
红黑树的性质:
-
每个节点要么是红色,要么是黑色。
-
根节点是黑色。
-
所有叶子节点(NIL 空节点)是黑色。
-
红色节点的子节点必须是黑色(不能有两个相邻的红节点)。
-
任意节点到其所有叶子节点的路径上,黑色节点数相同。
四、基本操作
(1)树的结构
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x): val(x),left(NULL),right(NULL){}
};
(2)二叉树的创建
TreeNode* buildTree(const vector<int>& arr) {
if (arr.empty()) return nullptr;
vector<TreeNode*> nodes(arr.size(), nullptr);
for (int i = 0; i < arr.size(); i++) {
if (arr[i] != -1) { // 用 -1 表示空节点
nodes[i] = new TreeNode(arr[i]);
}
}
for (int i = 0; i < arr.size(); i++) {
if (nodes[i]) {
int leftIndex = 2 * i + 1;
int rightIndex = 2 * i + 2;
if (leftIndex < arr.size()) nodes[i]->left = nodes[leftIndex];
if (rightIndex < arr.size()) nodes[i]->right = nodes[rightIndex];
}
}
return nodes[0]; // 返回根节点
}
(3)前序遍历
vector<int>preorderTarversal(TreeNode* root)
{
vector<int> res;
if(!root) return res;
stack<TreeNode*> st;
st.push(root);
while(!st.empty())
{
ListNode*node = st.top();
st.pop();
res.push_back(node->val);
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
}
return res;
}
(4)中序遍历
vector<int> inorderTraversal(TreeNode* root)
{
vector<int> res;
if(!root) return res;
stack<TreeNode*> st;
TreeNode* curr = root;
while(curr || !st.empty())
{
while(curr)
{
st.push(curr);
curr = curr->left;
}
curr = st.top();
st.pop();
res.push_back(curr->val);
curr = curr->right;
}
return res;
}
(5)后序遍历
vector<int> postorderTravesal(TreeNode* root)
{
vector<int> res;
if(!root) return res;
stack<TreeNode*> st;
st.push(root);
while(!st.empty())
{
TreeNode*node = st.top();
st.pop();
res.push_back(node->val);
if(root->left) st.push(root->left);//后序遍历先左后右
if(root->right) st.push(root->right);
}
reverse(res.begin(),res.end());
return res;
}
五、进阶操作
(1)求树的最大深度
int maxDepth(TreeNode* root)
{
if(!root) return 0;
return 1 + max(max(root->left),max(root->right));
}
(2)合并二叉树
TreeNode* mergeTree(TreeNode* t1,TreeNode* t2)
{
if(!t1) return t2;
if(!t2) return t1;
t1->val += t2->val;
t1->left = mergeTree(t1->left,t2->left);
t1->right = mergeTree(t1->right,t2->right);
return t1;
}
(3)判断是否为平衡二叉树
int check(TreeNode* root)
{
if(!root) return 0;
int left = check(root->left);
if(left == -1) return -1;
int right = check(root->right);
if(right == -1) return -1;
if(abs(left - right)> 1) return -1;
return 1+ max(left,right);
}
bool isBalanced(TreeNode* root)
{
return check(root) != -1;
}
未完待续。。。。。