← Назад к вопросам
Как называется наличие у объекта ссылки на предыдущий и следующий объект
1.0 Junior🔥 131 комментариев
#Другое
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Двусвязный список (Doubly Linked List)
Наличие у объекта ссылки на предыдущий и следующий объект называется структурой данных Двусвязный список (Doubly Linked List) или двунаправленный список.
Определение и характеристики
Двусвязный список - это линейная структура данных, в которой каждый узел (элемент) содержит:
- Данные (значение)
- Ссылку на следующий узел (next)
- Ссылку на предыдущий узел (previous)
В отличие от односвязного списка, где каждый узел имеет только ссылку на следующий элемент.
Структура узла двусвязного списка
public class Node<T> {
private T data;
private Node<T> next;
private Node<T> previous;
public Node(T data) {
this.data = data;
this.next = null;
this.previous = null;
}
// Getters and setters
public T getData() { return data; }
public Node<T> getNext() { return next; }
public void setNext(Node<T> next) { this.next = next; }
public Node<T> getPrevious() { return previous; }
public void setPrevious(Node<T> previous) { this.previous = previous; }
}
Реализация двусвязного списка
public class DoublyLinkedList<T> {
private Node<T> head;
private Node<T> tail;
private int size;
public DoublyLinkedList() {
this.head = null;
this.tail = null;
this.size = 0;
}
// Вставка в начало
public void insertAtBeginning(T data) {
Node<T> newNode = new Node<>(data);
if (head == null) {
head = newNode;
tail = newNode;
} else {
newNode.setNext(head);
head.setPrevious(newNode);
head = newNode;
}
size++;
}
// Вставка в конец
public void insertAtEnd(T data) {
Node<T> newNode = new Node<>(data);
if (tail == null) {
head = newNode;
tail = newNode;
} else {
tail.setNext(newNode);
newNode.setPrevious(tail);
tail = newNode;
}
size++;
}
// Вставка в позицию
public void insertAtPosition(int position, T data) {
if (position < 0 || position > size) {
throw new IndexOutOfBoundsException();
}
if (position == 0) {
insertAtBeginning(data);
return;
}
if (position == size) {
insertAtEnd(data);
return;
}
Node<T> newNode = new Node<>(data);
Node<T> current = getNode(position - 1);
newNode.setNext(current.getNext());
newNode.setPrevious(current);
current.getNext().setPrevious(newNode);
current.setNext(newNode);
size++;
}
// Удаление элемента
public void remove(int position) {
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException();
}
Node<T> current = getNode(position);
if (current.getPrevious() != null) {
current.getPrevious().setNext(current.getNext());
} else {
head = current.getNext();
}
if (current.getNext() != null) {
current.getNext().setPrevious(current.getPrevious());
} else {
tail = current.getPrevious();
}
size--;
}
// Получение элемента
public T get(int position) {
if (position < 0 || position >= size) {
throw new IndexOutOfBoundsException();
}
return getNode(position).getData();
}
private Node<T> getNode(int position) {
Node<T> current;
// Оптимизация: начинаем с конца, если элемент ближе
if (position < size / 2) {
current = head;
for (int i = 0; i < position; i++) {
current = current.getNext();
}
} else {
current = tail;
for (int i = size - 1; i > position; i--) {
current = current.getPrevious();
}
}
return current;
}
// Обход в прямом направлении
public void displayForward() {
Node<T> current = head;
System.out.print("Forward: ");
while (current != null) {
System.out.print(current.getData() + " <-> ");
current = current.getNext();
}
System.out.println("null");
}
// Обход в обратном направлении
public void displayBackward() {
Node<T> current = tail;
System.out.print("Backward: ");
while (current != null) {
System.out.print(current.getData() + " <-> ");
current = current.getPrevious();
}
System.out.println("null");
}
}
Пример использования
public class Main {
public static void main(String[] args) {
DoublyLinkedList<Integer> list = new DoublyLinkedList<>();
list.insertAtEnd(10);
list.insertAtEnd(20);
list.insertAtEnd(30);
list.insertAtBeginning(5);
list.insertAtPosition(2, 15);
list.displayForward(); // Forward: 5 <-> 10 <-> 15 <-> 20 <-> 30
list.displayBackward(); // Backward: 30 <-> 20 <-> 15 <-> 10 <-> 5
System.out.println("Element at position 2: " + list.get(2)); // 15
list.remove(2);
list.displayForward(); // Forward: 5 <-> 10 <-> 20 <-> 30
}
}
Преимущества двусвязного списка
- Можно перемещаться в обе стороны
- Удаление элемента эффективнее, если известна позиция
- Полезен для реализации LRU кешей
- Удобен для операций, требующих доступа к соседним элементам
Недостатки
- Требует больше памяти (две ссылки вместо одной)
- Сложнее в реализации и отладке
- Медленнее при работе с элементами (сравнено с массивом)
Применение в Java
В Java класс LinkedList реализует двусвязный список:
List<Integer> list = new LinkedList<>();
list.add(10);
list.add(20);
list.add(30);
list.remove(1);
Iterator<Integer> iterator = list.iterator();
Взаимосвязь с похожими структурами
Однозвязный список (Singly Linked List) - имеет только ссылку на следующий элемент. Циклический двусвязный список - tail указывает на head, head.previous указывает на tail.