如何高效存储含变量的数学表达式以实现快速多次求值?
高效存储解析后数学表达式以支持多组变量求值的方案
你选择用逆波兰表示法(RPN)的令牌数组存储解析结果的思路完全正确——这种结构天生适合栈式求值,且表达式结构固定,仅需更新变量值就能重复计算,完美匹配你多组变量求值的需求。
针对你纠结的运算符和函数存储问题,函数指针是最优方案之一,兼具速度和内存效率,下面给出具体的优化方案:
优化后的Token结构设计
将运算符拆分为一元/二元类型(求值时栈操作逻辑不同),直接在Token的union中存储函数指针,避免额外的参数结构体开销:
// 定义函数指针类型,统一返回double适配浮点求值 typedef double (*BinaryOp)(double, double); // 二元运算符:+、-、*、/、^等 typedef double (*UnaryOp)(double); // 一元运算符:负号、平方根等 typedef double (*MathFunc)(double); // 数学函数:sin、cos、log等 enum TokenType { NUMBER, // 常量数值 VARIABLE, // 变量 BINARY_OP, // 二元运算符 UNARY_OP, // 一元运算符 FUNCTION // 数学函数 }; struct Token { TokenType type; union { double value; // NUMBER类型:存储常量值(建议用double支持浮点) int variable_index; // VARIABLE类型:变量在值数组中的索引 BinaryOp binary_op; // BINARY_OP类型:指向二元运算函数的指针 UnaryOp unary_op; // UNARY_OP类型:指向一元运算函数的指针 MathFunc math_func; // FUNCTION类型:指向数学函数的指针 }; };
结构优势:
- 内存紧凑:union共享内存空间,每个Token仅占
sizeof(TokenType) + sizeof(最大成员)(64位系统下约16字节) - 求值直接:无需查表或字符串匹配,直接调用函数指针完成计算,速度最快
求值流程(多次复用)
- 维护一个
double类型的求值栈,以及一个存储变量值的数组(比如double vars[],索引对应Token的variable_index) - 遍历RPN令牌数组,按类型处理:
- NUMBER:将
value压入栈 - VARIABLE:根据
variable_index从变量数组取值,压入栈 - UNARY_OP:弹出栈顶元素,调用
unary_op计算,结果压回栈 - BINARY_OP:弹出两个元素(注意顺序:先弹的是右操作数),调用
binary_op计算,结果压回栈 - FUNCTION:弹出对应参数个数的元素(如
sin弹1个),调用math_func计算,结果压回栈
- NUMBER:将
- 遍历结束后,栈顶元素即为当前变量组对应的表达式结果
额外优化建议
- 变量数组用连续内存(如C++的
std::vector<double>或C的动态数组),保证快速随机访问 - 对于频繁使用的表达式,可以预分配求值栈的内存,避免每次求值时的内存分配开销
- 如果表达式中有重复常量,可共享同一个Token实例,进一步减少内存占用
内容的提问来源于stack exchange,提问作者FusRoDah
相关产品推荐
相关产品推荐

