当前位置: 首页 > news >正文

C++ 设计模式——解释器模式

目录

    • C++ 设计模式——解释器模式
      • 1. 主要组成成分
      • 2. 逐步构建解释器模式
        • 步骤1: 定义抽象表达式
        • 步骤2: 实现终结符表达式
        • 步骤3: 实现非终结符表达式
        • 步骤4: 构建语法树
        • 步骤5: 实现内存管理
        • 步骤6: 创建上下文和客户端
      • 3. 解释器模式 UML 图
        • UML 图解析
      • 4. 解释器模式的优点
      • 5. 解释器模式的缺点
      • 6. 解释器模式适用场景
      • 总结
      • 完整代码

C++ 设计模式——解释器模式

解释器模式是一种特定于语言的模式,用于定义如何评估语言的句法或表达式。它适用于某些重复出现的问题,可以将一个需要解释执行的语言中的句子表示为一个抽象的语法树。这种模式通常被用于开发编程语言解释器或简单的脚本引擎。

引人“解释器”设计模式的定义(实现意图):定义一个语言的文法(语法规则),并建立一个解释器解释该语言中的句子。

1. 主要组成成分

  1. 抽象表达式(Abstract Expression):定义了解释操作的接口。这个接口通常包含一个解释(Interpret)方法,该方法接受一个上下文作为参数。
  2. 终结符表达式(Terminal Expression):实现了抽象表达式接口。这些表达式代表了语言中的终结符,如数字或变量。
  3. 非终结符表达式(Nonterminal Expression):也实现了抽象表达式接口。这些表达式代表了语言中的非终结符,通常包含其他表达式。
  4. 上下文(Context):包含解释器之外的一些全局信息。这可能包括变量的值、当前状态等。
  5. 客户端(Client):构建抽象语法树并调用解释操作。客户端通常会创建或被给予一个表示特定句子的抽象语法树,然后调用解释方法。

2. 逐步构建解释器模式

这个逐步构建的过程展示了解释器模式的核心组件如何协同工作,从定义基本的表达式接口,到实现具体的表达式类,再到构建和解释复杂的表达式树。这种方法使得添加新的表达式类型变得简单,同时保持了整体结构的灵活性和可扩展性。

步骤1: 定义抽象表达式

首先定义一个抽象基类 Expression,它是所有表达式的基础,所有的具体表达式类都必须实现这个函数,以便执行具体的解释任务。

//小表达式(节点)父类
class Expression
{
public:Expression(int num, char sign) :m_dbg_num(num), m_dbg_sign(sign) {} //构造函数virtual ~Expression() {} //做父类时析构函数应该为虚函数public://解析语法树中的当前节点virtual int interpret(map<char, int> var) = 0; //#include <map>,map容器中的键值对用于保存变量名及对应的值public://以下两个成员变量是为程序跟踪调试时观察某些数据方便而引入int m_dbg_num;   //创建该对象时的一个编号,用于记录本对象是第几个创建的char m_dbg_sign; //标记本对象的类型,可能是个字符v代表变量(终结符表达式),也可能是个加减号(非终结符表达式)
};
步骤2: 实现终结符表达式

接着,创建一个或多个终结符表达式类,例如 VarExpression,它们直接与语言的终结符相对应。这些类实现了抽象表达式中定义的 interpret() 方法,返回变量在上下文中的值。

//变量表达式(终结符表达式)
class VarExpression :public Expression
{
public:VarExpression(const char& key, int num, char sign) :Expression(num, sign) //构造函数{m_key = key;}virtual int interpret(map<char, int> var){return var[m_key];  //返回变量名对应的数值}private:char m_key; //变量名,本范例中诸如a、b、c、d都是变量名
};
步骤3: 实现非终结符表达式

创建运算符表达式基类 SymbolExpression 和非终结符表达式类如 AddExpressionSubExpression 代表语言的规则。这些类通常会持有其他 Expression 对象,并在其 interpret() 方法中递归调用这些对象的 interpret() 方法,合并其结果。

