2015-12-22 44 views
3

我有这样一个简单的嵌套结构。 (这是简化的实际问题的版本他们中的一些实际使用的hash_set。)Java:通过大量半常数标志检查来优化循环循环?

class A{ AF a_field; B[] bs;} 
class B{ BF b_field; C[] cs;} 
class C{ CF c_field; D[] ds;} 
class D{ DF d_field; } 
static A[] as; // loosely speaking, it has about 4000 D 

一个伪码法“F”看起来可能是复杂的,但它是很容易理解: -

int f(int TYPE){ //TYPE is 0 - 40 
    int retur=0; 
    for(int n=0;n<as.length;n++){ 
    . if(some cheap condition of TYPE){ //use only "TYPE" , cheap (1) 
    . . as[n].a_field.doExpensiveAA(); //expensive OPERATION, use only "a_field" (Ex retur+=a_field) 
    . }else if(some cheap condition of TYPE){ //use only "TYPE" (2) 
    . . as[n].a_field.doExpensiveAB(); //expensive OPERATION, use only "a_field" (Ex retur-=a_field) 
    . } // .... and a lot of them 
    . for(int m=0;m<bs.length;m++){ 
    . . if(some cheap condition of TYPE){ //use only "TYPE" (3) 
    . . . as[n].bs[m].b_field.doExpensiveBA(); (*)//use only "b_field" 
    . . }else if(some cheap condition of TYPE){//use only "TYPE" (4) 
    . . . as[n].bs[m].b_field.doExpensiveBB(); (/) //use only "b_field" 
    . . } // .... and a lot of them 
    . . for(..cs ..){...for(...ds...) {...}...} 
    . } 
    } 
} 

(我拼命地添加缩进。)

“f” 被称为在每个时间步长: -

public static void caller(){ 
    for(int n=0;n<40;n++){ f(n); } 
} 

请注意,TYPE只是用于条件检查的变量,对于单个“f”调用而言它是不变的。

虽然每个条件检查确实很便宜,但是当它位于最内层循环时,它会花费很多CPU周期。如何优化“呼叫者”和/或“F”?

我的想法是

  1. 展开“F”为每一个“类型”,但会有很多肮脏的代码是很难维持......这样......

    (); f2(); f3(); f1(); f2(); f3(); f1(); f2(); f3(); ... f40(); }

  2. 使用开关盒!它比if-else更快,但是0到40的开关箱很丑。条件不能像“检查TYPE的奇数/偶数”那样分组,因此代码的可维护性较低。

编辑1(应答帕塔Sarathi戈什):检查位只是例子,所以位的指标是不重要的,它甚至可以“> 8”,只是要注意,所有的条件是依赖于类型。

编辑2:+ - * /只是一个例子,它是一个使用a_field,b_field等的任意函数(真实情况是在Opengl中设置3D纹理或系统变量)... cs。 ..和... ds ...是类似但不同的昂贵操作。

编辑3:添加信息 “A []为” 包含有关4000 d

编辑4(回答帕塔Sarathi戈什):从int编辑xxx_field的类型,以显示它们是不同的类。

+1

在第二个for循环使用的内部使用了'if(“TYPE的最后一位是1”)和'else if(“TYPE的第二个最后一位是0”)是否有任何错误? –

+1

而且,您还将'...... as ......'用作'retur + = as [n] .a_field'和'retur * = as [n] .a_field'。但'retur- = as [n] .bs [m] .b_field'和'retur/= as [n] .bs [m] .b_field'为'... bs ...'。那么对于'..cs ...'和其他所有人来说,会是什么? –

+2

这意味着你只有相同的结构数据(包装在不同的类中)。但是所有这些数据都是相互嵌套的。现在取决于一个标志变量说类型,你需要在不同的水平上执行不同的操作。但是对于单一类型,您需要针对特定​​级别执行特定操作,而不是其他级别的权限? –

回答

2

您需要将函数作为参数传递给递归函数。我在准备基本算法的时候看到这个post

您还需要使用自定义标记接口以相同的递归方法传递这些不同类型的数据。

这是您的示例程序。

import java.util.List; 
import java.util.ArrayList; 



