在Java中使用ListIterator在LinkedList上来回移动

在Java中使用ListIterator在LinkedList上来回移动,java,iterator,linked-list,Java,Iterator,Linked List,我有一个LinkedList,需要在上面来回迭代多次。我使用它来跟踪将动态创建的工作流中的一系列页面。这并不像我预期的那样。举个例子: LinkedList<String> navigationCases; navigationCases.add("page1"); navigationCases.add("page2"); navigationCases.add("page3"); navigationCases.add("page4"); ListIterator naviga

我有一个LinkedList,需要在上面来回迭代多次。我使用它来跟踪将动态创建的工作流中的一系列页面。这并不像我预期的那样。举个例子:

LinkedList<String> navigationCases;
navigationCases.add("page1");
navigationCases.add("page2");
navigationCases.add("page3");
navigationCases.add("page4");

ListIterator navigationItr = navigationCases.listIterator();
navigationItr.next(); // Returns page1
navigationItr.next(); // Returns page2
navigationItr.previous(); //Returns page2 again
navigationItr.next(); //Returns page2 again
LinkedList导航案例;
导航案例。添加(“第1页”);
导航案例。添加(“第2页”);
导航案例。添加(“第3页”);
导航案例。添加(“第4页”);
ListIterator navigationItr=navigationCases.ListIterator();
导航itr.next();//返回第1页
导航itr.next();//返回第2页
导航itr.previous()//再次返回第2页
导航itr.next()//再次返回第2页
我认为可能是我构建的列表不正确,或者使用的迭代器不正确,但在阅读文档后,这似乎是出于设计:

ListIterator没有当前元素;其光标位置始终位于调用previous()返回的元素和调用next()返回的元素之间。

以及:

(Next)返回列表中的下一个元素。此方法可以重复调用以遍历列表,也可以与对previous的调用混合在一起来回调用。(请注意,交替调用next和previous将重复返回相同的元素。)

因此,在阅读本文之后,我很清楚为什么我的代码会以这种方式运行。我只是不明白为什么会这样。甚至remove似乎也在向后弯曲以适应此实现:

请注意,remove()和set(Object)方法不是根据光标位置定义的;它们被定义为对调用next()或previous()返回的最后一个元素进行操作。

从概念上讲,LinkedList似乎很好地模拟了我的工作流案例,但我不能使用这样的迭代器。我是否在这里遗漏了什么,还是应该编写自己的类来维护案例列表并浏览它们?

执行类似的操作(伪代码)--

然后:

LinkedList导航案例;
导航案例。添加(“第1页”);
导航案例。添加(“第2页”);
导航案例。添加(“第3页”);
导航案例。添加(“第4页”);
SkipIterator navigationItr=(SkipIterator)navigationCases.listIterator();
导航itr.next();//返回第1页
导航itr.next();//返回第2页
navigationItr.previous();//返回第1页

干杯

这应该是你的工作:

public class Main {
    public static void main(String[] args) {
        final LinkedList<String> list = new LinkedList<String> ();

        list.add ("1"); list.add ("2"); list.add ("3"); list.add ("4");

        final MyIterator<String> it = new MyIterator (list.listIterator());

        System.out.println(it.next());
        System.out.println(it.next ());
        System.out.println(it.next ());
        System.out.println(it.previous ());
        System.out.println(it.previous ());
        System.out.println(it.next ());
    }

    public static class MyIterator<T> {

        private final ListIterator<T> listIterator;

        private boolean nextWasCalled = false;
        private boolean previousWasCalled = false;

        public MyIterator(ListIterator<T> listIterator) {
            this.listIterator = listIterator;
        }

        public T next() {
            nextWasCalled = true;
            if (previousWasCalled) {
                previousWasCalled = false;
                listIterator.next ();
            }
            return listIterator.next ();
        }

        public T previous() {
            if (nextWasCalled) {
                listIterator.previous();
                nextWasCalled = false;
            }
            previousWasCalled = true;
            return listIterator.previous();
        }

    }   
}
公共类主{
公共静态void main(字符串[]args){
最终LinkedList=新LinkedList();
list.add(“1”);list.add(“2”);list.add(“3”);list.add(“4”);
final MyIterator it=newmyiterator(list.listIterator());
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.previous());
System.out.println(it.previous());
System.out.println(it.next());
}
公共静态类MyIterator{
私有最终ListIterator ListIterator;
私有布尔值nextwascaled=false;
私有布尔值previousWasCalled=false;
公共MyIterator(ListIterator ListIterator){
this.listIterator=listIterator;
}
公共交通工具{
nextwascaled=true;
如果(先前调用){
PreviousWasCall=false;
listIterator.next();
}
返回listIterator.next();
}
公共事务{
如果(下一次升级){
listIterator.previous();
nextwascaled=false;
}
PreviousWasCall=true;
返回listIterator.previous();
}
}   
}

