【编程练习】二叉树相关算法(二)

二叉树的第一部分算法如下
https://blog.csdn.net/weixin_44611644/article/details/95897436

下面是第二部分的二叉树题目
(1)知道前序和中序之后,重建二叉树
前序遍历的特点是第一个值为根节点,中序遍历的值是根节点在中间,利用此规律对数组进行分割归并。

TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        int n = pre.size();
        if(n!=vin.size()||n==0)
            return nullptr;
         
        TreeNode* root = new TreeNode(pre[0]);
        vector<int> newPre;
        vector<int> newVin;
        for(int i = 0;i<vin.size();i++)
        {
            if(vin[i] == pre[0])
            {
                newPre.assign(pre.begin()+1,pre.begin()+i+1);
                newVin.assign(vin.begin(),vin.begin()+i);
                root->left = reConstructBinaryTree(newPre,newVin);
                
                newPre.assign(pre.begin()+i+1,pre.end());
                newVin.assign(vin.begin()+i+1,vin.end());
                root->right = reConstructBinaryTree(newPre,newVin);
                break;
            }
        }
        return root;
}

(2)二叉搜索树展开为双向链表
和二叉树展开为链表相似,递归算法。

TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree == nullptr) return nullptr;
        TreeNode* pre = nullptr;
        convertHelper(pRootOfTree, pre);
        TreeNode* res = pRootOfTree;
        while(res ->left)
            res = res ->left;
        return res;
    }
     
    void convertHelper(TreeNode* cur, TreeNode*& pre)
    {
        if(cur == nullptr) return;    
        convertHelper(cur ->left, pre);   
        cur ->left = pre;
        if(pre) pre ->right = cur;
        pre = cur;
        convertHelper(cur ->right, pre);
}

(3)左右视图树

以左视图树讲解,代表从最左面能看到的结点,可以这样做,先遍历一次,map存放结点和层数,然后进行逆序更新,就是从右忘左更新,比如第三层有2个结点 左面的结点是x1,右面的结点是x2,map中的键值对应关系是去重复的,先加载了x2 map[3]=x2;这里含义就是第三层能看到x2,逆序的最后把map[3]的值更新成了x1,这样就实现了map中保存的是各个层中 最左面的那个数。

void reUpdate(vector<float> &result) {
    map<int, float> mp;
    // 逆序更新
    for(int i = result.size() - 1; i >0; i -= 2) {
        auto pos = mp.find((int)result[i - 1]);
        // 如果已经存在则更新,若不存在则添加
        if(pos != mp.end()) {
            pos->second = result[i]; // 更新
        } else {
            mp.insert(make_pair((int)result[i - 1], result[i]));
        }
    }
    // 清空原result
    vector<float>().swap(result);
    // 将mp的结果放入result,并输出结果
    for(auto pair : mp) {
        result.push_back(pair.second);
    }
}
void preLeftView(Node & node, vector<float> &result, const int deep = 0) {
    result.push_back(deep);
    result.push_back(node.data);
    if(node.leftChiled != nullptr) {
        preLeftView(*(node.leftChiled), result, deep + 1);
    }
    if(node.rightChiled != nullptr) {
        preLeftView(*(node.rightChiled), result, deep + 1);
    }
}

// 左视图生成函数
void leftView(Node & node) {
    vector<float> result;
    preLeftView(node, result);
    // 逆序更新result
    reUpdate(result);
    for(auto x : result) {
        cout << x << " ";
    }
    
}

(4)判断是不是二叉搜索树后序遍历的结果
特点是 左节点比自己小,右结点比自己大。后序遍历的话根节点在最后,对数组进行遍历,先升后降,如果最后到达数组末尾则这个结点符合规律,依次判断全部结点。
这时候如果比较难理解的话不妨自己画一棵树模拟一下。

bool VerifySquenceOfBST(vector<int> sequence) {
        int size = sequence.size();
        if(0==size)return false;
 
        int i = 0;
        while(--size)
        {
            while(sequence[i++]<sequence[size]);
            while(sequence[i++]>sequence[size]);
 
            if(i<size)return false;
            i=0;
        }
        return true;
}

(5)二叉树中和为某一值的路径
和为某一值的路径可能不止一条,用二维数组保存所有结果。

class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) 
    {
        if (!root) return res;

        cur.push_back(root->val);
        if (root->val == expectNumber && !root->left && !root->right)
            res.push_back(cur);

        FindPath(root->left, expectNumber - root->val);
        FindPath(root->right, expectNumber - root->val);
 
        if (!cur.empty())
            cur.pop_back();
        return res;
    }

private:
    vector<int> cur;
    vector<vector<int>> res;
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值