- 浏览: 3047679 次
- 性别:
- 来自: 海外
文章分类
- 全部博客 (430)
- Programming Languages (23)
- Compiler (20)
- Virtual Machine (57)
- Garbage Collection (4)
- HotSpot VM (26)
- Mono (2)
- SSCLI Rotor (1)
- Harmony (0)
- DLR (19)
- Ruby (28)
- C# (38)
- F# (3)
- Haskell (0)
- Scheme (1)
- Regular Expression (5)
- Python (4)
- ECMAScript (2)
- JavaScript (18)
- ActionScript (7)
- Squirrel (2)
- C (6)
- C++ (10)
- D (2)
- .NET (13)
- Java (86)
- Scala (1)
- Groovy (3)
- Optimization (6)
- Data Structure and Algorithm (3)
- Books (4)
- WPF (1)
- Game Engines (7)
- 吉里吉里 (12)
- UML (1)
- Reverse Engineering (11)
- NSIS (4)
- Utilities (3)
- Design Patterns (1)
- Visual Studio (9)
- Windows 7 (3)
- x86 Assembler (1)
- Android (2)
- School Assignment / Test (6)
- Anti-virus (1)
- REST (1)
- Profiling (1)
- misc (39)
- NetOA (12)
- rant (6)
- anime (5)
- Links (12)
- CLR (7)
- GC (1)
- OpenJDK (2)
- JVM (4)
- KVM (0)
- Rhino (1)
- LINQ (2)
- JScript (0)
- Nashorn (0)
- Dalvik (1)
- DTrace (0)
- LLVM (0)
- MSIL (0)
最新评论
-
mldxs:
虽然很多还是看不懂,写的很好!
虚拟机随谈(一):解释器,树遍历解释器,基于栈与基于寄存器,大杂烩 -
HanyuKing:
Java的多维数组 -
funnyone:
Java 8的default method与method resolution -
ljs_nogard:
Xamarin workbook - .Net Core 中不 ...
LINQ的恶搞…… -
txm119161336:
allocatestlye1 顺序为 // Fields o ...
最近做的两次Java/JVM分享的概要
相关链接:
那啥……穷举实现的24点
昨天那帖里提到,那个实现并不完整,会漏掉一些情况。漏掉的是什么呢?
假如我们用n代表一个数字,用o代表一个运算符,那么昨天实现的运算是这样的形式的后序表达式:
实际上因为减法与除法不满足交换律,所以另外几种情况也必须考虑到。
一共是5种情况:
后序表达式 => 中序表达式
思路是:以后序表达式考虑,一共是7个空位,其中头两个必须是数字,最后一个必须是运算符;从左向右看,每个位置之前的数字的个数至少要比运算符的个数多一个。于是得到上面的5种情况。
把昨天漏掉的情况加进来,我做了下面的实现,暂且叫rev1。
不过这个实现并没有尝试去消除所有本质上相同的表达式(在后缀表达式中本质上相同但写法不同的表达式会由满足交换律的运算而产生),只是把三个运算都是加法或者乘法的情况作为特殊情况单独计算了而已。
还是把生成全排列的部分换成了递归的方法。昨天那个三层for循环嵌套的方法太ad-hoc了,不爽。
说起来,我并没有用栈去计算表达式,实际上也没有用后序表达式来做计算。只是用后序表达式来输出,想绕开括号问题而已。在rev1的实现里,只要在Evaluator里把其中的几个toString()方法改掉就能改回到以中序方式输出;不想在括号上多麻烦的话,可以只给加法和减法的两边加括号——因为这里运算优先级最高的除括号外就是乘法和除法了,它们两边加不加括号都可以。有个小陷阱就是了:a * b / c与a * ( b / c )不一定一样,因为b不一定是c的倍数,但a * b可能是c的倍数。
在Operator和两个Tuple类里都添加了些暂时还没用上的方法(例如说运算符优先级、Iteratable<E>的实现、equals()的覆盖等),不过如果以后还想改进的话说不定会用到,就留着了。
Anyway,这代码里一个switch也没有,因为没有这个必要。依靠面向对象的多态性,没必要让代码被switch所污染。在多个地方对某种整型代码做switch的话,很可能改一处就改一堆地方,太麻烦……
要是Java支持类似C#的indexer就好了……那样就不用写一堆get(0)、get(1)之类的 T T
Calc24.java:
OperandTuple.java:
OperatorTuple.java:
Operator.java:
Evaluator.java:
CannotDivideException.java:
那啥……穷举实现的24点
昨天那帖里提到,那个实现并不完整,会漏掉一些情况。漏掉的是什么呢?
假如我们用n代表一个数字,用o代表一个运算符,那么昨天实现的运算是这样的形式的后序表达式:
n n o n o n o
实际上因为减法与除法不满足交换律,所以另外几种情况也必须考虑到。
一共是5种情况:
后序表达式 => 中序表达式
n n n n o o o => n o ( n o ( n o n ) ) n n n o n o o => n o ( ( n o n ) o n ) ) n n n o o n o => ( n o ( n o n ) ) o n n n o n n o o => ( n o n ) o ( n o n ) n n o n o n o => ( ( n o n ) o n ) o n
思路是:以后序表达式考虑,一共是7个空位,其中头两个必须是数字,最后一个必须是运算符;从左向右看,每个位置之前的数字的个数至少要比运算符的个数多一个。于是得到上面的5种情况。
把昨天漏掉的情况加进来,我做了下面的实现,暂且叫rev1。
不过这个实现并没有尝试去消除所有本质上相同的表达式(在后缀表达式中本质上相同但写法不同的表达式会由满足交换律的运算而产生),只是把三个运算都是加法或者乘法的情况作为特殊情况单独计算了而已。
还是把生成全排列的部分换成了递归的方法。昨天那个三层for循环嵌套的方法太ad-hoc了,不爽。
说起来,我并没有用栈去计算表达式,实际上也没有用后序表达式来做计算。只是用后序表达式来输出,想绕开括号问题而已。在rev1的实现里,只要在Evaluator里把其中的几个toString()方法改掉就能改回到以中序方式输出;不想在括号上多麻烦的话,可以只给加法和减法的两边加括号——因为这里运算优先级最高的除括号外就是乘法和除法了,它们两边加不加括号都可以。有个小陷阱就是了:a * b / c与a * ( b / c )不一定一样,因为b不一定是c的倍数,但a * b可能是c的倍数。
在Operator和两个Tuple类里都添加了些暂时还没用上的方法(例如说运算符优先级、Iteratable<E>的实现、equals()的覆盖等),不过如果以后还想改进的话说不定会用到,就留着了。
Anyway,这代码里一个switch也没有,因为没有这个必要。依靠面向对象的多态性,没必要让代码被switch所污染。在多个地方对某种整型代码做switch的话,很可能改一处就改一堆地方,太麻烦……
要是Java支持类似C#的indexer就好了……那样就不用写一堆get(0)、get(1)之类的 T T
Calc24.java:
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.HashSet; public class Calc24 { private HashSet<OperandTuple> operandTupleSet; private HashSet<OperatorTuple> operatorTupleSet; private int[] inputOperand; public Calc24() { this.operandTupleSet = new HashSet<OperandTuple>(); this.operatorTupleSet = new HashSet<OperatorTuple>(); this.inputOperand = promptInput(); this.permutateOperand(); for (Operator op1 : Operator.values()) for (Operator op2 : Operator.values()) for (Operator op3 : Operator.values()) this.operatorTupleSet.add(new OperatorTuple(op1, op2, op3)); } public static void main(String[] args) { Calc24 program = new Calc24(); HashSet<String> resultSet = new HashSet<String>(); OperandTuple numTuple = new OperandTuple(program.inputOperand[0], program.inputOperand[1], program.inputOperand[2], program.inputOperand[3]); OperatorTuple opAddTuple = new OperatorTuple(Operator.Add, Operator.Add, Operator.Add); OperatorTuple opMulTuple = new OperatorTuple(Operator.Multiply, Operator.Multiply, Operator.Multiply); program.operatorTupleSet.remove(opAddTuple); program.operatorTupleSet.remove(opMulTuple); // special case handling if (Evaluator.TYPE1.eval(numTuple, opAddTuple) == 24) resultSet.add(Evaluator.TYPE1.toString(numTuple, opAddTuple)); if (Evaluator.TYPE1.eval(numTuple, opMulTuple) == 24) resultSet.add(Evaluator.TYPE1.toString(numTuple, opMulTuple)); // evaluate all other possible expressions for (OperandTuple operandTuple : program.operandTupleSet) for (OperatorTuple operatorTuple : program.operatorTupleSet) for (Evaluator ev : Evaluator.values()) try { if (ev.eval(operandTuple, operatorTuple) == 24) resultSet.add(ev.toString(operandTuple, operatorTuple)); } catch (Exception e) { } // skip when modulo is not zero in a division for (String expression : resultSet) System.out.println(expression); } private static int[] promptInput() { int[] input = new int[4]; BufferedReader reader = null; String line = null; try { reader = new BufferedReader(new InputStreamReader(System.in)); for (int i = 0; i < 4; ++i) { System.out.print("Enter a number (1 to 13): "); line = reader.readLine(); try { input[i] = Integer.parseInt(line); if (input[i] < 1 || input[i] > 13) throw new IllegalArgumentException(); } catch (IllegalArgumentException e) { System.out.println("The input is invalid. Please try again."); --i; } } } catch (Exception e) { // ignore other exceptions } return input; } // print N! permutation of the elements of array a (not in order) private void permutateOperand() { int[] indices = new int[] { 0, 1, 2, 3 }; permutateOperand(indices, indices.length); } private void permutateOperand(int[] array, int length) { if (length == 1) { this.operandTupleSet.add(new OperandTuple( this.inputOperand[array[0]], this.inputOperand[array[1]], this.inputOperand[array[2]], this.inputOperand[array[3]])); return; } for (int i = 0; i < length; i++) { swap(array, i, length - 1); permutateOperand(array, length - 1); swap(array, i, length - 1); } } // swap the numbers at indices i and j private static void swap(int[] array, int i, int j) { int temp; temp = array[i]; array[i] = array[j]; array[j] = temp; } }
OperandTuple.java:
import java.util.Arrays; import java.util.Iterator; public class OperandTuple implements Iterable<Integer> { private Integer[] numbers; public OperandTuple(int first, int second, int third, int fourth) { this.numbers = new Integer[4]; this.numbers[0] = first; this.numbers[1] = second; this.numbers[2] = third; this.numbers[3] = fourth; } public int get(int index) { return this.numbers[index]; } @Override public boolean equals(Object obj) { if (obj instanceof OperandTuple) { OperandTuple rhs = (OperandTuple) obj; return Arrays.equals(this.numbers, rhs.numbers); } return false; } @Override public int hashCode() { return Arrays.hashCode(this.numbers); } public Iterator<Integer> iterator() { return Arrays.asList(this.numbers).iterator(); } }
OperatorTuple.java:
import java.util.Arrays; import java.util.Iterator; public class OperatorTuple implements Iterable<Operator> { private Operator[] operators; public OperatorTuple(Operator first, Operator second, Operator third) { this.operators = new Operator[3]; this.operators[0] = first; this.operators[1] = second; this.operators[2] = third; } public Operator get(int index) { return this.operators[index]; } @Override public boolean equals(Object obj) { if (obj instanceof OperatorTuple) { OperatorTuple rhs = (OperatorTuple) obj; return Arrays.equals(this.operators, rhs.operators); } return false; } @Override public int hashCode() { return Arrays.hashCode(this.operators); } public Iterator<Operator> iterator() { return Arrays.asList(this.operators).iterator(); } }
Operator.java:
public enum Operator { Add("+", 1) { int invoke(int first, int second) { return first + second; } }, Minus("-", 1) { int invoke(int first, int second) { return first - second; } }, Multiply("*", 2) { int invoke(int first, int second) { return first * second; } }, Divide("/", 2) { int invoke(int first, int second) { if (!canDivide(first, second)) throw new CannotDivideException(first + ", " + second); return first / second; } }; private String opChar; private int precedence; Operator(String opChar, int precedence) { this.opChar = opChar; this.precedence = precedence; } abstract int invoke(int first, int second); @Override public String toString() { return this.opChar; } public int getPrecedence() { return this.precedence; } public static boolean canDivide(int first, int second) { return (first % second) == 0; } }
Evaluator.java:
public enum Evaluator { TYPE1 { // num1 num2 num3 num4 op1 op2 op3 public int eval(OperandTuple nums, OperatorTuple ops) { return ops.get(2).invoke(nums.get(0), ops.get(1).invoke(nums.get(1), ops.get(0).invoke(nums.get(2), nums.get(3)))); } public String toString(OperandTuple nums, OperatorTuple ops) { return (nums.get(0) + " " + nums.get(1) + " " + nums.get(2) + " " + nums.get(3) + " " + ops.get(0) + " " + ops.get(1) + " " + ops.get(2)); } }, TYPE2{ // num1 num2 num3 op1 num4 op2 op3 public int eval(OperandTuple nums, OperatorTuple ops) { return ops.get(2).invoke(nums.get(0), ops.get(1).invoke(ops.get(0).invoke(nums.get(1), nums.get(2)), nums.get(3))); } public String toString(OperandTuple nums, OperatorTuple ops) { return (nums.get(0) + " " + nums.get(1) + " " + nums.get(2) + " " + ops.get(0) + " " + nums.get(3) + " " + ops.get(1) + " " + ops.get(2)); } }, TYPE3{ // num1 num2 num3 op1 op2 num4 op3 public int eval(OperandTuple nums, OperatorTuple ops) { return ops.get(2).invoke(ops.get(1).invoke(nums.get(0), ops.get(0).invoke(nums.get(1), nums.get(2))), nums.get(3)); } public String toString(OperandTuple nums, OperatorTuple ops) { return (nums.get(0) + " " + nums.get(1) + " " + nums.get(2) + " " + ops.get(0) + " " + ops.get(1) + " " + nums.get(3) + " " + ops.get(2)); } }, TYPE4{ // num1 num2 op1 num3 num4 op2 op3 public int eval(OperandTuple nums, OperatorTuple ops) { return ops.get(2).invoke(ops.get(0).invoke(nums.get(0), nums.get(1)), ops.get(1).invoke(nums.get(2), nums.get(3))); } public String toString(OperandTuple nums, OperatorTuple ops) { return (nums.get(0) + " " + nums.get(1) + " " + ops.get(0) + " " + nums.get(2) + " " + nums.get(3) + " " + ops.get(1) + " " + ops.get(2)); } }, TYPE5{ // num1 num2 op1 num3 op2 num4 op3 public int eval(OperandTuple nums, OperatorTuple ops) { return ops.get(2).invoke(ops.get(1).invoke(ops.get(0).invoke(nums.get(0), nums.get(1)), nums.get(2)), nums.get(3)); } public String toString(OperandTuple nums, OperatorTuple ops) { return (nums.get(0) + " " + nums.get(1) + " " + ops.get(0) + " " + nums.get(2) + " " + ops.get(1) + " " + nums.get(3) + " " + ops.get(2)); } }; abstract public int eval(OperandTuple nums, OperatorTuple ops); abstract public String toString(OperandTuple nums, OperatorTuple ops); }
CannotDivideException.java:
public class CannotDivideException extends RuntimeException { private static final long serialVersionUID = -9174448473262875939L; public CannotDivideException() { super(); } public CannotDivideException(String message) { super(message); } }
评论
3 楼
RednaxelaFX
2008-08-11
在CodeProject上看到另一种更受限制的24点问题,和对应的一种解:The 24 Puzzle
2 楼
RednaxelaFX
2008-04-09
我这也是傻瓜型的……总之算法什么的完全跟“优化”沾不上边。只是做了:
1、充分使用Java的语法
2、使用面向对象的“壳”……骨子里嘛,嘛rev1的代码比昨天的稍微好点吧。
1、充分使用Java的语法
2、使用面向对象的“壳”……骨子里嘛,嘛rev1的代码比昨天的稍微好点吧。
1 楼
jhpx
2008-04-09
偶以前用C写过一个递归的傻瓜型24点……
发表评论
-
The Prehistory of Java, HotSpot and Train
2014-06-02 08:18 0http://cs.gmu.edu/cne/itcore/vi ... -
MSJVM and Sun 1.0.x/1.1.x
2014-05-20 18:50 0当年的survey paper: http://www.sym ... -
Sun JDK1.4.2_28有TieredCompilation
2014-05-12 08:48 0原来以前Sun的JDK 1.4.2 update 28就已经有 ... -
IBM JVM notes (2014 ver)
2014-05-11 07:16 0Sovereign JIT http://publib.bou ... -
class data sharing by Apple
2014-03-28 05:17 0class data sharing is implement ... -
Java 8与静态工具类
2014-03-19 08:43 16273以前要在Java里实现所谓“静态工具类”(static uti ... -
Java 8的default method与method resolution
2014-03-19 02:23 10450先看看下面这个代码例子, interface IFoo { ... -
HotSpot Server VM与Server Class Machine
2014-02-18 13:21 0HotSpot VM历来有Client VM与Server V ... -
Java 8的lambda表达式在OpenJDK8中的实现
2014-02-04 12:08 0三月份JDK8就要发布首发了,现在JDK8 release c ... -
GC stack map与deopt stack map的异同
2014-01-08 09:56 0两者之间不并存在包含关系。它们有交集,但也各自有特别的地方。 ... -
HotSpot Server Compiler与data-flow analysis
2014-01-07 17:41 0http://en.wikipedia.org/wiki/Da ... -
字符串的一般封装方式的内存布局 (1): 元数据与字符串内容,整体还是分离?
2013-11-07 17:44 22388(Disclaimer:未经许可请 ... -
字符串的一般封装方式的内存布局
2013-11-01 12:55 0(Disclaimer:未经许可请 ... -
关于string,内存布局,C++ std::string,CoW
2013-10-30 20:45 0(Disclaimer:未经许可请 ... -
对C语义的for循环的基本代码生成模式
2013-10-19 23:12 21870之前有同学在做龙书(第二版)题目,做到8.4的练习,跟我对答案 ... -
Java的instanceof是如何实现的
2013-09-22 16:57 0Java语言规范,Java SE 7版 http://docs ... -
oop、klass、handle的关系
2013-07-30 17:34 0oopDesc及其子类的实例 oop : oopDesc* ... -
Nashorn各种笔记
2013-07-15 17:03 0http://bits.netbeans.org/netbea ... -
《深入理解Java虚拟机(第二版)》书评
2013-07-08 19:19 0值得推荐的中文Java虚拟机入门书 感谢作者赠与的样书,以下 ... -
豆列:从表到里学习JVM实现
2013-06-13 14:13 48357刚写了个学习JVM用的豆列跟大家分享。 豆列地址:http: ...
相关推荐
在编程领域,"C++算24点代码穷举实现"是一个典型的数学和算法问题,它涉及到使用C++编程语言来解决24点游戏。24点游戏是一种流行的心算游戏,玩家需要从四张1到13的扑克牌中通过加、减、乘、除运算得出24这个结果。...
在编程领域,"穷举组合法计算24点"是一个有趣的算法问题,它涉及到数学、逻辑和编程技巧。24点游戏是大家都熟知的一种智力游戏,玩家需要利用四张牌上的数字,通过加减乘除四则运算以及括号来得到结果24。在这个问题...
本文将深入探讨如何使用C语言实现24点游戏的穷举法。24点游戏是一种数学智力游戏,玩家需要从四张1到13之间的扑克牌中,通过加、减、乘、除和括号的操作,使得结果等于24。 首先,我们需要理解游戏规则。四张牌可以...
标题中的“还是24点……前两个都有问题……”暗示了这是一个关于解决24点游戏的问题,其中前两种尝试可能存在不足或错误。24点游戏是一个流行的心算游戏,玩家需要使用加减乘除四种基本运算,以及括号来重新组合给定...
15.6 应用…………………………………………………………………………………………………………227 〖案例l〗果园篱笆………………………………………………………………227 〖案例2〗巨人和鬼………………...
穷举破解24点游戏
24点算法是一种基于四则运算的...总的来说,24点算法的C++实现涉及了数据结构(堆栈)、算法(穷举搜索、后缀表达式求值)以及基本的逻辑判断。这种编程挑战有助于提升对数值计算、逻辑控制和数据结构的理解与运用。
自己用粗暴的穷举法实现的八皇后,代码浅显易懂,对初学者应该有帮助。
给定4个整数,其中每个数字只能使用一次;任意使用 + - * / ( ) ,构造出一个表达式,使得最终结果为24,这就是常见的算24点的游戏。这方面的程序很多,一般都是穷举求解。本程序通过递归算法实现实现24点计算,
0-1整数规划有很广泛的应用背景,比如指派问题,背包问题等等,实际上TSP问题也是一个0-1问题,当然这些问题都是NP问题,对于规模较大的问题用穷举法是没有办法在可接受的时间内求得最优解的,本程序只不过是一个...
在编程领域,穷举法是一种常见的解决问题的策略,尤其在C和C++这两种语言中,开发者经常使用这种方法来实现特定的算法。穷举法,也称为全搜索或枚举,是指在解决一个问题时,尝试所有可能的情况,直到找到正确答案。...
### 知识点解析 #### 一、穷举算法简介 穷举算法是一种通过尝试所有可能情况来寻找问题最优解的算法。它适用于问题规模较小的情况,在这些情况下,计算机能够快速处理并找到最佳解决方案。虽然穷举算法在解决大...
标签"穷举目录 穷举文件"再次强调了这个程序的主要任务,即遍历目录结构并列举出所有文件。在实际的编程实践中,这通常涉及到递归算法,因为要处理无限深度的子目录结构。 压缩包内的文件名列表提供了更多关于程序...
根据提供的文件信息,本文将详细解析“穷举法求解0-1整数规划的MATLAB程序”的核心知识点,包括穷举法的基本概念、在0-1整数规划中的应用以及MATLAB实现方法。 ### 一、穷举法概述 穷举法(Exhaustive Search ...
用穷举法求解n皇后问题
标题与描述中的关键词“穷举法代码解析带注释”明确指出本文将深入探讨穷举法的基本原理、代码实现以及具体应用案例。穷举法,作为一种基础而有效的算法策略,被广泛应用于解决特定类型的问题,尤其是在面对有限解...
四、穷举的实现技巧 1. 递归:适合于结构清晰、状态转移明确的问题,如回溯法。 2. 循环:对于有序或无序集合,可以用循环结构进行枚举。 3. 广度优先搜索(BFS)和深度优先搜索(DFS):在图和树结构中应用广泛,...
MATLAB优化算法案例分析与应用(进阶篇)1-10章程序下载
通常,穷举法需要用多重循环来实现。在程序实现时,需要考虑穷举范围和约束条件。这两点是穷举法的关键步骤。 本章节还提供了几个实例来说明穷举法的应用。例如,换钱问题、水仙花数问题和数独游戏问题。这些实例...
### 如何实现24点计算 #### 知识点概览 本文主要介绍了一种实现24点游戏计算的方法,并提供了详细的算法分析及C++语言的实现思路。24点是一种数学益智游戏,通常玩家需要利用加减乘除四则运算以及括号,将随机给出...