数据结构之二叉树的相关知识

二叉树学习记录贴;

一、二叉树学习路线

基本上就是要搞清楚不同二叉树的概念,以及与一般数据结构的对比。学会二叉树的基本操作以及常见的面试常考题,如判断是否为平衡二叉树等。

二、基本概念

        二叉树是一种 树形数据结构,它的每个结点最多有 两个子结点,分别称为 左子结点右子结点

对于上图的树状结构需要知道几个基本概念:

(1)每个节点下方直接相连的节点称为子节点,上方直接相连的节点称为父节点。比方说节点 3 的父节点是 1,左子节点是 5,右子节点是 6;节点 5 的父节点是 3,左子节点是 7,没有右子节点。

(2)以子节点为根的树称为子树。比方说节点 3 的左子树是节点 5 和 7 组成的树,右子树是节点 6 和 8 组成的树。

(3)最上方那个没有父节点的节点 1 为根节点,称最下层没有子节点的节点 478 为叶子节点

(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;
}

未完待续。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值