我编写了一个递归算法,基本上如下所示。我用的是 Map<Integer, Long>
作为一个穷人的袋子/多套。为了避免 ConcurrentModificationException
我从不从Map上删除/添加键。它运行良好,而且 0
在此上下文中,不删除事件并不重要。
ps:我知道它不能扩展,它只是一种有趣的/通用的方式来解决代码日1第1部分和第2部分的出现。
Optional<Integer> solve(final Map<Integer, Long> intOccurrences, final int sum, final int addendsCount) {
if (addendsCount < 1) return Optional.empty();
if (addendsCount == 1) {
return intOccurrences.getOrDefault(sum, 0L) > 0 ? Optional.of(sum) : Optional.empty();
}
for (val entry : intOccurrences.entrySet()) {
if (entry.getValue() < 1) continue;
val left = entry.getKey();
val delta = sum - left;
changeCountOf(intOccurrences, left, -1);
val result = solve(intOccurrences, delta, addendsCount - 1);
if (result.isPresent()) {
return Optional.of(left * result.get());
}
changeCountOf(intOccurrences, left, 1);
}
return Optional.empty();
}
因为我已经好几年没有编写java了,所以我决定通过实现一个 IntBag
. 我已经实施了 IntBag
用一个 Map<Integer, Count>
实现的背景图 Iterable<Occurrence>
. 自定义迭代器由Map的 entrySet
迭代器和跳过 0
事件。
一切正常,但我现在 IntBag
实现与递归回溯算法配合得很好,它还会因为 0
事件永远不会被清除。
问题
有没有一种替代的方法来实现一个包,它不会遭受这种内存泄漏问题,同时避免 CurrentModificationException
(这不包括复制整个包)?
如果我当前的实现有意义的话,有什么合适的方法来清理条目?例如,我想过在某个阈值之后运行gc进程,但我不确定哪个阈值有意义,等等。
我曾想过在迭代过程中标记要删除的条目,然后在所有迭代完成后进行清理,但我认为如果我实现了,就没有办法保证所有迭代都完成了 Iterable
. 如果我只执行 forEach
但是,在最外层 forEach
退出(在迭代过程中仍然需要忽略0次出现的值)。
以上这些都不能解决递归迭代时添加新值的问题。我想不出一个办法,除了复制整个包现在工作?希望在迭代时添加项不是很常见,我猜。。。
这个 IntBag
实现当前看起来是这样的(由于没有必要,所以没有实现添加/删除):
final class IntBag implements Iterable<IntBag.Occurrence> {
private final Map<Integer, Count> occurrenceMap;
private IntBag(final Map<Integer, Count> occurrenceMap) {
this.occurrenceMap = occurrenceMap;
}
boolean contains(final int value) {
return !occurrenceMap.getOrDefault(value, Count.ZERO).isZero();
}
@Override
public Iterator<Occurrence> iterator() {
return new IntBag.BagIterator(occurrenceMap.entrySet().iterator());
}
static IntBag of(final List<Integer> values) {
return new IntBag(countInts(values));
}
private static Map<Integer, Count> countInts(final List<Integer> values) {
return values.stream().collect(groupingBy(Function.identity(), reducing(Count.ZERO, e -> Count.ONE, Count::merge)));
}
private static final class BagIterator implements Iterator<Occurrence> {
private final Iterator<Entry<Integer, Count>> entryIterator;
private Entry<Integer, Count> nextEntry;
BagIterator(@NonNull final Iterator<Entry<Integer, Count>> entryIterator) {
this.entryIterator = entryIterator;
initNext();
}
@Override
public boolean hasNext() {
return nextEntry != null;
}
@Override
public Occurrence next() {
if (!hasNext()) throw new NoSuchElementException();
val currentEntry = nextEntry;
initNext();
return new Occurrence(currentEntry);
}
private void initNext() {
while(entryIterator.hasNext()) {
val maybeNext = entryIterator.next();
if (maybeNext.getValue().isZero()) continue;
nextEntry = maybeNext;
return;
}
nextEntry = null;
}
}
@RequiredArgsConstructor
static final class Occurrence {
private final Map.Entry<Integer, Count> entry;
int value() {
return entry.getKey();
}
long count() {
return entry.getValue().value();
}
void merge(final long modifier) {
entry.setValue(entry.getValue().merge(modifier));
}
}
private static final class Count {
private final long value;
private Count(final long value) {
this.value = Math.max(0L, value);
}
long value() {
return value;
}
boolean isZero() {
return value == 0L;
}
Count merge(@NonNull final Count modifier) {
return merge(modifier.value());
}
Count merge(final long modifier) {
return new Count(value + modifier);
}
static final Count ZERO = Count.of(0L);
static final Count ONE = Count.of(1L);
static Count of(final long value) {
return new Count(value);
}
}
}
暂无答案!
目前还没有任何答案,快来回答吧!