//运算符表达式(非终结符表达式)父类
class SymbolExpression :public Expression
{
public:SymbolExpression(Expression* left, Expression* right, int num, char sign) :m_left(left), m_right(right), Expression(num, sign) {} //构造函数Expression* getLeft() { return m_left; }Expression* getRight() { return m_right; }
protected://左右各有一个操作数Expression* m_left;Expression* m_right;
};//加法运算符表达式(非终结符表达式)
class AddExpression :public SymbolExpression
{
public:AddExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数virtual int interpret(map<char, int> var){//分步骤拆开写,方便理解和观察int value1 = m_left->interpret(var); //递归调用左操作数的interpret方法int value2 = m_right->interpret(var); //递归调用右操作数的interpret方法int result = value1 + value2;return result; //返回两个变量相加的结果}
};//减法运算符表达式(非终结符表达式)
class SubExpression :public SymbolExpression
{
public:SubExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数virtual int interpret(map<char, int> var){int value1 = m_left->interpret(var);int value2 = m_right->interpret(var);int result = value1 - value2;return result; //返回两个变量相减的结果}
};
步骤4: 构建语法树

创建一个函数来分析表达式字符串并构建语法树:

//分析—创建语法树(表达式树)
Expression* analyse(string strExp) //strExp:要计算结果的表达式字符串,比如"a-b+c+d"
{stack<Expression*>  expStack;//#include <stack>,这里用到了栈这种顺序容器Expression* left = nullptr;Expression* right = nullptr;int icount = 1;for (size_t i = 0; i < strExp.size(); ++i)//循环遍历表达式字符串中的每个字符{switch (strExp[i]){case '+'://加法运算符表达式(非终结符表达式)left = expStack.top(); //返回栈顶元素(左操作数)++i;right = new VarExpression(strExp[i], icount++, 'v'); //v代表是个变量节点//在栈顶增加元素expStack.push(new AddExpression(left, right, icount++, '+')); //'+'代表是个减法运算符节点break;case '-'://减法运算符表达式(非终结符表达式)left = expStack.top(); //返回栈顶元素++i;right = new VarExpression(strExp[i], icount++, 'v');expStack.push(new SubExpression(left, right, icount++, '-')); //'-'代表是个减法运算符节点break;default://变量表达式(终结符表达式)expStack.push(new VarExpression(strExp[i], icount++, 'v'));break;} //end switch} //end forExpression* expression = expStack.top(); //返回栈顶元素return expression;
}
步骤5: 实现内存管理

添加一个函数来释放表达式树的内存:

void release(Expression* expression)
{//释放表达式树的节点内存SymbolExpression* pSE = dynamic_cast<SymbolExpression*>(expression); //此处代码有优化空间(不使用dynamic_cast),留给读者思考if (pSE){release(pSE->getLeft());release(pSE->getRight());}delete expression;
}
步骤6: 创建上下文和客户端

main 函数中创建上下文(变量映射)并使用解释器:

int main()
{string strExp = "a-b+c+d";	 //将要求值的字符串表达式map<char, int> varmap;//下面是给字符串表达式中所有参与运算的变量一个对应的数值varmap.insert(make_pair('a', 7)); //类似于赋值语句a = 7varmap.insert(make_pair('b', 9)); //类似于赋值语句b = 9varmap.insert(make_pair('c', 3)); //类似于赋值语句c = 3varmap.insert(make_pair('d', 2)); //类似于赋值语句d = 2Expression* expression = analyse(strExp);  //调用analyse函数创建语法树int result = expression->interpret(varmap); //调用interpret接口求解字符串表达式的结果cout << "字符串表达式\"a - b + c + d\"的计算结果为:" << result << endl; //输出字符串表达式结果//释放内存release(expression);return 0;
}

3. 解释器模式 UML 图

解释器模式 UML 图

UML 图解析

解释器模式的 UML 图中包含如下 4 种角色:

  1. AbstractExpression (抽象表达式):声明了一个抽象的解释操作,它是所有终结符表达式和非终结符表达式的公共基类。这里指Expression类。

  2. TerminalExpression (终结符表达式):抽象表达式的子类,实现了语言文法中与终结符表达式相关的解释操作。一个句子中的每个终结符表达式都是该类的一个实例,这些实例可以通过非终结符表达式组成更为复杂的句子。这里指VarExpression类。

