0
点赞
收藏
分享

微信扫一扫

C#面:StringBuilder 和 String 的区别

程序员阿狸 2024-03-01 阅读 12
c++算法

1.括号表示法构造一棵树

下面的代码都使用下面的图测试:
在这里插入图片描述

这颗树的前序遍历是

  • [A,B,D,G,C,E,F,H]

为了程序的完整性,我想先构建一颗上述树,知识匮乏的我只能使用括号表示法构造:

  • “A(B(,D(G,)),C(E,F(H,)))”

1.用一个类表示树的节点

class Node 
{
public:
    int val;
    vector<Node*> children;   //每个Node节点包含一个children数组,数组元素是Node*类型,表示指向其它的节点

    //三个构造函数
    Node() {} 
    Node(int _val) 
    {
        val = _val;
    }
    Node(int _val, vector<Node*> _children) 
    {
        val = _val;
        children = _children;
    }
};

2.使用括号表示法构建树

void CreateTree(Node *&root,string &s)
{
    stack<Node*>tree;
    Node* p = NULL;
    int i =0;
    char ch = s[0];
    while (i < s.length())
    {
        switch (ch)
        {
        case '(':
            tree.push(p);
            break;
        case ')':
            tree.pop();
            break;
        case ',':
            break;
        default:
            p = new Node();
            p->val = ch;

            if (root == NULL)  //没有加入根节点
            {
                root = p;
            }
            else
            {
                tree.top()->children.push_back(p);
            }
        }
        ch = s[++i];
    }
}

我觉得这个代码逻辑非常清晰,我想尝试一下用递归的方式完成上述代码。在此之前,我先介绍一下我现在对于构建二叉树的理解,我感觉这个难度不亚于用非递归写出树的前中后序遍历😋

