坚持使用大型阵列以便更快地访问

时间:2010-02-04 20:14:01

标签: java

我有一个5维数组,其中所有指标的范围都是2-14。它包含5个数字序列的所有可能排列。 该阵列保持525720个排列,计算需要相当长的时间。 (在我的Macbook专业版上5-7秒)。它应该用作查找表,以恒定时间访问值,或者更具体地说,某个扑克牌的值:

array[2][3][4][5][7] // 1
array[5][5][5][5][14] // 2000

有没有更快的方法来创建这个数组?我正在考虑以某种方式持久化数组,然后在每次程序启动时加载它 - 但有没有有效的方法来执行此操作?

我对持久性不是很熟悉。我真的不知道它是否适合我,从磁盘加载它,而不是每次都创建它。我知道Hibernate,但这似乎有点过分,只是坚持一个阵列?

7 个答案:

答案 0 :(得分:2)

通过MappedByteBuffer写出来。创建一个足够大的文件,映射它,得到一个asIntBuffer(),输入你的数字。

然后你可以稍后映射它并通过IntBuffer.get(明显的数学索引)访问它。

序列化的速度要快得多。

答案 1 :(得分:2)

我首先要将您的维度折叠起来进行索引:

假设您有一组索引(从第一个示例开始,允许的值为2到14):

 i1 = 2
 i2 = 3
 i3 = 5
 i4 = 6
 i5 = 7

并使用

创建了数组
 short array[] = new short[13 * 13 * 13 * 13 * 13];
 ...

然后访问每个元素

 array[(i1 - 2) * 13 * 13 * 13 * 13 + (i2 - 2) * 13 * 13 * 13 + (i3 - 2)
     * 13 * 13 + (i4 - 2) * 13 + (i5 - 2)]

此阵列将占用更少的内存,因为您不需要在每个维度上创建额外的对象层,并且您可以轻松地将整个内容存储在一个文件中并将其加载到一个列表中。

遍历此数组也会更快,因为您将进行1/5的数组查找。

此外,每个维度中元素数量的收紧将节省大量内存。

为了保持代码清洁,这个数组应该隐藏在一个带有get和set方法的对象中,该方法需要五个索引。

答案 2 :(得分:2)

不是您原来问题的直接答案,但是......

如果您正在尝试进行快速的扑克手评估,您需要确保通读The Great Poker Hand Evaluator Roundup

特别是:Cactus Kev's Poker Hand Evaluator

我参与了关于运行最快的5和7手扑克评估的长期讨论,其中大部分内容都来自于此。坦率地说,直到你可以在查找表中保存所有C(52,5)或2,598,960手值之前,我看不出这些评估会如何更快。

答案 3 :(得分:1)

您可能想要做的是,如果数组的计算过于昂贵,则将其序列化。这基本上将数据的二进制副本放到您可以非常快速加载的存储介质(例如您的硬盘)上。

序列化非常简单。这是专门针对序列化数组的a tutorial

由于这些值可能只会在您评估扑克牌的算法发生变化时发生变化,因此只需运送序列化文件即可。如果您存储在每个数组元素中的数据不是太大(例如,如果它是一个16位整数,文件大小约为1MB),则文件大小应该合理。

答案 4 :(得分:1)

我不相信你的扑克牌数量排列是正确的,但无论如何......

通过同时存储给定扑克牌的每个排列,您可以使阵列初始化大约快120倍。这是有效的,因为扑克牌的“价值”不受牌顺序的影响。

首先计算一只手的值。假设您有五张牌(c1,c2,c3,c4,c5):

handValue = EvaluateHand(c1, c2, c3, c4, c5);

// Store the pre-calculated hand value in a table for faster lookup
hand[c1][c2][c3][c4][c5] = handValue;

然后将handValue分配给该手的所有排列(即卡的顺序不会改变handValue)。

hand[c1][c2][c3][c5][c4] = handValue;
hand[c1][c2][c4][c3][c5] = handValue;
hand[c1][c2][c4][c5][c3] = handValue;
hand[c1][c2][c5][c3][c4] = handValue;
hand[c1][c2][c5][c4][c3] = handValue;
:
etc.
:
hand[c5][c4][c3][c2][c1] = handValue;

答案 5 :(得分:0)

一些事情:

如果这是扑克手,你不能只存储2-14。您还需要存放该套装。这实际上意味着您需要存储0-51。否则你无法知道array[2][3][4][5][6]是直的还是同花顺。

如果您实际上不需要为您的应用程序存储套装,并且您确实想要在数组中执行它,请使用0-12而不是2-14的索引。这将允许您使用13×13×13×13×13(371,293成员)阵列,而不是15×15×15×15×15(759,375成员)阵列。无论何时访问数组,您只需要从每个索引中减去2。 (我不确定你的525,720计数在哪里......)

答案 6 :(得分:0)

首先,感谢您的热情!

所以直接的方法似乎只是序列化它。我想我会首先尝试这个,测试性能,看看它是否足够。 (我猜是这样的)。

关于MappedByteBuffer ...是否正确理解,这使得加载序列化数组的一小部分成为可能?所以我在运行时加载了我需要的值,而不是在启动时加载整个数组?

@Jennie 套装存储在不同的阵列中。我不确定这是最好的方法,因为有很多东西要考虑这个特殊的问题。同花顺基本上是一张高牌,具有不同的价值......所以我没有真正的理由两次存储相同的排列(高牌),但这是现在的方法。我认为要走的路是散列函数,所以我可以很容易地将高卡值转换为flush值,但我没有给出这么多想法。

关于这些指标,你当然是对的。这只是暂时的。我现在更容易测试“2 3 4 5 6”的值,只需输入卡值即可...稍后,我将切割数组!