ListIterator i przechodzenie dwukierunkowe
Używaj ListIterator do przechodzenia po listach w przód i w tył oraz modyfikowania elementów podczas iteracji.
ListIterator i przechodzenie dwukierunkowe to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.
ListIterator
ListIterator<T> rozszerza Iterator<T> o przechodzenie wstecz, pozycjonowanie na podstawie indeksu oraz możliwość dodawania i zastępowania elementów podczas iterowania.
API ListIterator
Dodatkowe metody poza Iterator: hasPrevious(), previous(), nextIndex(), previousIndex(), set(), add().
import java.util.*;
List<String> list = new ArrayList<>(List.of("A", "B", "C", "D"));
ListIterator<String> lit = list.listIterator();
// Forward traversal
while (lit.hasNext()) {
System.out.print(lit.nextIndex() + ":" + lit.next() + " ");
}
// 0:A 1:B 2:C 3:D
System.out.println();
// Backward traversal
while (lit.hasPrevious()) {
System.out.print(lit.previousIndex() + ":" + lit.previous() + " ");
}
// 3:D 2:C 1:B 0:ARozpoczynanie od określonej pozycji
Utworzenie obiektu ListIterator rozpoczynającego działanie od określonego indeksu za pomocą listIterator(index).
List<Integer> nums = new ArrayList<>(List.of(10, 20, 30, 40, 50));
// Start at index 2 (30)
ListIterator<Integer> lit = nums.listIterator(2);
System.out.println(lit.next()); // 30
System.out.println(lit.next()); // 40
System.out.println(lit.previous()); // 40
System.out.println(lit.previous()); // 30
System.out.println(lit.previous()); // 20set() podczas iteracji
set() zastępuje ostatni element zwrócony przez next() lub previous(). Jest to wydajne — O(1) dla LinkedList i O(1) dla ArrayList.
List<String> words = new ArrayList<>(List.of("hello", "world", "java"));
ListIterator<String> lit = words.listIterator();
while (lit.hasNext()) {
String word = lit.next();
lit.set(word.toUpperCase()); // replace each with uppercase
}
System.out.println(words); // [HELLO, WORLD, JAVA]add() podczas iteracji
add(element) wstawia element przed następną pozycją. Dodany element nie zostanie zwrócony przez kolejne wywołanie next() — znajduje się już „za” kursorem.
List<Integer> numbers = new ArrayList<>(List.of(1, 2, 3));
ListIterator<Integer> lit = numbers.listIterator();
while (lit.hasNext()) {
int n = lit.next();
lit.add(n * 10); // insert n*10 after each element
}
System.out.println(numbers); // [1, 10, 2, 20, 3, 30]Odwracanie listy w miejscu
Użycie ListIterator do odwrócenia listy w czasie O(n), bez przydzielania nowej listy.
static <T> void reverse(List<T> list) {
ListIterator<T> front = list.listIterator(0);
ListIterator<T> back = list.listIterator(list.size());
for (int i = 0, n = list.size() / 2; i < n; i++) {
T frontVal = front.next();
T backVal = back.previous();
front.set(backVal);
back.set(frontVal);
}
}
List<String> data = new ArrayList<>(List.of("a","b","c","d","e"));
reverse(data);
System.out.println(data); // [e, d, c, b, a]nextIndex i previousIndex
nextIndex() zwraca indeks elementu, który zostałby zwrócony przez next(). previousIndex() zwraca indeks elementu, który zostałby zwrócony przez previous().
List<String> list = List.of("X", "Y", "Z");
ListIterator<String> lit = list.listIterator();
System.out.println(lit.nextIndex()); // 0
System.out.println(lit.previousIndex()); // -1 (before start)
lit.next(); // consume X
System.out.println(lit.nextIndex()); // 1
System.out.println(lit.previousIndex()); // 0Wydajność ListIterator dla LinkedList
ListIterator dla LinkedList zapewnia O(1) dla next/previous, ponieważ przechodzenie polega na podążaniu za wskaźnikami. get(i) dla LinkedList ma złożoność O(n) — do wydajnego przechodzenia należy używać ListIterator.
import java.util.*;
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 5; i++) list.add(i * 10);
// Efficient: O(n) total for traversal via ListIterator
ListIterator<Integer> lit = list.listIterator();
while (lit.hasNext()) {
int val = lit.next();
if (val == 20) lit.set(99); // O(1) update
}
System.out.println(list); // [0, 10, 99, 30, 40]Sprawdzanie palindromu za pomocą ListIterator
Elegancki przykład przechodzenia dwukierunkowego: sprawdzanie, czy lista jest palindromem.
static <T> boolean isPalindrome(List<T> list) {
ListIterator<T> front = list.listIterator(0);
ListIterator<T> back = list.listIterator(list.size());
for (int i = 0, n = list.size() / 2; i < n; i++) {
if (!front.next().equals(back.previous())) return false;
}
return true;
}
System.out.println(isPalindrome(List.of(1, 2, 3, 2, 1))); // true
System.out.println(isPalindrome(List.of(1, 2, 3, 4))); // falsePorównanie Iterator i ListIterator
Najważniejsze różnice:
- Iterator: tylko do przodu, hasNext/next/remove
- ListIterator: dwukierunkowy, hasPrevious/previous, nextIndex/previousIndex, set/add
- ListIterator działa wyłącznie z listami (nie z Set ani Queue)
Cofanie i ponawianie zmian za pomocą ListIterator
Edytor tekstu oparty na kursorze, wykorzystujący ListIterator do wydajnego poruszania się po znakach podczas cofania i ponawiania zmian.
import java.util.*;
class TextEditor {
private final LinkedList<Character> chars = new LinkedList<>();
private ListIterator<Character> cursor;
TextEditor() { cursor = chars.listIterator(); }
void type(char c) { cursor.add(c); } // insert before cursor
void moveCursorLeft() { if (cursor.hasPrevious()) cursor.previous(); }
void moveCursorRight() { if (cursor.hasNext()) cursor.next(); }
void backspace() {
if (cursor.hasPrevious()) { cursor.previous(); cursor.remove(); }
}
String text() {
StringBuilder sb = new StringBuilder();
chars.forEach(sb::append);
return sb.toString();
}
}
TextEditor ed = new TextEditor();
ed.type('H'); ed.type('e'); ed.type('l'); ed.type('o');
ed.moveCursorLeft(); ed.moveCursorLeft();
ed.type('l');
System.out.println(ed.text()); // HelloKiedy używać ListIterator
ListIterator należy używać, gdy potrzebne są:
- przechodzenie po liście wstecz
- zastępowanie elementów podczas przechodzenia za pomocą set()
- wstawianie elementów podczas przechodzenia za pomocą add()
- śledzenie pozycji za pomocą nextIndex()/previousIndex()
Szybkie sprawdzenie
Co robi ListIterator.set()?
Podsumowanie: ListIterator i iteracja dwukierunkowa
Najważniejsze informacje:
- ListIterator rozszerza Iterator o hasPrevious(), previous(), set() i add()
- ListIterator można utworzyć w określonej pozycji za pomocą listIterator(index)
- set() zastępuje ostatni element zwrócony przez next() lub previous()
- add() wstawia element przed bieżącą pozycją kursora
- nextIndex() i previousIndex() dostarczają informacji o pozycji
- ListIterator dla LinkedList należy stosować do przechodzenia i modyfikowania elementów w czasie O(1)
Często zadawane pytania
Czy lekcja „ListIterator i przechodzenie dwukierunkowe” jest bezpłatna?
Tak — pełny tekst „ListIterator i przechodzenie dwukierunkowe” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „ListIterator i przechodzenie dwukierunkowe”?
Używaj ListIterator do przechodzenia po listach w przód i w tył oraz modyfikowania elementów podczas iteracji. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Java Academy?
Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.
Ile czasu zajmuje lekcja „ListIterator i przechodzenie dwukierunkowe”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?
Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Kontrakty Iterable i Iterator
- Implementowanie własnego iteratora
- ListIterator i przechodzenie dwukierunkowe
- Iteratory fail-fast a fail-safe