个人见解:
对于S字符串分析,S=A(B(,D(G,)),C(E,F(H,)))。从头开始遍历,想要通过S字符串构建一颗树。
想要将问题给解决,必须找到字符串内在的联系并且将其具体化。发现,所有的括号都是配对出现的,且’(‘其配对的是最近的’)’。每次当遇到’(‘的时候,可以把新的问题具体成”构建一棵小树“(发现和最开始的问题是一个内在逻辑)。然后小树挂在大树身上
解释一下:
最开始的问题是构建A(B(,D(G,)),C(E,F(H,))) 这棵树。
遍历到B后面的’(‘的时候,问题变成构建B(,D(G,)),C(E,F(H,))这棵树,然后B挂在A身上
遍历到D后面的’(‘的时候,问题变成构建D(G,)这颗树。然后D挂在B身上
发现了实际上就是解决无数个这样的小问题最后解决大问题,而进入小问题的接口就是遇到’('。所以只需要能解决最简单的A(B,C)这个问题,那么后面无限的衍生都是一个道理。
问题即抽象为:
A ( B , C , D , E . . . . ) A(B,C,D,E....) A(B,C,D,E....)
即将每个子树都‘挂’在A后面即可

Node* CreateTree1(int i,int len) //表示创建一颗树(从下标i(根节点)开始,后面跟着长度为len的子树)即用s[i]~s[i+len]构造树
{
    if (s[i] == ',')return NULL;  //树的根应该是一个字母
    Node* p = new Node();
    p->val = s[i];
    if (len == 0)return p;
    //接下来要把该根节点的所有子树都挂在它身上
    //要创建若干颗树

    //子树都是由字符串s构造的
    int start = i + 2;  //子树开始位置
    int length = 0;   //子树(除去根节点)长度(从根节点后面第一个左括号到匹配完所有对应的右括号为止)比如A(B(C,D),E),这里面B(C,D)就是一个子树,子树长度在这里指根节点后面跟着的长度+1,即(C,D)的长度为5,B(C,D)的长度是6
    while (start <= i+len)// 子树的区间[i+2,i+len],s[i+2]是子树的根节点
    {
        if (s[start] < 'A'|| s[start]>'Z') //保证s[start]是个字母(树的根节点)
        {
            start++;
            continue; 
        }
        length = Find_BabyTree(start);  //找子树长度
        p->children.push_back(CreateTree1(start, length));  //子树挂到根节点后面
        start = start + length + 2;  //下一个子树的起点
    }
    return p;
}

我的测试数据A(B(,D(G,)),C(E,F(H,)))
输出是正确的,就是博客开头的树

放完整代码

#include<iostream>
#include<vector>
#include<cstring>
#include<new>
#include<stack>

using namespace std;

class Node
{
public:
    int val;
    vector<Node*> children;   //每个Node节点包含一个children数组,数组元素是Node*类型,表示指向其它的节点

    //三个构造函数
    Node() {}
    Node(int _val)
    {
        val = _val;
    }
    Node(int _val, vector<Node*> _children)
    {
        val = _val;
        children = _children;
    }
};

string s;


void CreateTree(Node*& root, string& s)  //括号表示法构建树,非递归法
{
    stack<Node*>tree;
    Node* p = NULL;
    int i = 0;
    char ch = s[0];
    while (i < s.length())
    {
        switch (ch)
        {
        case '(':
            tree.push(p);
            break;
        case ')':
            tree.pop();
            break;
        case ',':
            break;
        default:
            p = new Node();
            p->val = ch;

            if (root == NULL)  //没有加入根节点
            {
                root = p;
            }
            else
            {
                tree.top()->children.push_back(p);
            }
        }
        ch = s[++i];
    }

}


void preOrdered(Node* root)  //前序遍历,非递归法
{
    if (root == NULL)return;
    cout << char(root->val) << " ";
    for (int i = 0; i < root->children.size(); i++)
        preOrdered(root->children[i]);
    return;
}

int Find_BabyTree(int start)  //数以s[start]为根节点的子树长度
{
    //根据括号规律,一个'('匹配一个')',当'('的次数等于')'的次数时表示当前这颗树构造完了
    //左括号+1,右括号-1
    if (s[start + 1] !='(')return  0;  //该树只有一个根节点,子树长度为0
    int kuohao = 0;
    int i = 1;
    for (i; i + start < s.length(); i++)
    {
        if (s[start+i] == '(')kuohao++;
        if (s[start+i] == ')')kuohao--;
        if (kuohao == 0)break;
    }
    return i;
}

Node* CreateTree1(int i,int len) //表示创建一颗树(从下标i(根节点)开始,后面跟着长度为len的子树)即用s[i]~s[i+len]构造树
{
    if (s[i] == ',')return NULL;  //树的根应该是一个字母个
    Node* p = new Node();
    p->val = s[i];
    if (len == 0)return p;
    //接下来要把该根节点的所有子树都挂在它身上
    //要创建若干颗树

    //子树都是由字符串s构造的
    int start = i + 2;  //子树开始位置
    int length = 0;   //子树长度(从根节点后面第一个左括号到匹配完所有对应的右括号为止)比如A(B(C,D),E),这里面B(C,D)就是一个子树,子树长度在这里指根节点后面跟着的长度,即(B,C)的长度为5
    while (start <= i+len)// 子树的区间[i+2,i+len],s[i+2]是子树的根节点
    {
        if (s[start] < 'A'|| s[start]>'Z') //保证s[start]是个字母(树的根节点)
        {
            start++;
            continue; 
        }
        length = Find_BabyTree(start);  //找子树长度
        p->children.push_back(CreateTree1(start, length));  //子树挂到根节点后面
        start = start + length + 2;  //下一个子树的起点
    }
    return p;
}

int main()
{
    Node* root = NULL;  //根节点
    s = "A(B(,D(G,)),C(E,F(H,)))";  //使用括号表示法构建树
    //CreateTree(root, s);  //建树
    root = CreateTree1(0,s.length()-1);
    //然后用前序遍历输出树看是否正确

    preOrdered(root);  //前序遍历

    return 0;
}

强迫症使然,找到思考大致的题目:leetcode
在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution 
{
public:
    TreeNode* CreateTree(string s)  //表示当前根节点是s[i],当前的树的长度是len(包括i)
    {
        if(!s.size())
            return NULL;
        TreeNode*root=new TreeNode();
        int flag=1;
        int i=0;
        if(s[i]=='-')  //特殊判断负数
        {
            flag=-flag;
            i++;
        }
        //要将截至到最近的'('的所有字符提取出来转换为数字(有可能不是一个字符)
        int st=i;
        int n=s.size();
        while(i<n&&s[i]!='(')
            i++;
        root->val=flag*stoi(s.substr(st,i));

        if(i==n)return root; //只有数字没有括号的情况,可以提前退出

        //处理子树
        int kuohao=1;   //此时i指向左括号,左括号数量加1
        int ls=i+1;
        i++;
        for(;i<n&&kuohao!=0;i++)
        {
            if(s[i]=='(')
                kuohao++;
            if(s[i]==')')
                kuohao--;
        }
        //此时k指向左子树结束的后一个字符
        root->left=str2tree(s.substr(ls,i-ls-1));
        //看是否有右子树
        if(i<n)
        {
            root->right=str2tree(s.substr(i+1,n-i-2));  //有点难算,先画个图
        }
        return root;


    }
    TreeNode* str2tree(string s) 
    {
        //分解问题,找到规律:
        //遇到字符则新建节点(当成一颗新树)
        //将当前字符为根节点的左右子树挂到根节点后面(左右子树)

        TreeNode *root=NULL;
        root=CreateTree(s);
        return root;
    }
};
举报

相关推荐

0 条评论