  3. NonterminalExpression (非终结符表达式):同样是抽象表达式的子类,实现了语言文法中与非终结符表达式相关的解释操作。考虑到非终结符表达式既可以包含终结符表达式,也可以包含其他非终结符表达式,所以其相关的解释操作一般是通过递归调用实现的。这里指AddExpressionSubExpression

    注意,引入SymbolExpression类的目的是方便AddExpressionSubExpression作为其子类的编写(方便继承),SymbolExpression类本身并不是非终结符表达式,也并不是必须存在的。

  4. Context (环境类/上下文类):用于存储解释器之外的一些全局信息,例如变量名与值的映射关系、存储和访问表达式解释器的状态等。之后这个信息会作为参数传递到所有表达式的解释操作(interpret成员函数)中作为这些解释操作的公共对象来使用。可以根据实际情况决定是否需要使用该类。这里指varmap这个map容器(虽然上述范例并没有将该容器封装到一个类中)。

4. 解释器模式的优点

  1. 易于改变和扩展文法:每个文法规则都对应一个类,可以方便地改变或扩展文法。
  2. 实现文法较为容易:每条文法规则都可以表示为一个类,因此可以直接将规则表示为代码。
  3. 增加新的解释表达式较为方便:如果需要增加新的解释表达式,只需要添加一个新的类即可。

5. 解释器模式的缺点

  1. 对于复杂文法难以维护:当文法规则数目太多时,管理这些类会变得非常困难。
  2. 执行效率较低:解释器模式使用了大量的循环和递归调用,对于复杂的句子可能会导致效率问题。
  3. 可能会引起类膨胀:每个文法规则都需要一个单独的类,可能会导致系统中类的数量急剧增加。

6. 解释器模式适用场景

