树的括号表示法

news2024/11/19 9:39:46

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1478755.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高效降本|深度案例解读 Koupleless 在南京爱福路的落地实践

文&#xff5c;祁晓波 南京爱福路汽车科技基础设施负责人 主要研究微服务、可观测、稳定性、研发效能、Java 中间件等领域。 本文 4812 字 阅读 12 分钟 Koupleless&#xff08;原 SOFAServerless&#xff09;自 2023 年开源以来已经落地了若干企业&#xff0c;这些企业也见证了…

C++之标准库中string的底层实现方式

目录 1、Eager Copy(深拷贝) 2、COW(Copy-On-Write)写时复制 2.1写时复制的实现 3、SSO&#xff08;Short String Optimization)短字符串优化 4、最佳策略 5、线程安全性 我们都知道&#xff0c; std::string的一些基本功能和用法了&#xff0c;但它底层到底是如何实现的…

基于SSM SpringBoot vue物流配送人员管理系统

基于SSM SpringBoot vue物流配送人员管理系统 系统功能 登录注册 个人中心 员工管理 考勤信息管理 小区信息管理 打卡信息管理 出勤统计管理 派单信息管理 工资结算管理 任务统计管理 开发环境和技术 开发语言&#xff1a;Java 使用框架: SSM(Spring SpringMVC Mybaits)或…

黑马c++ STL部分 笔记(3) deque容器

双端数组&#xff0c;可以对头端进行插入删除操作 deque与vector区别&#xff1a; vector对于头部的插入删除效率低&#xff0c;数据量越大&#xff0c;效率越低&#xff08;每次头插&#xff0c;后面的元素就往后移&#xff09; deque相对而言&#xff0c;对头部的插入删除速…

Java Web(十)--jQuery

介绍 官网文档&#xff1a;jQuery 教程 jQuery API 中文文档 | jQuery API 中文在线手册 | jquery api 下载 | jquery api chm 下载地址&#xff1a;https://jquery.com/download/%20jQuery jQuery 是一个快速的&#xff0c;简洁的 javaScrip工具库&#xff0c;使用户能更方…

尝鲜18倍速大模型Groq和世界第二AI Mistral(Le Chat)

01 尝鲜 中午,一边吃饭,一边尝试一下最新的AI:Groq,它使用了重新设计的LPU,据说比英伟达的GPU快了18倍。 运行了开源的Mixtral-8x7b模型,屏幕上的文字回复几乎是瞬间的,那种速度感,让人心跳加速。 接着,我尝试了来自欧洲的新贵——Mistral AI的Le Chat。 这个三天前…

前端同时传递文件数据+非文件数据,前后端解决方案

之前录制视频《文件上传组件》的时候有位观众提了个问题&#xff0c;如果我没有理解错的话&#xff0c;应该就是前后同时传递文件数据 非文件数据&#xff0c;前后端数据该如何接收&#xff0c;这里我给出我自己的解决方案 tip:下文在编写前端代码的时候&#xff0c;用到了这篇…

基于SpringBoot的民宿租赁管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

生成voc格式数据集

数据集存放格式&#xff1a;&#xff08;Annotations文件夹放标注的xml文件&#xff0c;JPEGImages文件夹放标注的图片&#xff09; 运行代码&#xff1a; import os import random import xml.etree.ElementTree as ETimport numpy as npdef get_classes(classes_path):with …

nacos开启鉴权+springboot配置用户名密码

nacos默认没有开启鉴权&#xff0c;springboot无需用户名密码即可连接nacos。从2.2.2版本开始&#xff0c;默认控制台也无需登录直接可进行操作。 因此本文记录一下如何开启鉴权&#xff0c;基于nacos2.3.0版本。 编辑nacos服务端的application.properties&#xff1a; # 开…

期货开户保证金保障市场正常运转

期货保证金是什么&#xff1f;在期货市场上&#xff0c;采取保证金交易制度&#xff0c;投资者只需按期货合约的价值&#xff0c;交一定比率少量资金即可参与期货合约买卖交易&#xff0c;这种资金就是期货保证金。期货保证金&#xff08;以下简称保证金〕按性质与作用的不同。…

力扣-移除元素

问题 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长…

手机如何使用NFC卡模拟门禁刷卡

部分手机具备NFC卡刷卡功能&#xff0c;理论上也可模拟门禁卡。 一个功能强大且免费的NFC卡模拟器&#xff0c;可模拟各类门禁卡、电梯卡、部分公司&#xff08;工厂&#xff09;工卡或饭卡、部分学校饭卡、部分图书馆借书卡等各类IC卡&#xff0c;用手机替代卡片去刷门禁、刷…

377组合总和 Ⅳ

题目 给你一个由 不同 整数组成的数组 nums &#xff0c;和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。题目数据保证答案符合 32 位整数范围。示例 1&#xff1a;输入&#xff1a;nums [1,2,3], target 4 输出&#xff1a;7 解释&…

DDD设计学习

之前在研究生项目中遇到的问题便是&#xff1a; 随着业务需求的不断改变&#xff0c;需要在原有项目代码中不断进行修改&#xff0c;导致代码不断累积。 那如何构建高质量应用&#xff0c;那就要遵循三大设计原则&#xff1a; 1.单一职责原则&#xff1a;一个类只负责单一的职…

Unity 佳能SDK 及数据获取

1. 填写信息跟官方申请SDK,大概1-2个工作日会邮件回复你 佳能(中国)- 佳定制(佳能影像产品),SDK,EDSDK,CCAPI,软件开发包下载 2. 将SDK这两个文件放到 Unity Plugins文件夹 3. 把CameraControl 下面只要是绿色的 .cs 文件都复制到Unity 中

windows U盘不能识别

windows U盘不能识别 1、问题描述2、问题分析解决3、把U盘插到windows电脑上试试能不能识别 1、问题描述 windwos u盘不能识别 u盘被拿到mac电脑上做了启动盘之后&#xff0c;就不能被windows识别了。题主很奇怪里面被mac电脑的同学放了什么&#xff0c;因此想到把优盘挂载到L…

Cesium-广告牌

创作来源 1、道路标识牌 2、视频广告 创作思路 1、创建有颜色柱体 2、创建长方体并带有纹理 3、将视频问题贴到长方体上 实现步骤 1、创建柱体 /*** 获取柱状几何对象* param radius* param height* return {Geometry}*/ export const getCylinderGeometry (radius, he…

how to deploy parent pom without module deployment

how to deploy parent pom without module deployment deploy -N -f pom.xml

从1-20之间随机抽取5个数,输出抽取出来的5个数之和与剩余未被抽取的15个数之和

从1-20之间随机抽取5个数&#xff0c;输出抽取出来的5个数之和与剩余未被抽取的15个数之和&#xff0c;每个答案独占一行 代码&#xff1a; #include <cstdio> #include <stdlib.h> int main() {int arr[20] { 0 };printf("抽取的5个随机数是&#xff1a;&…