通过真值树解析布尔表达式(eg:A&B|C)
第一步:求出一个表达式的truth tree
1.生成真值表
2.根据真值表生成真值树(合并短路产生相同的两个子树)
/****************************************
* File: truth_tree.h
*
*A&B|C truth_table
0 0 1 1
0 1 1 1
1 0 1 1
1 1 0 1
1 1 1 1
*
* Complete Binary Tree
* -1(root)
/ \
A: 0 1
/ \ / \
B: 0 1 0 1
\ \ \ / \
C: 1 1 1 0 1
*
*
* After merge
* * -1(root)
/ \
A: 0 1
/ / \
B: -1 0 1
\ \ /
C: 1 1 -1
*
*
* *****************************************/ #ifndef UTIL_TRUTH_TREE_H
#define UTIL_TRUTH_TREE_H #include <memory>
#include <vector> namespace util { struct TruthTreeNode
{
int8_t value;
std::shared_ptr<TruthTreeNode> left;
std::shared_ptr<TruthTreeNode> right; explicit TruthTreeNode(int8_t in_v):value(in_v),left(nullptr),right(nullptr){}
TruthTreeNode(const TruthTreeNode&) = delete;
TruthTreeNode(TruthTreeNode&&) = delete;
TruthTreeNode& operator=(const TruthTreeNode&) = delete;
TruthTreeNode& operator=(TruthTreeNode&&) = delete;
}; using truth_table_t = std::vector<std::vector<bool>>; class TruthTree
{
public: //Constructors and destructor
TruthTree():m_root(nullptr){} TruthTree(const TruthTree& tree)
{
m_root = copy_tree(tree.root());
} TruthTree& operator=(const TruthTree& tree)
{
if (this == &tree)
return *this; m_root = copy_tree(tree.root());
return *this;
} TruthTree(TruthTree&&) = delete;
TruthTree& operator=(TruthTree&&) = delete;
~TruthTree() = default; public: //interface
void initialize_tree(const truth_table_t& truth_table); const std::shared_ptr<TruthTreeNode>& root() const
{
return m_root;
} bool empty() const
{
if (nullptr == m_root)
return true; if (nullptr == m_root->left && nullptr == m_root->right)
return true; return false;
} private: //static member method
static std::shared_ptr<TruthTreeNode> copy_tree(const std::shared_ptr<TruthTreeNode>& parent_node_ptr);
static std::shared_ptr<TruthTreeNode> table_to_tree(const truth_table_t& truth_table);
static std::shared_ptr<TruthTreeNode> try_add_new_child_node(bool element, std::shared_ptr<TruthTreeNode> parent_node_ptr);
static std::shared_ptr<TruthTreeNode> add_new_child_node(bool element, std::shared_ptr<TruthTreeNode> parent_node_ptr);
static bool compare_tree(const std::shared_ptr<TruthTreeNode> left, const std::shared_ptr<TruthTreeNode> right);
static void merge_child_trees(std::shared_ptr<TruthTreeNode> parent_node_ptr); private: //member data
std::shared_ptr<TruthTreeNode> m_root;
}; } #endif //UTIL_TRUTH_TREE_H
/*
* File: truth_tree.cpp
*/ #include "truth_tree.h"
#include <numeric> namespace util { void TruthTree::initialize_tree(const truth_table_t& truth_table)
{
m_root = table_to_tree(truth_table);
merge_child_trees(m_root);
} std::shared_ptr<TruthTreeNode> TruthTree::copy_tree(const std::shared_ptr<TruthTreeNode>& parent_node_ptr)
{
if (nullptr == parent_node_ptr)
return nullptr; std::shared_ptr<TruthTreeNode> node_ptr = std::make_shared<TruthTreeNode>(parent_node_ptr->value);
node_ptr->left = copy_tree(parent_node_ptr->left);
node_ptr->right = copy_tree(parent_node_ptr->right); return node_ptr;
} std::shared_ptr<TruthTreeNode> TruthTree::table_to_tree(const truth_table_t& truth_table)
{
if (truth_table.empty())
return nullptr; std::shared_ptr<TruthTreeNode> root = std::make_shared<TruthTreeNode>(-);
for (size_t row = ; row < truth_table.size(); ++row)
{
std::shared_ptr<TruthTreeNode> parent_node_ptr = root;
for (size_t column = ; column < truth_table[row].size(); ++column)
{
std::shared_ptr<TruthTreeNode> child_node_ptr = try_add_new_child_node(truth_table[row][column], parent_node_ptr);
parent_node_ptr = child_node_ptr;
}
} return root;
} std::shared_ptr<TruthTreeNode> TruthTree::try_add_new_child_node(bool element, std::shared_ptr<TruthTreeNode> parent_node_ptr)
{
if (nullptr == parent_node_ptr)
return nullptr; if (!element && nullptr != parent_node_ptr->left)
return parent_node_ptr->left; if (element && nullptr != parent_node_ptr->right)
return parent_node_ptr->right; return add_new_child_node(element, parent_node_ptr);
} std::shared_ptr<TruthTreeNode> TruthTree::add_new_child_node(bool element, std::shared_ptr<TruthTreeNode> parent_node_ptr)
{
if (nullptr == parent_node_ptr)
return nullptr; //false to left node, true to right node
if (!element)
{
parent_node_ptr->left = std::make_shared<TruthTreeNode>();
return parent_node_ptr->left;
}
else
{
parent_node_ptr->right = std::make_shared<TruthTreeNode>();
return parent_node_ptr->right;
}
} /***************************Recursive create tree****************************************/
/*
root {-1,-1,(0,1,2,3,4)} A: {0,0,(0,1)} {0,1,(2,3,4)} B: {1,0,(0)} {1,1,(1)} {1,0,(2)} {1,1,(3,4)} C: {2,1,(0)} {2,1,(1)} {2,1,(2)} {2,0,(3)} {2,1,(4)} struct truth_tree_node
{
int8_t level;//truth table row index
int8_t value;
std::vector<size_t> index_vec;//truth table columns index
std::shared_ptr<truth_tree_node> left;
std::shared_ptr<truth_tree_node> right;
//std::vector<size_t> indexs(m_truth_table[0].size());
//std::iota(indexs.begin(), indexs.end(), 0);
//m_root = std::make_shared<truth_tree_node>(-1, -1, indexs);
}; void TruthTree::insert_child_node(std::shared_ptr<truth_tree_node> parent_node_ptr)
{
if (nullptr == parent_node_ptr)
return; int8_t level = parent_node_ptr->level + 1;
if ( (level < 0) || (level >= m_truth_table.size()) )
return; std::vector<size_t> left_indexs;
std::vector<size_t> right_indexs;
for(size_t i : parent_node.index_vec)
{
if(!m_truth_table[level][i])
left_indexs.push_back(i);
else
right_indexs.push_back(i);
} if (!left_indexs.empty())
parent_node.left = std::make_shared<truth_tree_node>(level, 0, left_indexs); if (!right_indexs.empty())
parent_node.right = std::make_shared<truth_tree_node>(level, 1, right_indexs);
} void TruthTree::SubCreat(std::shared_ptr<truth_tree_node> parent_node_ptr)
{
if (nullptr == parent_node_ptr)
return; insert_child_node(parent_node_ptr); SubCreat(parent_node_ptr->left);
SubCreat(parent_node_ptr->right);
}
***************************************************************************************/ bool TruthTree::compare_tree(const std::shared_ptr<TruthTreeNode> left_tree, const std::shared_ptr<TruthTreeNode> right_tree)
{
if ((nullptr == left_tree) && (nullptr == right_tree))
{
return true;
} //if one is null and other is not null
if ((nullptr == left_tree) || (nullptr == right_tree))
{
return false;
} if (left_tree->value != left_tree->value)
{
return false;
} bool left = compare_tree(left_tree->left, right_tree->left);
bool right = compare_tree(left_tree->right, right_tree->right);
return (left && right);
} void TruthTree::merge_child_trees(std::shared_ptr<TruthTreeNode> parent_node_ptr)
{
if (nullptr == parent_node_ptr || nullptr == parent_node_ptr->left || nullptr == parent_node_ptr->right)
{
return;
} bool merge_flag = compare_tree(parent_node_ptr->left->left, parent_node_ptr->right->left)
&& compare_tree(parent_node_ptr->left->right, parent_node_ptr->right->right); if (merge_flag)
{
parent_node_ptr->left->value = -;
parent_node_ptr->right = nullptr; //delete right tree
} merge_child_trees(parent_node_ptr->left);
merge_child_trees(parent_node_ptr->right);
} }
第二步:计算表达式
同时按层深度索引真值树,遍历表达式的变量(按需求值),当能走到树的叶子节点时说明本次表达式为true
数据结构:
1.真值树:是一个二叉树,每层依次对应A,B,C...表达式成员;用真值表作为参数构造;提供Creat();Empty();Root()等常见接口
2.表达式类:专门负责解析字符串(eg:A&B|C),提供接口:获取{表达式成员序列,真值树};通过{表达式成员序列,真值树}+成员求值函数对象 计算表达式值
备注:
1.参照http://www.cppblog.com/vczh/archive/2008/06/15/53373.html和《C++沉思录》第八章写出eval::IcomputeBoolExpr()接口
2.真值树的层数最好在16层以内,过大可能过于增加构造树的时间;对于过大的表达式建议不考虑用真值树实现表达式短路。
3.真值树的思路相当于预先把所有可能的值都求一遍,缓存起来;需要读编译原理,了解GCC语法树,可能有更好的思路实现表达式短路。
通过真值树解析布尔表达式(eg:A&B|C)的更多相关文章
- 轻量级表达式树解析框架Faller
有话说 之前我写了3篇关于表达式树解析的文章 干货!表达式树解析"框架"(1) 干货!表达式树解析"框架"(2) 干货!表达式树解析"框架" ...
- 干货!表达式树解析"框架"(1)
最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 关于我和表达式树 其实我也没有深入了解表达式树一些内在实现的原理 ...
- 干货!表达式树解析"框架"(2)
最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 为了过个好年,我还是赶快把这篇完成了吧 声明 本文内容需要有一定 ...
- 干货!表达式树解析"框架"(3)
最新设计请移步 轻量级表达式树解析框架Faller http://www.cnblogs.com/blqw/p/Faller.html 这应该是年前最后一篇了,接下来的时间就要陪陪老婆孩子了 关于表达 ...
- 介绍一个可以将Expression表达式树解析成Transact-SQL的项目Expression2Sql
一.Expression2Sql介绍 Expression2Sql是一个可以将Expression表达式树解析成Transact-SQL的项目.简单易用,几分钟即可上手使用,因为博主在设计Expres ...
- 表达式树解析"框架"
干货!表达式树解析"框架"(2) 为了过个好年,我还是赶快把这篇完成了吧 声明 本文内容需要有一定基础的开发人员才可轻松阅读,如果有难以理解的地方可以跟帖询问,但我也不一定能回 ...
- Lambda表达式树解析(下)
概述 前面章节,总结了Lambda树的构建,那么怎么解析Lambda表达式树那?Lambda表达式是一种委托构造而成,如果能够清晰的解析Lambda表达式树,那么就能够理解Lambda表达式要传递的正 ...
- Lambda表达式树解析(下)包含自定义的provider和查询
概述 前面章节,总结了Lambda树的构建,那么怎么解析Lambda表达式树那?Lambda表达式是一种委托构造而成,如果能够清晰的解析Lambda表达式树,那么就能够理解Lambda表达式要传递的正 ...
- CSS加载不会阻塞DOM树解析
1.css的加载不会阻塞DOM树解析. 1).css加载不会阻塞DOM树的解析: 2).css加载会阻塞DOM树渲染: 先把DOM树结构先解析完,等CSS加载完后根据最终样式渲染DOM树,免了css加 ...
随机推荐
- D语言简介
D语言,一种通用计算机程序语言,威力强大.功能丰富,支持多种编程范式,例如面向对象.[1] D语言最初由Digital Mars公司就职的Walter Bright于2001年发布,意图改进C++语 ...
- C++输入cin详解
输入原理: 程序的输入都建有一个缓冲区,即输入缓冲区.一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据.正因为cin函数是直接从缓冲区取数据 ...
- [转]C++的Json解析库:jsoncpp和boost
JSON(JavaScript Object Notation)跟xml一样也是一种数据交换格式,了解json请参考其官网http://json.org,本文不再对json做介绍,将重点介绍c++的j ...
- JVM内核-原理、诊断与优化学习笔记(二):JVM运行机制
文章目录 JVM启动流程 PC寄存器 方法区 保存装载的类信息 通常和永久区(Perm)关联在一起 Java堆 Java栈 Java栈 – 局部变量表 ** 包含参数和局部变量 ** Java栈 – ...
- hexo next主题深度优化(六),使用hexo-neat插件压缩页面,大幅度提升页面性能和响应速度。
文章目录 隆重感谢: 背景 开始 试水 成功的案例 安装插件,执行命令. hexo _config.yml文件添加 坑 跳过压缩文件的正确配置方式 压缩html时不要跳过.md文件 压缩html时不要 ...
- 3. Vim入门教程
1. 基本概念 1.1 了解Vim的三个基本模式 当我们安装完一个编辑器后,肯定会打开它,然后在里面输入点什么东西,但是打你打开Vim后,想要输入点什么却发现自己什么都没有输入,所以在写点东西之前,先 ...
- Function(高阶函数式编程)
Function一个可以进行高阶函数式编程的模块. chain def chain[a](fs: Seq[(a) ? a]): (a) ? a 把一些列的方法串起来,挨个执行,每个方法的结果,回作为下 ...
- Intellij IDEA 撸码最头大的问题。。
想栈长我当初从 Eclipse 转用 IDEA 真是纠结,放弃然后尝试了N次,不过现在已经算是转型成功了,可以完全脱离 Eclipse 撸码了,虽然说我现在真的撸得非常少了.. 说到 IDEA 的痛点 ...
- 逻辑回归,多分类推广算法softmax回归中
转自http://ufldl.stanford.edu/wiki/index.php/Softmax%E5%9B%9E%E5%BD%92 简介 在本节中,我们介绍Softmax回归模型,该模型是log ...
- HDU 5531
题目大意: 给定一个n边形的顶点 以每个顶点为圆心画圆(半径可为0) 每个顶点的圆要和它相邻顶点的圆相切(不相邻的可相交) 求所有圆的最小面积总和并给出所有圆的半径 设半径为r1 r2 ... rn, ...