Как определяется первый элемент в LinkedList
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
# Как определяется первый элемент в LinkedList
LinkedList в Java — это двусвязный список (doubly-linked list), и первый элемент определяется специальной ссылкой (node reference). Рассмотрим детально, как это работает.
1. Структура LinkedList
Внутренняя структура Node
private static class Node<E> {
E item; // Данные
Node<E> next; // Ссылка на следующий элемент
Node<E> prev; // Ссылка на предыдущий элемент
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Хранение ссылки на первый элемент
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
transient int size = 0;
// Ссылка на первый элемент списка
transient Node<E> first;
// Ссылка на последний элемент списка
transient Node<E> last;
}
Первый элемент хранится в переменной first, которая является ссылкой (reference) на объект типа Node<E>.
2. Как определить первый элемент - основные методы
getFirst() - O(1) сложность
public E getFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return f.item;
}
Этот метод просто возвращает элемент, на который указывает ссылка first.
get(0) - O(1) сложность для первого элемента
public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
Node<E> node(int index) {
// Для малых индексов идет от начала
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
// Для больших индексов идет от конца
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
Для индекса 0 просто возвращает first.item без итерации.
peekFirst() - безопасная версия
public E peekFirst() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
Отличие от getFirst() в том, что возвращает null вместо исключения.
3. Инициализация первого элемента
При добавлении в пустой список
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode; // Если список был пуст, newNode становится first
else
l.next = newNode;
size++;
}
addFirst() - добавление в начало
public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode; // Новый элемент становится first
if (f == null)
last = newNode; // Если список был пуст
else
f.prev = newNode; // Связываем старый first с новым
size++;
}
4. Проверка наличия первого элемента
LinkedList<String> list = new LinkedList<>();
// Проверка пустоты
if (list.isEmpty()) {
System.out.println("Список пуст");
} else {
String first = list.getFirst();
}
// Безопасный способ
String first = list.peekFirst();
if (first != null) {
System.out.println("Первый элемент: " + first);
}
5. Сравнение с ArrayList
| Операция | LinkedList | ArrayList |
|---|---|---|
| Получить первый | O(1) | O(1) |
| Вставить в начало | O(1) | O(n) |
| Удалить первый | O(1) | O(n) |
| Поиск по индексу | O(n) | O(1) |
6. Практический пример
LinkedList<Integer> numbers = new LinkedList<>();
numbers.add(10);
numbers.add(20);
numbers.add(30);
// Все эти операции работают с first
Int first = numbers.getFirst(); // 10 - O(1)
int firstValue = numbers.get(0); // 10 - O(1)
Int peekFirst = numbers.peekFirst(); // 10 - O(1)
Int poll = numbers.pollFirst(); // Удалить и вернуть first
// Добавить в начало
numbers.addFirst(5); // first теперь указывает на 5
7. Внутренние детали реализации
Временные сложности
// O(1) операции - прямой доступ к first
getFirst() // Прямой доступ к first.item
addFirst() // Создание нового node, обновление first
pollFirst() // Удаление first, обновление ссылок
peekFirst() // Проверка first == null
// O(n) операции - требуют итерации
get(i) где i > 0 // Нужно пройти i узлов от first
remove(i) где i > 0 // Нужно найти node(i)
Заключение
Первый элемент в LinkedList определяется через приватную переменную first типа Node<E>. Это позволяет получать, добавлять и удалять первый элемент с временной сложностью O(1). LinkedList идеален для операций с началом/концом списка, но плохо подходит для доступа по индексу в середине списка.