用C#表达式树优雅的计算24点
思路:一共4个数字,共需要3个运算符,可以构造一个二叉树,没有子节点的节点的为值,有叶子节点的为运算符
例如数字{1, 2, 3, 4},其中一种解的二叉树形式如下所示:
因此可以遍历所有二叉树可能的形式,4个数的全排列,从4种运算符中挑选3种运算符(运算符可以重复)
核心步骤1:需要遍历所有二叉树的可能,参考Eric Lippert的方法
- class Node
- {
- public Node Left { get; private set; }
- public Node Right { get; private set; }
- public Node(Node left, Node right)
- {
- this.Left = left;
- this.Right = right;
- }
- }
- static IEnumerable<Node> AllBinaryTrees(int size)
- {
- if (size == )
- return new Node[] { null };
- return from i in Enumerable.Range(, size)
- from left in AllBinaryTrees(i)
- from right in AllBinaryTrees(size - - i)
- select new Node(left, right);
- }
核心步骤2:对于任意一个二叉树,构造表达式树
- static Expression Build(Node node, List<double> numbers, List<Func<Expression, Expression, BinaryExpression>> operators)
- {
- var iNum = ;
- var iOprt = ;
- Func<Node, Expression> f = null;
- f = n =>
- {
- Expression exp;
- if (n == null)
- exp = Expression.Constant(numbers[iNum++]);
- else
- {
- var left = f(n.Left);
- var right = f(n.Right);
- exp = operators[iOprt++](left, right);
- }
- return exp;
- };
- return f(node);
- }
核心步骤3:遍历4个数字的全排列,全排列参考这里
- static IEnumerable<List<T>> FullPermute<T>(List<T> elements)
- {
- if (elements.Count == )
- return EnumerableOfOneElement(elements);
- IEnumerable<List<T>> result = null;
- foreach (T first in elements)
- {
- List<T> remaining = elements.ToArray().ToList();
- remaining.Remove(first);
- IEnumerable<List<T>> fullPermuteOfRemaining = FullPermute(remaining);
- foreach (List<T> permute in fullPermuteOfRemaining)
- {
- var arr = new List<T> { first };
- arr.AddRange(permute);
- var seq = EnumerableOfOneElement(arr);
- if (result == null)
- result = seq;
- else
- result = result.Union(seq);
- }
- }
- return result;
- }
- static IEnumerable<T> EnumerableOfOneElement<T>(T element)
- {
- yield return element;
- }
例如有四个数字{1, 2, 3, 4},它的全排列如下:
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
- , , ,
核心步骤4:从4种运算符中挑选3个运算符
- static IEnumerable<IEnumerable<Func<Expression, Expression, BinaryExpression>>> OperatorPermute(List<Func<Expression, Expression, BinaryExpression>> operators)
- {
- return from operator1 in operators
- from operator2 in operators
- from operator3 in operators
- select new[] { operator1, operator2, operator3 };
- }
最后是Main函数:
- static void Main(string[] args)
- {
- List<double> numbers = new List<double> { , , , };
- var operators = new List<Func<Expression, Expression, BinaryExpression>> {
- Expression.Add,Expression.Subtract,Expression.Multiply,Expression.Divide
- };
- foreach (var operatorCombination in OperatorPermute(operators))
- {
- foreach (Node node in AllBinaryTrees())
- {
- foreach (List<double> permuteOfNumbers in FullPermute(numbers))
- {
- Expression expression = Build(node, permuteOfNumbers, operatorCombination.ToList());
- Func<double> compiled = Expression.Lambda<Func<double>>(expression).Compile();
- try
- {
- var value = compiled();
- if (Math.Abs(value - ) < 0.01)
- Console.WriteLine("{0} = {1}", expression, value);
- }
- catch (DivideByZeroException) { }
- }
- }
- }
- Console.Read();
- }
计算结果:
- ( * ( + ( + ))) =
- ( * ( + ( + ))) =
- ( * ( + ( + ))) =
- ( * ( + ( + ))) =
- ( * ( + ( + ))) =
- ( * ( + ( + ))) =
- ( * (( + ) + )) =
- ( * (( + ) + )) =
- ( * (( + ) + )) =
- ( * (( + ) + )) =
- ( * (( + ) + )) =
- ( * (( + ) + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ) * ( + )) =
- (( + ( + )) * ) =
- (( + ( + )) * ) =
- (( + ( + )) * ) =
- (( + ( + )) * ) =
- (( + ( + )) * ) =
- (( + ( + )) * ) =
- ((( + ) + ) * ) =
- ((( + ) + ) * ) =
- ((( + ) + ) * ) =
- ((( + ) + ) * ) =
- ((( + ) + ) * ) =
- ((( + ) + ) * ) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * ( * ( * ))) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- ( * (( * ) * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ) * ( * )) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- (( * ( * )) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- ((( * ) * ) * ) =
- (( * ( * )) / ) =
- (( * ( * )) / ) =
- (( * ( * )) / ) =
- (( * ( * )) / ) =
- (( * ( * )) / ) =
- (( * ( * )) / ) =
- ((( * ) * ) / ) =
- ((( * ) * ) / ) =
- ((( * ) * ) / ) =
- ((( * ) * ) / ) =
- ((( * ) * ) / ) =
- ((( * ) * ) / ) =
- ( * (( * ) / )) =
- ( * (( * ) / )) =
- ( * (( * ) / )) =
- ( * (( * ) / )) =
- ( * (( * ) / )) =
- ( * (( * ) / )) =
- (( * ) * ( / )) =
- (( * ) * ( / )) =
- (( * ) * ( / )) =
- (( * ) * ( / )) =
- (( * ) * ( / )) =
- (( * ) * ( / )) =
- ((( * ) / ) * ) =
- ((( * ) / ) * ) =
- ((( * ) / ) * ) =
- ((( * ) / ) * ) =
- ((( * ) / ) * ) =
- ((( * ) / ) * ) =
- ( / ( / ( * ))) =
- ( / ( / ( * ))) =
- ( / ( / ( * ))) =
- ( / ( / ( * ))) =
- ( / ( / ( * ))) =
- ( / ( / ( * ))) =
- (( * ) / ( / )) =
- (( * ) / ( / )) =
- (( * ) / ( / )) =
- (( * ) / ( / )) =
- (( * ) / ( / )) =
- (( * ) / ( / )) =
- ( * ( * ( / ))) =
- ( * ( * ( / ))) =
- ( * ( * ( / ))) =
- ( * ( * ( / ))) =
- ( * ( * ( / ))) =
- ( * ( * ( / ))) =
- ( * (( / ) * )) =
- ( * (( / ) * )) =
- ( * (( / ) * )) =
- ( * (( / ) * )) =
- ( * (( / ) * )) =
- ( * (( / ) * )) =
- (( / ) * ( * )) =
- (( / ) * ( * )) =
- (( / ) * ( * )) =
- (( / ) * ( * )) =
- (( / ) * ( * )) =
- (( / ) * ( * )) =
- (( * ( / )) * ) =
- (( * ( / )) * ) =
- (( * ( / )) * ) =
- (( * ( / )) * ) =
- (( * ( / )) * ) =
- (( * ( / )) * ) =
- ((( / ) * ) * ) =
- ((( / ) * ) * ) =
- ((( / ) * ) * ) =
- ((( / ) * ) * ) =
- ((( / ) * ) * ) =
- ((( / ) * ) * ) =
- ( * ( / ( / ))) =
- ( * ( / ( / ))) =
- ( * ( / ( / ))) =
- ( * ( / ( / ))) =
- ( * ( / ( / ))) =
- ( * ( / ( / ))) =
- (( / ( / )) * ) =
- (( / ( / )) * ) =
- (( / ( / )) * ) =
- (( / ( / )) * ) =
- (( / ( / )) * ) =
- (( / ( / )) * ) =
- ( / (( / ) / )) =
- ( / (( / ) / )) =
- ( / (( / ) / )) =
- ( / (( / ) / )) =
- ( / (( / ) / )) =
- ( / (( / ) / )) =
对于一些平时口算相对稍难的一些组合也是毫无压力,例如{1, 5, 5, 5}, {3, 3, 7, 7}, {3, 3, 8, 8},有兴趣的看官口算试试 :)
用C#表达式树优雅的计算24点的更多相关文章
- C#学习笔记(九):LINQ和表达式树
LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...
- 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截
程序猿修仙之路--数据结构之你是否真的懂数组? 数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构 .要想在之后的江湖历练中通关,数据结构必不可少. ...
- C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数
一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...
- c# 表达式树(一)
前言 打算整理c# 代码简化史系列,所以相关的整理一下,简单的引出一下概念. 什么是表达式树呢? 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的 ...
- C# 委托、事件、表达式树理解
1.什么是委托? 委托是一种动态调用方法的类型,属于引用型. 委托是对方法的抽象和封装.委托对象实质上代表了方法的引用(即内存地址) 所有的异步都是委托 委托就是函数当入参 委托被各种语法糖遮 ...
- C# Lambda表达式详解,及Lambda表达式树的创建
最近由于项目需要,刚刚学完了Action委托和Func<T>委托,发现学完了委托就必须学习lambda表达式,委托和Lambda表达式联合起来,才能充分的体现委托的便利.才能使代码更加简介 ...
- C#中的Lambda表达式和表达式树
在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...
- LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树
序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...
- C#在泛型类中,通过表达式树构造lambda表达式
场景 最近对爬虫的数据库架构做调整,需要将数据迁移到MongoDB上去,需要重新实现一个针对MongoDB的Dao泛型类,好吧,动手开工,当实现删除操作的时候问题来了. 我们的删除操作定义如下:voi ...
随机推荐
- 浏览器js console对象
js中调用console写日志 console.log("some log"); console.warn("some warning"); console.e ...
- nop 添加字段
一.Libraries 1.core 层------------实体字段 2.data-Map----------映射到数据库 二.Admin 1.Models --------admin界面模型 ...
- decode 横竖转换 2
select sno,nvl(to_char(sum(decode(cno,'c001',score))),'-') c001,nvl(to_char(sum(decode(cno,'c002',sc ...
- 关于collapsed margin(外边距合并)
这是前面写postion定位时写到最后面的例子的时候发现的一个问题,于是专门写一篇随笔来解释记录一下,毕竟两个知识点同时写在一篇文章里面有点混乱的感觉.. 上篇随笔position定位遇到的问题在这里 ...
- 封装getElementsByClassName()
function getElementsByClassName(node,classname){ if(node.getElementsByClassName){ ...
- C++混合编程之idlcpp教程Lua篇(4)
上一篇在这 C++混合编程之idlcpp教程Lua篇(3) 与前面的工程相似,工程LuaTutorial2中,同样加入了三个文件 LuaTutorial2.cpp, Tutorial2.i, tut ...
- 配置本地IIS和VS自带IIS
以前调试网站一直用的vs自带的IIS,做为学习没啥大碍,但要是用于团队项目开发就会带来诸多不便.团队开发项目有统一的网站端口号.文件目录什么的,端口号可以在配置文件中修改倒也没啥,但是要在自己的项目中 ...
- qooxdoo 3.0 发布,JavaScript 的 GUI 框架
qooxdoo 3.0 是一个主要的版本,包含很多新特性和内部的改动,qooxdoo 3.0 是一个通用的 JS 框架,主要改进体现在 qx.Desktop, qx.Mobile, 和 qx.Webs ...
- Linux下oracle11gR2系统安装到数据库建立配置及最后oracle的dmp文件导入一站式操作记录
简介 之前也在linux下安装过oralce,可每次都是迷迷糊糊的,因为大脑一片空白,网上随便看见一个文档就直接复制,最后搞了乱七八糟,虽然装上了,却乱得很,现在记录下来,希望能给其他网上朋友遇到问题 ...
- WebApi与手机客户端通信安全机制
最近公司有几个项目需要开发手机客户端,服务器端选用WebApi,那么如何保证手机客户端在请求服务器端时数据不被篡改,如何保证一个http请求的失效机制,下面总结一下我们在项目中针对这两个问题的解决方案 ...