/** The Invoker class */ 
class Switch { 
    List<Command> commandList = new ArrayList<Command>(); 
    Switch() { 
     commandList.add(new IncreementCommand()); //Level 1 Operation 
     commandList.add(new MultipleCommand()); 
     commandList.add(new DecrementCommand()); 
     //If level 4 need same operation like level 1 
     commandList.add(new IncreementCommand()); 

    } 

    public int execute(CustomMarker a, int lvl){ 
     int rtr = 0; 
     Command cmd = commandList.get(lvl-1); //Level 1 means 1st operation 
     return execute(a, lvl, rtr, cmd); 
    } 


    /** The Command interface */ 
    interface Command { 
     int execute(int data, int rtr); 
    } 

    private int execute(CustomMarker a, int lvl, int rtr, Command cmd){ 
     if(lvl == 0){ 
      return cmd.execute(a.getData(), rtr); 
     } 
     else { 
      lvl--; 
      if(a.getSubData() != null && a.getSubData().length>0){ 
       for (int i = 0; i < a.getSubData().length; i++) { 
       rtr = execute(a.getSubData()[i], lvl, rtr, cmd); 
       } 
      } 
      return rtr; 
     } 
    } 

    //Inner classes 
    class IncreementCommand implements Command { 
     @Override // Command 
     public int execute(int data, int rtr) { 
      return rtr+data; 
     } 
    } 

    /** The Command for turning off the light - ConcreteCommand #2 */ 
    class MultipleCommand implements Command { 
     @Override // Command 
     public int execute(int data, int rtr) { 
      return rtr*data; 
     } 
    } 

    /** The Command for turning off the light - ConcreteCommand #2 */ 
    class DecrementCommand implements Command { 
     @Override // Command 
     public int execute(int data, int rtr) { 
      return rtr-data; 
     } 
    } 
} 

/** The Custom Marker interface */ 
interface CustomMarker { 
    //It will return your int a_field or b_field 
    public int getData(); 
    public CustomMarker[] getSubData(); 
} 


//Level 1 
class A implements CustomMarker { int a_field; B[] bs; 
    public int getData() { 
     return a_field; 
    } 
    public CustomMarker[] getSubData() { 
     return bs; 
    } 
} 
//Level 2 
class B implements CustomMarker { int b_field; C[] cs; 
    public int getData() { 
     return b_field; 
    } 
    public CustomMarker[] getSubData() { 
     return cs; 
    } 
} 
//Level 3 
class C implements CustomMarker { int c_field; D[] ds; 
    public int getData() { 
     return c_field; 
    } 
    public CustomMarker[] getSubData() { 
     return ds; 
    } 
} 
//Level 4 
class D implements CustomMarker { int d_field; 
    public int getData() { 
     return d_field; 
    } 
    public CustomMarker[] getSubData() { 
     return null; 
    } 
} 


/* The test class or client */ 
public class TestClass { 
    static A[] as; 
    public static void main(String[] args){ 



     CustomMarker topLevel = new CustomMarker() { 
     @Override 
     public int getData() { 
      // TODO Auto-generated method stub 
      return 0; 
     } 
     @Override 
     public CustomMarker[] getSubData() { 
      return as; 
     } 
     }; 

     Switch mySwitch = new Switch(); 
     for(int n=1;n<=3;n++){ 
      mySwitch.execute(topLevel, n); 
     } 
    } 
} 

在这个程序中我已经使用相同的数据类型为a_field和为int。 但是你可以用Object来试试它。所以在每个操作中执行block typecast它。如果程序可以正确处理关卡及其类型,则不需要在类型转换之前进行检查。

我已最小化操作到41次只。 40操作和+ 1开关(操作控制器)。

编辑:更新了Switch类的执行公共方法,复制粘贴的错误在那里。

+0

在准备答案时,您是否可以避免创建(“新”)很多对象?像C++那样传递函数指针似乎很酷,但是我没有找到一种没有很多“新”调用的方法。我相信“新”会让Java变慢。 A []“as”有大约4000个D对象,在每个时间步中创建4000个函数指针可能不是那么好...不确定...谢谢。 – javaLover

+0

更新了一个示例程序,让我知道如果你有难以理解的逻辑。 –

+0

你也可以通过反射来完成这个程序。为创建40个不同的内部类而创建,你可以在Switch类中创建40个方法。然后你可以在CollandList(String of List)中获取这些方法的名称,然后通过Reflection getMethod找到该方法。然后执行它。但我认为用反思进行工作是昂贵的。 –