我想存储键值对,其中键是整数,值ArrayLists
是Strings
.
我不能使用数据库,因为我必须使用代码在线解决特定比赛的问题。
对于少量数据,我可以毫无问题地使用哈希表。但是当我的数据变大时,我的堆大小就用完了。我无法更改堆大小,因为我只需要上传代码并且无法提供工作环境。这就是挑战。
我想存储键值对,其中键是整数,值ArrayLists
是Strings
.
我不能使用数据库,因为我必须使用代码在线解决特定比赛的问题。
对于少量数据,我可以毫无问题地使用哈希表。但是当我的数据变大时,我的堆大小就用完了。我无法更改堆大小,因为我只需要上传代码并且无法提供工作环境。这就是挑战。
如果字符串经常重复,具有自然语言频率,请不要为同一字符串使用新的对象实例。
private Map<String, String> sharedStrings = new HashMap<>().
public void shareString(String s) {
String t = sharedStrings.get(s);
if (t == null) {
t = s;
sharedStrings.put(t, t);
}
return t;
}
字符串的编号可能太慢了。
将字符串列表打包成一个(分隔一些控制字符),并可能对字符串进行 Gzip 压缩(GZipOutputStream、GZipInputStream)。
使用足够的初始容量调整哈希图。(对不起,如果我说的很明显。)
使用巨大的 large 对所有 ArrayList 进行自己的分配String[]
:
int count;
String[] allStrings = new String[999999];
Map<Integer, Long> map = new HashMap<>(9999);
void put(int key, List<String> strings) {
int start = count;
for (String s : strings) {
allStrings[count] = s;
++count;
}
// high: start index, low: size
long listDescriptor = (((long)start) << 32) | (count - start);
map.put(key, listDescriptor);
}
有使用 int 和 long 等原语的地图实现;例如trove库(我自己没有使用它)。
使用简单的数组代替ArrayList
可能会节省一些额外的内存(但不多)。
如果搜索性能不是优先考虑的,您可以使用 aPair<Integer, List<>>
并手动进行搜索。
如果整数的范围有限,只需实例化一个数组List[integer_range]
并使用数组索引作为键。
由于您正在使用Strings
,您可以尝试使用intern()
它们并确保没有重复值。
让我们知道有关您拥有的数据的哪些统计信息 - 键是什么,值是否重复,等等。
一种可能的优化可能是 ArrayList.trimToSize,它将 ArrayList 使用的存储减少到最低限度。
一些想法
如果您可以写入文件,则将数据存储在那里。您可以将键保存在内存中的一组中,以便更快地查找,只需将值写出 - 可以写入单个文件,甚至可以写入每个条目的文件。
创建您自己的映射实现,将值列表序列化为 String 或 byte[],然后压缩序列化数据。您必须在读取时反序列化。不过,每次执行 get/put 时,都会受到很大的运行时影响。有关示例,请参见http://theplateisbad.blogspot.co.uk/2011/04/java-in-memory-compression.html 。
每次查找地图数据时,只需计算列表值,而不是存储它们 - 如果可以的话。
您可以将 ArrayList 存储在序列化(甚至可能压缩)的ByteBuffers中。当您需要访问列表时,您需要对其进行反序列化、更改/读取,然后将其存储回来。
操作会明显变慢,但您可以进行一些缓存以将 X Arraylists 保留在堆中并将其余部分存储在外部。
如果您不能增加堆大小,那么您需要限制哈希表(或您使用的任何其他数据结构)的大小。我建议尝试Apache LRUMap:
LRU地图
Map 的一种实现,它具有最大大小,并在达到最大大小并添加新项目时使用最近最少使用算法从 Map 中删除项目。
如果您真的需要同步版本,那么也可以使用:
可以通过以下方式获得同步版本: Collections.synchronizedMap( theMapToSynchronize ) 如果它将被多个线程访问,则必须同步访问此 Map。甚至并发的 get(Object) 操作也会产生不确定的行为。
如果你不想使用 LRU 来丢失数据,那么你需要编写一个算法来将一些数据保存在你的数据结构中,并保留在持久性存储中,例如文件等。