ListIterator就是这样设计的。参见ShyJ答案下面的对话,了解其基本原理

我发现这种行为非常愚蠢,于是写了一个非常简单的替代方案。以下是Kotlin代码,其中包含ArrayList的扩展函数:

class ListIterator<E>(var list: ArrayList<E>) : Iterator<E> {

    private var cursor: Int = 0

    fun replace(newList: ArrayList<E>) {
        list = newList
        cursor = 0
    }

    override fun hasNext(): Boolean {
        return cursor + 1 < list.size
    }

    override fun next(): E {
        cursor++
        return current()
    }

    fun hasPrevious(): Boolean {
        return 0 <= cursor - 1
    }

    fun previous(): E {
        cursor--
        return current()
    }

    fun current(): E {
        return list[cursor]
    }

}

fun <E> ArrayList<E>.listFlippingIterator() = ListIterator(this)
class ListIterator(变量列表:ArrayList):迭代器{
私有变量游标:Int=0
趣味替换(新列表:ArrayList){
列表=新列表
光标=0
}
override fun hasNext():Boolean{
返回光标+1返回0为什么不能“使用这种行为的迭代器”?世界上其他地方都是这样。只需接受它的工作方式,并按预期使用它。它的行为方式是这样的,因为它使从头开始的迭代和删除与从头开始的迭代和删除完全相同。如果必须,请将核心功能包装在自己的逻辑中,以调用
它erator.previous().previous()
(伪明显)当您请求
myIterator.previous()
@Madbreaks时,当上一个操作是next()时,您只需调用previous两次。否则,您只调用一次。因此,我感到沮丧:)这是一种非常令人沮丧的行为。我花了数小时来重现和调试包含此代码的问题。不幸的是,如果上一个操作是next(),我只想调用previous()两次。如果next不是previous,则调用previous()两次实际上会导致迭代器跳过列表中的一个元素。好的,在中构建该逻辑。:)思想是可以扩展基类并包含用例所需的逻辑。执行
previous()
每次调用两次将不会在没有事先调用
next()
的情况下向后导航时提供所需的行为。是的,我看不出有任何方法可以避免记住以前的操作。谢谢!
public class Main {
    public static void main(String[] args) {
        final LinkedList<String> list = new LinkedList<String> ();

        list.add ("1"); list.add ("2"); list.add ("3"); list.add ("4");

        final MyIterator<String> it = new MyIterator (list.listIterator());

        System.out.println(it.next());
        System.out.println(it.next ());
        System.out.println(it.next ());
        System.out.println(it.previous ());
        System.out.println(it.previous ());
        System.out.println(it.next ());
    }

    public static class MyIterator<T> {

        private final ListIterator<T> listIterator;

        private boolean nextWasCalled = false;
        private boolean previousWasCalled = false;

        public MyIterator(ListIterator<T> listIterator) {
            this.listIterator = listIterator;
        }

        public T next() {
            nextWasCalled = true;
            if (previousWasCalled) {
                previousWasCalled = false;
                listIterator.next ();
            }
            return listIterator.next ();
        }

        public T previous() {
            if (nextWasCalled) {
                listIterator.previous();
                nextWasCalled = false;
            }
            previousWasCalled = true;
            return listIterator.previous();
        }

    }   
}
class ListIterator<E>(var list: ArrayList<E>) : Iterator<E> {

    private var cursor: Int = 0

    fun replace(newList: ArrayList<E>) {
        list = newList
        cursor = 0
    }

    override fun hasNext(): Boolean {
        return cursor + 1 < list.size
    }

    override fun next(): E {
        cursor++
        return current()
    }

    fun hasPrevious(): Boolean {
        return 0 <= cursor - 1
    }

    fun previous(): E {
        cursor--
        return current()
    }

    fun current(): E {
        return list[cursor]
    }

}

fun <E> ArrayList<E>.listFlippingIterator() = ListIterator(this)