【问题标题】:How to use two different iterators on a Linked List in Java?如何在 Java 中的链表上使用两个不同的迭代器?
【发布时间】:2012-11-04 03:38:07
【问题描述】:

我想使用链表来执行元素的提取和插入,尝试所有组合以进行启发式。链表对于这种类型的操作更有效。 因为我想尝试所有可能的提取/插入对,所以我在列表上使用了两个不同的迭代器。这会引发“ConcurrentModificationException”。我怎样才能有效地执行此操作,而无需每次都重新遍历列表,因为这会破坏首先使用列表的全部目的?

以下是代码的相关部分:

ListIterator<Integer> it1 = data.listIterator();
ListIterator<Integer> it2;

while(it1.hasNext()) {
    int i = it1.next();
    it2 = data.listIterator();

    while(it2.hasNext()) {
        if (i == it2.next()) continue; // continue right away when the indexes are equal
        it1.remove();
        it2.add(i);
        if (length() < best)
            return true;
        }

    // when the swap is not better/consistent
    it2.remove();
    it1.add(i);
}
return false;

谢谢

【问题讨论】:

  • 如果通过一个迭代器更改列表,则不能使用任何其他迭代器。
  • 你可以使用 ConcurrentLinkedQueue 代替它,因为它没有 CME 吗?我怀疑在任何情况下都有更有效的方法来做你正在做的任何事情。
  • 请用谷歌搜索:www.google.com/search?q=multi+dimensional+linked+list+java 并检查类似dreamincode.net/forums/topic/…的结果
  • 对于特定的启发式方法,我必须考虑所有可能的重新插入组合。必须评估所有组合。这是为了探索 NP-hard 问题的受限邻域 O(n^2)。
  • 但是无论如何,您不能考虑将所有重新插入都放在一个列表中。您需要不同版本的列表。

标签: java iterator linked-list heuristics concurrentmodification


【解决方案1】:

如果我没听错的话,你会寻找一种数据结构,它提供了几个迭代器来操作列表。这对于原始的 java.util.LinkedList 来说在技术上是困难的,因为它对当前索引进行内务处理,并且只有在其他迭代器在列表中的未知位置没有并行更改时,这才可能以一种有效的方式实现。但是,您可以轻松实现一个简单的 LinkedList,它不做这种内务处理并支持通过多个迭代器添加/删除。然后,迭代器不知道它在列表中的位置,但我敢打赌你不在乎。只需使用这样的东西:

public class MyList<T> {
private MyNode<T> first = null, last = null;

public MyNode<T> getFirst() {
    return first;
}

public MyNode<T> getLast() {
    return last;
}

public boolean contains(MyNode<T> n) {
    return n.list == this;
}

/**
 * If beforeMe is null, toInsert is inserted at the end of the list.
 * @return inserted node
 */
public void insertBefore(MyNode<T> beforeMe, MyNode<T> newNode) {
    if (newNode == null) {
        throw new IllegalArgumentException("toInsert must not be null!");
    }

    if (newNode.list != null) {
        throw new IllegalArgumentException("This node is already in the list " + newNode.list);
    }

    if (beforeMe == null) {
        if (last == null) {
            newNode.prev = newNode.next = null;
            first = last = newNode;
        } else {
            last.next = newNode;
            newNode.prev = last;
            newNode.next = null;
            last = newNode;
        }
    } else {
        newNode.prev = beforeMe.prev;
        newNode.next = beforeMe;

        if (beforeMe.prev != null) {
            beforeMe.prev.next = newNode;
        } else {
            first = newNode;
        }

        beforeMe.prev = newNode;
    }

    newNode.list = this;
}

/**
 * If beforeMe is null, t is inserted at the end of the list.
 * @return inserted node
 */
public MyNode<T> insertBefore(MyNode<T> beforeMe, T t) {
    MyNode<T> newNode = new MyNode<T>(t);
    insertBefore(beforeMe, newNode);
    return newNode;
}

public void remove(MyNode<T> n) {
    if (n == null || n.list != this) {
        throw new IllegalArgumentException("Node is not in the list!");
    }

    if (n.prev != null) {
        n.prev.next = n.next;
    } else {
        first = n.next;
    }

    if (n.next != null) {
        n.next.prev = n.prev;
    } else {
        last = n.prev;
    }

    n.prev = n.next = null;
    n.list = null;
}}

public class MyNode<T> {

private T t;
/**
 * written only by MyList
 */
MyNode<T> prev = null;
/**
 * written only by MyList
 */
MyNode<T> next = null;
/**
 * written only by MyList
 */
MyList<T> list = null;

public T get() {
    return t;
}

public void set(T t) {
    this.t = t;
}

public MyNode<T> previous() {
    return prev;
}

public MyNode<T> next() {
    return next;
}

public MyList<T> list() {
    return list;
}

/**
 * called only by MyList.
 * @param t
 */
MyNode(T t) {
    this.t = t;
}}

【讨论】:

    【解决方案2】:

    您不能在 LinkedList 上同时使用多个迭代器,但是您可以使用 CopyOnWriteArrayList

    试试这个:

    List<Integer> safeData = new CopyOnWriteArrayList(date);
    // your code, but working with safeData rather than data
    

    【讨论】:

    • 谢谢,但这是作为数组实现的,而不是作为列表。这意味着插入效率不高; O(n) 而不是 O(1)。
    • @DavidBlinder 插入效率会降低,但不是因为您所说的任何内容。在内部列出 use 数组,但是这个特殊的类在更改时会在内部创建一个完整的自身副本以使其成为线程安全的 - 请参阅链接的 javadoc
    【解决方案3】:

    当您只执行读取操作时,您可以在 LIST 上使用任意数量的迭代器。由于您在此处执行删除/添加,因此您不能将同一个列表与两个不同的迭代器一起使用,因为它会导致您现在遇到的 ConcurrentModificationException。

    你想达到什么目标?也许,人们可以通过不同的选择帮助您。

    【讨论】:

    • 你不应该写 cmets 作为答案。
    • 同意。但是由于stackoverflow中的启动状态,不允许我添加为评论:(。
    • 两个小时前,这不再是真的了:) 阈值为 50。
    猜你喜欢
    • 2021-06-27
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多