  1. 简单语法的语言:解释器模式非常适合用于实现一些简单的、可组合的语法规则。例如,计算器程序需要解析和计算数学表达式,可以使用解释器模式来实现。
  2. 领域特定语言(DSL):在某些领域,可能需要定义一个小型的语言来描述特定的任务或行为。例如,SQL查询、正则表达式、配置文件解析等,都可以使用解释器模式来实现相应的解析和执行。
  3. 文本处理:解释器模式可以用于文本处理和编译,例如编译器或解释器中的词法分析和语法分析。它可以将输入的文本转换为抽象语法树,并基于这个树结构执行相应的操作。
  4. 命令解释: 一些应用程序可能需要解析和执行命令行输入或脚本语言。解释器模式可以用来定义这些命令的语法,并提供相应的解释和执行机制。
  5. 规则引擎:在某些业务系统中,可能需要根据一系列规则来执行不同的操作。解释器模式可以用来定义这些规则的语法,并在运行时解析和执行这些规则。
  6. 编程语言的实现:实现一种新的编程语言或脚本语言时,解释器模式可以用于解析和执行语言的语法。许多简单的脚本语言和教学语言都使用解释器模式来实现。

总结

解释器模式提供了一种灵活的方式来解释特定语言的句子。它将每个文法规则封装到单独的类中,使得语言的解释变得模块化和可扩展。然而,这种模式在处理复杂语言时可能会导致类的数量激增,并且可能存在性能问题。因此,解释器模式最适合用于简单语言的解释,或者在需要频繁修改语法规则的场景中。在实际应用中,需要权衡其优点和缺点,并根据具体需求决定是否使用此模式。

完整代码

#include <iostream>
#include <cstring>
#include <map>
#include <stack>
#include <vector>using namespace std;//小表达式(节点)父类
class Expression
{
public:Expression(int num, char sign) :m_dbg_num(num), m_dbg_sign(sign) {} //构造函数virtual ~Expression() {} //做父类时析构函数应该为虚函数public://解析语法树中的当前节点virtual int interpret(map<char, int> var) = 0; //#include <map>,map容器中的键值对用于保存变量名及对应的值public://以下两个成员变量是为程序跟踪调试时观察某些数据方便而引入int m_dbg_num;   //创建该对象时的一个编号,用于记录本对象是第几个创建的char m_dbg_sign; //标记本对象的类型,可能是个字符v代表变量(终结符表达式),也可能是个加减号(非终结符表达式)
};//-----
//变量表达式(终结符表达式)
class VarExpression :public Expression
{
public:VarExpression(const char& key, int num, char sign) :Expression(num, sign) //构造函数{m_key = key;}virtual int interpret(map<char, int> var){return var[m_key];  //返回变量名对应的数值}private:char m_key; //变量名,本范例中诸如a、b、c、d都是变量名
};//------
//运算符表达式(非终结符表达式)父类
class SymbolExpression :public Expression
{
public:SymbolExpression(Expression* left, Expression* right, int num, char sign) :m_left(left), m_right(right), Expression(num, sign) {} //构造函数Expression* getLeft() { return m_left; }Expression* getRight() { return m_right; }
protected://左右各有一个操作数Expression* m_left;Expression* m_right;
};//加法运算符表达式(非终结符表达式)
class AddExpression :public SymbolExpression
{
public:AddExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数virtual int interpret(map<char, int> var){//分步骤拆开写,方便理解和观察int value1 = m_left->interpret(var); //递归调用左操作数的interpret方法int value2 = m_right->interpret(var); //递归调用右操作数的interpret方法int result = value1 + value2;return result; //返回两个变量相加的结果}
};//减法运算符表达式(非终结符表达式)
class SubExpression :public SymbolExpression
{
public:SubExpression(Expression* left, Expression* right, int num, char sign) :SymbolExpression(left, right, num, sign) {}//构造函数virtual int interpret(map<char, int> var){int value1 = m_left->interpret(var);int value2 = m_right->interpret(var);int result = value1 - value2;return result; //返回两个变量相减的结果}
};//分析—创建语法树(表达式树)
Expression* analyse(string strExp) //strExp:要计算结果的表达式字符串,比如"a-b+c+d"
{stack<Expression*>  expStack;//#include <stack>,这里用到了栈这种顺序容器Expression* left = nullptr;Expression* right = nullptr;int icount = 1;for (size_t i = 0; i < strExp.size(); ++i)//循环遍历表达式字符串中的每个字符{switch (strExp[i]){case '+'://加法运算符表达式(非终结符表达式)left = expStack.top(); //返回栈顶元素(左操作数)++i;right = new VarExpression(strExp[i], icount++, 'v'); //v代表是个变量节点//在栈顶增加元素expStack.push(new AddExpression(left, right, icount++, '+')); //'+'代表是个减法运算符节点break;case '-'://减法运算符表达式(非终结符表达式)left = expStack.top(); //返回栈顶元素++i;right = new VarExpression(strExp[i], icount++, 'v');expStack.push(new SubExpression(left, right, icount++, '-')); //'-'代表是个减法运算符节点break;default://变量表达式(终结符表达式)expStack.push(new VarExpression(strExp[i], icount++, 'v'));break;} //end switch} //end forExpression* expression = expStack.top(); //返回栈顶元素return expression;
}void release(Expression* expression)
{//释放表达式树的节点内存SymbolExpression* pSE = dynamic_cast<SymbolExpression*>(expression); //此处代码有优化空间(不使用dynamic_cast),留给读者思考if (pSE){release(pSE->getLeft());release(pSE->getRight());}delete expression;
}int main()
{string strExp = "a-b+c+d";	 //将要求值的字符串表达式map<char, int> varmap;//下面是给字符串表达式中所有参与运算的变量一个对应的数值varmap.insert(make_pair('a', 7)); //类似于赋值语句a = 7varmap.insert(make_pair('b', 9)); //类似于赋值语句b = 9varmap.insert(make_pair('c', 3)); //类似于赋值语句c = 3varmap.insert(make_pair('d', 2)); //类似于赋值语句d = 2Expression* expression = analyse(strExp);  //调用analyse函数创建语法树int result = expression->interpret(varmap); //调用interpret接口求解字符串表达式的结果cout << "字符串表达式\"a - b + c + d\"的计算结果为:" << result << endl; //输出字符串表达式结果//释放内存release(expression);return 0;
}

相关文章:

C++ 设计模式——解释器模式

目录 C 设计模式——解释器模式1. 主要组成成分2. 逐步构建解释器模式步骤1: 定义抽象表达式步骤2: 实现终结符表达式步骤3: 实现非终结符表达式步骤4: 构建语法树步骤5: 实现内存管理步骤6: 创建上下文和客户端 3. 解释器模式 UML 图UML 图解析 4. 解释器模式的优点5. 解释器模…...

【开源大模型生态6】生态大咖与产品布局

上图是基础设施、大模型、行业应用构成大模型开源生态体系。 这里一一给大家介绍以下。 金融 Qwen&#xff1a;阿里云推出的一种大型语言模型&#xff0c;具有强大的对话能力和多模态理解能力。天工&#xff1a;通常指的是阿里云的一套物联网&#xff08;IoT&#xff09;解决…...

虚拟机苹果系统的QT安装体验

前言 苹果系统MacOS中除了安装XCode&#xff0c;完全可以安装QT。本质上来讲&#xff0c;苹果系统就是Linux改装版本&#xff0c;实际上和Ubuntu非常的接近。 1、Mac对应的QT安装包的下载 安装参考链接&#xff1a;MacOS下Qt 5开发环境安装与配置_macos qt-CSDN博客 苹果系统…...

多路转接之poll(接口介绍,struct pollfd介绍,实现原理,实现非阻塞网络通信代码)

目录 poll 引入 介绍 函数原型 fds struct pollfd 特点 nfds timeout 取值 返回值 原理 如何实现关注多个fd? 如何确定哪个fd上有事件就绪? 如何区分事件类型? 判断某事件是否就绪的方法 代码 示例 总结 为什么说它解决了fd上限问题? 缺点 poll 引入…...

两个月冲刺软考——位示图题型的例题讲解与分析;索引文件的详细解读

1. 位示图 位示图&#xff08;Bitmap&#xff09;是一种数据结构&#xff0c;用于表示和存储图像信息。在计算机科学中&#xff0c;位示图通常指的是一个二维的数组&#xff0c;每个元素称为一个像素&#xff0c;每个像素可以存储一个颜色值。 可以将位示图类比为电影院选座操作…...

SprinBoot+Vue校园数字化图书馆系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平台Java领域优质…...

python如何加速计算密集型任务?

问题描述&#xff1a; 在python中&#xff0c;有一个函数&#xff0c;其功能是进行某种计算&#xff0c;需要传入一些参数&#xff0c;计算完成后传回结果&#xff0c;调用其一次大概要1s的时间&#xff0c;现在需要通过for循环调用其350次&#xff0c;保存每次调用结果&#…...

握手的方式展现人的性格及行为倾向

握手是人际交往中最常见的礼节之一&#xff0c;同时通过和对方握手&#xff0c;可以感知他的内心&#xff0c;进一步得知对方的性格及行为倾向。 心理学家认为&#xff0c;最好的握手方式是力度适中&#xff0c;动作沉稳&#xff0c;自然注视对方的眼睛&#xff0c;这种握手方…...

Java 排序算法详解

排序是计算机科学中的基本操作&#xff0c;Java 提供了多种排序算法来满足不同的需求。常见的排序算法包括冒泡排序、选择排序、插入排序、归并排序、快速排序和堆排序。本文将逐一介绍这些排序算法及其 Java 实现。 1. 冒泡排序 (Bubble Sort) 冒泡排序是一种简单的排序算法…...

vue3实现拖拽移动位置,拖拽过程中鼠标松开后元素还吸附在鼠标上并随着鼠标移动

发现问题 拖拽元素移动的时候&#xff0c;偶尔会出现拖拽过程中鼠标松开后元素还吸附在鼠标上并随着鼠标移动&#xff0c;要再按一下元素才会被放置下来。但是有时就正常。 问题分析 出现该问题的原因是&#xff1a;这个过程会触发H5原生的拖拽事件&#xff0c;并且不会监听…...

没有屋檐的房子-011

棺材 &#xff08;下&#xff09; 时过境迁这个成语描述了前因后果的两种概念的变化&#xff0c;时间推延和环境的变迁。问题是&#xff0c;时间是什么呢&#xff1f;是环境变化表征了时间的推延&#xff0c;还是时间推延导致了环境的变化&#xff1f;人在多数时候&#xff0c;…...

Puppeteer-Cluster:并行处理网页操作的新利器

在现代Web开发和自动化测试领域&#xff0c;高效地处理多个网页操作任务成为了许多开发者和测试工程师的迫切需求。传统的Puppeteer工具虽然功能强大&#xff0c;但在处理大量并发任务时可能会显得力不从心。为此&#xff0c;Puppeteer-Cluster应运而生&#xff0c;作为一个基于…...

使用Protocol Buffers传输数据

使用 Google Protocol Buffers&#xff08;ProtoBuf&#xff09;与 Kafka 结合来定义和传输数据&#xff0c;可以确保传输数据的结构性、可扩展性和高效性。以下是一个简单的步骤指南&#xff0c;帮助你实现生产者和消费者。 1. 定义 ProtoBuf 消息格式 首先&#xff0c;你需…...

chmod修改文件权限

0 Preface/Foreword 1 chmod使用方法 1.1 修改单个文件 命令如下&#xff1a; sudo chmod xyz fileName xyz: x, y, z分别代表一个8进制数字&#xff08;0-7&#xff09; 1.2 修改文件夹 命令如下&#xff1a; sudo chmod -R xyz folderName...

二叉树--python

二叉树 一、概述 1、介绍 是一种非线性数据结构&#xff0c;将数据一分为二&#xff0c;代表根与叶的派生关系&#xff0c;和链表的结构类似&#xff0c;二叉树的基本单元是结点&#xff0c;每个节点包括值和左右子节点引用。 每个节点都有两个引用&#xff08;类似于双向链…...

matlab数据批量保存为excel,文件名,行和列的名称设置

Excel文件内数据保存结果如下&#xff1a; Excel文件保存结果如下&#xff1a; 代码如下&#xff1a; clear;clc; for jjjj1:10 %这个可以改 jname(jjjj-1)*10; %文件名中变数 这是EXCEL文件名字的一部分 根据自己需要改 jkkkk_num2str(jname); for …...

Pygame中Sprite类实现多帧动画3-2

3.2.3 设置帧的宽度、高度、范围及列数 通过如图6所示的代码设置帧的宽度、高度、范围及列数。 图6 设置帧的宽度、高度、范围及列数的代码 其中&#xff0c;frame_width、frame_height、rect和columns都是MySprite类的属性&#xff0c;在其__init__()方法中定义&#xff0c;…...

C#发送正文带图片带附件的邮件

1&#xff0c;开启服务&#xff0c;获取授权码。以QQ邮箱为例&#xff1a; 点击管理服务&#xff0c;进入账号与安全页面 2&#xff0c;相关设置参数&#xff0c;以QQ邮箱为例&#xff1a; 登录时&#xff0c;请在第三方客户端的密码输入框里面填入授权码进行验证。&#xff0…...

【C#跨平台开发详解】C#跨平台开发技术之.NET Core基础学习及快速入门

1. C#与.NET的发展历程 C#是由Microsoft开发的现代编程语言&#xff0c;最初伴随着.NET Framework发布。随着技术的进步&#xff0c;特别是针对跨平台开发的需求&#xff0c;Microsoft推出了.NET Core&#xff0c;这是一个开源且跨平台的框架&#xff0c;支持Windows、macOS和…...

请解释Java中的死锁产生的原因和解决方法。什么是Java中的并发工具类?请列举几个并解释其用途。

请解释Java中的死锁产生的原因和解决方法。 Java中的死锁是指两个或两个以上的线程在执行过程中&#xff0c;因为争夺资源而造成的一种相互等待的现象&#xff0c;若无外力作用&#xff0c;这些线程都将无法向前推进。死锁是并发编程中常见的问题&#xff0c;它会导致程序运行…...

[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?

&#x1f9e0; 智能合约中的数据是如何在区块链中保持一致的&#xff1f; 为什么所有区块链节点都能得出相同结果&#xff1f;合约调用这么复杂&#xff0c;状态真能保持一致吗&#xff1f;本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里&#xf…...

论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)

HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

LabVIEW双光子成像系统技术

双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制&#xff0c;展现出显著的技术优势&#xff1a; 深层组织穿透能力&#xff1a;适用于活体组织深度成像 高分辨率观测性能&#xff1a;满足微观结构的精细研究需求 低光毒性特点&#xff1a;减少对样本的损伤…...