表示给定范围内所有数字的最佳方法是什么? (一些限制)

时间:2017-10-23 23:55:31

标签: java multithreading algorithm recursion

背景:创建一个类似于Mastermind但类固醇的游戏。目前正在尝试优化AI并增加我的极限。让我解释一下:

对于我的AI算法,我需要生成某种数据结构,它可以表示给定0的所有可能数字 - 一个限制。我还需要从这种结构中删除数字以反映可能的数字。

现在在我的游戏中我使用List代表一个数字本身。这样我可以像任何基地一样,根据游戏中的事件,我可以为这样的数字添加一个数字。我知道这不是解决这个问题的最佳方式,但对于游戏而言,人工智能是完成所有繁重工作的地方。

我创建了一种方法来获得ArrayList>但问题是当限制变得大于Integer.MAX_VALUE时,我遇到很多问题导致程序冻结等等,并且还会导致巨大的内存问题。 我提取了一些代码,显示我当前是如何生成所有序列的。我也刚刚实现了多线程的糟糕工作,所以你们不必在运行代码时等待很长时间:

public class Recursive {

    private static List<List<Integer>> allSeqL = new ArrayList<List<Integer>>();
    private static final Object addPossibleSequenceLock = new Object();
    public static void main(String[] args){

        //Create Digits
        List<Integer> digits = new ArrayList<Integer>();
        int index = 0;
        while(10 > index){
            digits.add(index);
            index++;
        }
        System.out.println(digits.size()+"SIZE OF DIGITS");

        //Get Amount of Threads to run at once
        int recommendedAmountWT = Runtime.getRuntime().availableProcessors()*3/4;

        //Create Working List
        List<Thread> workTL = new ArrayList<Thread>();
        for(Integer number : digits){
            Thread t = new Thread(new Runnable(){
                private int number;
                private List<Integer> digits;
                public void run(){
                    int sizeOfSequence = 10;
                    boolean dupAllowed = true;
                    Integer[] sequence = new Integer[sizeOfSequence];
                    sequence[0] = number;
                    if(dupAllowed){
                        Recursive.recursiveAllPossible(new ArrayList<Integer>(digits), sequence, 1, dupAllowed);
                    }   else{
                        digits.remove(new Integer(number));
                        Recursive.recursiveAllPossible(digits, sequence, 1, dupAllowed);
                    }
                }
                public Runnable init(int number, List<Integer> digits){
                    this.number = number;
                    this.digits = digits;
                    return this;
                }
            }.init(number, new ArrayList<Integer>(digits)));
            workTL.add(t);
        }


        System.out.println(workTL.size()+"SIZE WORKTL");

        //Run only Recommended amount of work threads at once
        List<Thread> tempTL = new ArrayList<Thread>();
        while(workTL.size() != 0){
            int startThread = 0;
            while(workTL.size() != 0 && recommendedAmountWT > startThread){
                Thread t1 = workTL.get(0);
                tempTL.add(t1);
                workTL.remove(t1);
                startThread++;
                t1.start();
            }
            System.out.println(startThread);
            System.out.println(tempTL.size());
            System.out.println("##########################");
            for(Thread t : tempTL){
                try {
                    t.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            tempTL.clear();
        }
        System.out.println("TOTAL ALLSEQL: "+Recursive.allSeqL.size());
    }


    private static void recursiveAllPossible(List<Integer> digits, Integer[] sequence, int index, boolean dupAllowed){
        for(Integer number : digits){
            sequence[index] = number;
            if(sequence.length-1 > index){
                List<Integer> newPositionL = new ArrayList<Integer>(digits);
                if(!dupAllowed){
                    newPositionL.remove(number);
                }
                Recursive.recursiveAllPossible(newPositionL, sequence, new Integer(index+1), dupAllowed);
            }   else{
                Recursive.addToL(Arrays.asList(sequence));
            }
        }
    }

    /**
     * Method : Add to all sequence List
     * @param sequence : Sequence being added
     * Reason this has a lock is because when creating this list there are multiple threads
     */
    public static void addToL(List<Integer> sequence){
        synchronized(Recursive.addPossibleSequenceLock){
            Recursive.allSeqL.add(sequence);
            System.out.println(sequence);
        }
    }
}

基本上这可以通过将数字的数字设置为序列数组的索引,循环直到它不能再设置,然后将它添加到所有序列列表。然后它循环回到前一个并查看是否有另一个要添加的数字。添加和重复。

与其他游戏相比,AI真的不必遵循List格式。但是,为了比较数字,我必须将任何内容转换为List或重写我的Result类,但我宁愿不这样做。

所以我应该感谢你应该做些什么来解决这个问题。 我想出的解决方案是实现某种树。说实话,虽然我对树木了解不多,但对此并不自信。 另一种解决方案是在使用新序列到达Integer.MAX_VALUE时创建一个新的ArrayList,但这看起来好像我将在地毯下扫描问题。

第三个解决方案是使用LinkedList,但仍然可以说(我试过这个)。

2 个答案:

答案 0 :(得分:1)

考虑到问题的大小,您是否考虑过使用稀疏矩阵?

我想也许你可以代表一个不相连的非连续数字列表  只是一个范围列表:

my_ranges = [(0,10),(12,1500),(1502,25000000)]

这样,当你需要删除一个数字时你可以(某些pythonic伪代码):

insert():
for subrange in my_ranges:
   if 27 in my_ranges:
       # do nothing
   else:
       # build intermediate ranges with 27 included
return new_ranges

delete():
for subrange in my_ranges:
   if 27 in my_ranges:
       # split this range into two ranges, before and after 27
return new_ranges


exists():
for subrange in my_ranges:
   if 27 in my_ranges:
       return 1
return return 0

通过这种方式,您可以解决代表大量数字的问题,但有一些例外情况,而不会实际耗尽内存。

或者,您可以使用稀疏矩阵:)。

答案 1 :(得分:1)

我曾经做过一个可能对你的问题感兴趣的收藏课。

它充当Set<Long>,但它使用非常有效的内部表示,具有良好的空间/时间权衡。

关键的想法是存储连续的范围,更准确地说是存储功能&#34;包含的数字&#34;改变价值。在最坏的情况下,大小与元素的数量成比例,当元素代表棋盘(1,3,5,7,9等)时会发生,但即使在这种情况下,它仍然只是N.空并且全集具有恒定大小1.范围10000-30000的大小为2而不是20000等。否则,在添加/删除值时,会动态合并和分割范围。

该类支持标准集操作,例如intesection,union等。根据我的经验,它工作得很好,但我可能没有你那么多的要求。在实践中,&#34; delta点的数量&#34;仍然受到java Integer.MAX_VALUE的限制,但将其扩展到Long.MAX_VALUE甚至BigInteger是相当简单的。

要解决您的问题,您应该观察数据中的模式。模式是否随机?这些值是否已本地化?等等。不同的用法需要不同的数据结构和算法,具有不同的权衡。如果您刚刚开始,请查看Google Guava项目中的HashSetTreeSet或馆藏以帮助您前进,然后查找数据中的模式。还有一些概率结构,例如您可能觉得有用的Bloom过滤器。最终,您在实际数据中观察到的模式将为您提供最佳答案。