一些背景
我正在解决一个问题,我将集合存储在hashmap中,其中键是集合名,即Set1--
该程序的目的是从用户那里取一个值作为“阈值”,即2,它用于集合之间的最小共性。如果达到或超过阈值,程序建议集合之间合并。
我已经创建了一个组合生成器,它将生成集合名称之间的所有可能组合,以便与未考虑的顺序进行比较,即(Set1,Set2,),(Set1,Set3),(Set2,Set3),(Set1,Set2,Set3)。
然后使用这些组合集来实际比较这些集合。如果满足阈值,该组合将存储在单独的列表中,以作为可能的合并输出给用户。在输出之前,这些是删除子组合的逻辑,也就是说,如果(Set1,Set2,Set3)是一个可能的合并,那么你可以忽略其他3个子组合,因为这个超级组合已经覆盖了它。然后输出建议的合并。
问题所在
当我们达到一定数量的集合进行比较时,比如说超过17个集合,我们就会出现内存不足的问题,因为有数百万个组合正在被创建。我希望您能帮助我理解其他方法,或者我们如何改进这种方法。它可以工作,但效率不够:(
组合创建者
/**
* Iterates through the setsToBeCompared ArrayList and gets all the combinations
*
* @return - ArrayList with all the possible combinations
*/
public ArrayList<String> generateCombinations(ArrayList<String> setsToBeCompared) {
List<List<String>> temp = new ArrayList<>();
ArrayList<String> a = new ArrayList<>();
for (int i = 2; i <= 3; i++) {
temp = calculateCombinations(setsToBeCompared, i);
for (List<String> list : temp) {
a.add(list.toString());
}
}
return a;
}
/**
* Calculates all the combination given by the parameters
*
* @param values - the names of the sets to be compared
* @param size - where to start from
* @return - List of all possible calculated combinations
*/
private List<List<String>> calculateCombinations(List<String> values, int size) {
if (0 == size) {
return Collections.singletonList(Collections.<String>emptyList());
}
if (values.isEmpty()) {
return Collections.emptyList();
}
List<List<String>> combination = new LinkedList<List<String>>();
String actual = values.iterator().next();
List<String> subSet = new LinkedList<String>(values);
subSet.remove(actual);
List<List<String>> subSetCombination = calculateCombinations(subSet, size - 1);
for (List<String> set : subSetCombination) {
List<String> newSet = new LinkedList<String>(set);
newSet.add(0, actual);
combination.add(newSet);
}
combination.addAll(calculateCombinations(subSet, size));
return combination;
}
所以,总结一下我作为评论发表的观点。
在您的情况下,生成集合的所有子集绝对不是一个选项,因为此类子集的数量将为~2N。当N=50时,它比地球在纳秒内存在的时间还要长。
我假设从集合的子集切换到它们的项的子集。比如说,M
子集有N
不同的项,合并阈值是T
。因此,您需要尝试大小的~NTk-组合,看看哪些子集可以通过项的组合合并,这对于小T
是可以接受的。
算法将如下:
let D - collection of initial sets
let S - collection of distinct elements in sets across D
for each k-combination c over S {
M = new M(c) // merge object, which stores subset of merged sets and k-combination by which they are merged
for each (s in D) {
if (s.containsAll(c))
M.sets.add(s)
}
if (M.sets.size > 0) // some sets was merged through c
merges.add(M)
}
之后,获取所有可能的合并对,删除那些被其他合并完全覆盖的:
for each m in merges {
for each m1 in merges {
if (m.sets.containsAll(m1.sets))
m1.markDeleted()
}
}
像这样的东西怎么样(将使用更少的内存,但仍然需要检查大量的值-2^N)
import static java.util.stream.IntStream.range;
public class Subsets implements Iterator<List<Integer>> {
private final int level;
private final LinkedList<List<Integer>> queue = new LinkedList<>();
public Subsets(int level) {
this.level = level;
range(0, level).forEach(i -> queue.add(Arrays.asList(i)));
}
@Override
public boolean hasNext() {
return !queue.isEmpty();
}
public List<Integer> next() {
List<Integer> list = queue.removeFirst();
int maxValue = list.get(list.size() - 1);
if(list.size() < level) {
for (int k = maxValue+1; k < level; k++) {
List<Integer> newList = new ArrayList<>(list);
newList.add(k);
queue.addFirst(newList);
}
}
return list;
}
public static void main(String[] args) {
Subsets s4 = new Subsets(4);
while (s4.hasNext()) {
System.err.println(s4.next());
}
}
}
要使用它,您需要将集合(键)的名称映射为整数。示例输出:
[0]
[0, 3]
[0, 2]
[0, 2, 3]
[0, 1]
[0, 1, 3]
[0, 1, 2]
[0, 1, 2, 3]
[1]
[1, 3]
[1, 2]
[1, 2, 3]
[2]
[2, 3]
[3]
我正在Windows服务器上使用C#处理存储在IIS服务器上的web应用程序。 null
问题内容: (关于省时的稀疏数组存在一些问题,但我正在寻找内存效率。) 我需要一个相当于或哪些 只需设置一个比以前遇到的密钥大的密钥即可按需增长。(可以假定键为非负数。) 与大多数索引不是(即实际数据不是很稀疏时)的情况下的内存效率差不多。 当索引稀疏时,消耗的空间与非索引的数量成正比。 使用的内存少于(因为这会使键自动装箱并且可能不利用标量键类型)。 可以获取或设置摊销log(N)时间中的元素,
我正在尝试使用Micronaut中的可组合存储库实现一个方法。 我有: 在这里,EmployeeRepositoryCustom是一个带有“list()”方法的接口: 然后我有一个实现接口方法的EmployeeRepositoryCustomImpl类: 当我使用以下方法调用该方法时: 我得到以下消息: 我尝试在EmployeeRepositoryCustom和EmployeeRepository
问题内容: 我的磁盘中有40MB的文件,我需要使用字节数组将其“映射”到内存中。 最初,我认为将文件写入ByteArrayOutputStream是最好的方法,但我发现在复制操作期间的某个时刻它会占用约160MB的堆空间。 有人知道不使用三倍于RAM的文件大小的更好方法吗? 更新: 感谢您的回答。我注意到我可以减少内存消耗,告诉ByteArrayOutputStream初始大小比原始文件的大小稍大
如何使用itext7在内存流中创建PDF而不是物理文件?我不知道如何在最新版本中做到这一点,有帮助吗? 我尝试了以下代码,但pdfSM没有正确填充: 完整的测试代码如下所示供您参考,它在通过filePath进入PdfWriter时有效,但不适用于内存流:
问题内容: 我刚刚接受采访,并被要求使用Java 造成内存泄漏。 不用说,我对如何开始创建它一无所知。 一个例子是什么? 问题答案: 这是在纯Java中创建真正的内存泄漏(运行代码无法访问但仍存储在内存中的对象)的好方法: 该应用程序将创建一个长期运行的线程(或使用线程池更快地泄漏)。 线程通过(可选,自定义)加载类。 该类分配大量的内存(例如),在静态字段中存储对它的强引用,然后在中存储对自身的