思路:一共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点的更多相关文章

  1. C#学习笔记(九):LINQ和表达式树

    LINQ LINQ:语言集成查询(Language Integrated Query)是一组用于c#和Visual Basic语言的扩展.它允许编写C#或者Visual Basic代码以查询数据库相同 ...

  2. 程序猿修仙之路--数据结构之你是否真的懂数组? c#socket TCP同步网络通信 用lambda表达式树替代反射 ASP.NET MVC如何做一个简单的非法登录拦截

    程序猿修仙之路--数据结构之你是否真的懂数组?   数据结构 但凡IT江湖侠士,算法与数据结构为必修之课.早有前辈已经明确指出:程序=算法+数据结构  .要想在之后的江湖历练中通关,数据结构必不可少. ...

  3. C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数

    一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...

  4. c# 表达式树(一)

    前言 打算整理c# 代码简化史系列,所以相关的整理一下,简单的引出一下概念. 什么是表达式树呢? 表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的 ...

  5. C# 委托、事件、表达式树理解

    1.什么是委托? 委托是一种动态调用方法的类型,属于引用型. 委托是对方法的抽象和封装.委托对象实质上代表了方法的引用(即内存地址) 所有的异步都是委托   委托就是函数当入参   委托被各种语法糖遮 ...

  6. C# Lambda表达式详解,及Lambda表达式树的创建

    最近由于项目需要,刚刚学完了Action委托和Func<T>委托,发现学完了委托就必须学习lambda表达式,委托和Lambda表达式联合起来,才能充分的体现委托的便利.才能使代码更加简介 ...

  7. C#中的Lambda表达式和表达式树

    在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在 ...

  8. LinQ实战学习笔记(三) 序列,查询操作符,查询表达式,表达式树

    序列 延迟查询执行 查询操作符 查询表达式 表达式树 (一) 序列 先上一段代码, 这段代码使用扩展方法实现下面的要求: 取进程列表,进行过滤(取大于10M的进程) 列表进行排序(按内存占用) 只保留 ...

  9. C#在泛型类中,通过表达式树构造lambda表达式

    场景 最近对爬虫的数据库架构做调整,需要将数据迁移到MongoDB上去,需要重新实现一个针对MongoDB的Dao泛型类,好吧,动手开工,当实现删除操作的时候问题来了. 我们的删除操作定义如下:voi ...

随机推荐

  1. Intellij Idea 12 开发Android 报Caused by: java.lang.UnsatisfiedLinkError: FindLibrary return null;

    这次开发是用的百度地图api,导入两个so文件,结果启动的时候总是报Caused by: java.lang.UnsatisfiedLinkError: findlibrary return null ...

  2. 修改默认MYSQL数据库data存放位置

    随着业务量的增长,mysql默认安装所在分区大小出现瓶颈,通常需要将datadir换到较大的分区 示例原目录:/usr/local/mysql/data/示例新目录:/data/mysqldata/ ...

  3. 冒泡排序优化JAVA

    本文对传统的冒泡排序进行了一些优化,减少了循环次数. 时间复杂度 若文件的初始状态是正序的,一趟扫描即可完成排序.所需的关键字比较次数 C 和记录移动次数 M 均达到最小值: C(min)=n-1 , ...

  4. 数据库知识整理<六>

    聚合函数与分组 6.1使用聚合函数进行数据统计: 聚合函数常见的有以下几种: count:返回该结果集中行的数目. sum:返回结果集中所有值的总和. avg:返回结果集中所有值的平均值. max:返 ...

  5. IHttpActionResult – new way of creating responses in ASP.NET Web API 2

    先收藏这篇文章. http://www.strathweb.com/2013/06/ihttpactionresult-new-way-of-creating-responses-in-asp-net ...

  6. 用nifi把hdfs数据导到hive

    全景图:     1. ListHDFS & FetchHDFS: ListHDFS:   FetchHDFS:   2. EvaluateJsonPath: {"status&qu ...

  7. [MFC] 从文件读取与向文件添加数据

    CString str,str2,str3;str2="dsf",str3="dsfds"; CStdioFile myFile, File; if(myFil ...

  8. [WinAPI] API 9 [文件的删除、复制和移动功能]

    Windows系统为文件的删除.复制.重命名或移动文件提供了相应的API函数.删除文件使用DeleteFile函数:复制文件使用CopyFile函数:重命名文件和移动文件实际是一个操作,使用MoveF ...

  9. [stm32] Systick

    (一) 背景介绍在传统的嵌入式系统软件按中通常实现 Delay(N) 函数的方法为:for(i=0;i<=x;i++); x--:            对应于N毫秒的循环值对于STM32系列微 ...

  10. Lingo 做线性规划 - DEA

    Reference: <An Introduction to Management Science Quantitative Approaches to Decision Making, Rev ...