양방향 연결 리스트(Doubly Linked List)는 각 노드가 두 개의 포인터를 가지고 있는 연결 리스트의 한 종류입니다.
각 노드는 데이터와 두 개의 포인터(다음 노드를 가리키는 next 포인터와 이전 노드를 가리키는 prev 포인터)로 구성되어 있습니다.
이러한 구조로 인해 양방향 연결 리스트는 단방향 연결 리스트와 달리 노드의 이전 노드를 쉽게 접근할 수 있습니다.
양방향 연결 리스트의 특징:
노드 구성: 각 노드는 데이터 필드와 두 개의 포인터(다음 노드를 가리키는 next 포인터와 이전 노드를 가리키는 prev 포인터)로 이루어져 있습니다.
양방향 이동: 단방향 연결 리스트와 달리, 양방향 연결 리스트는 노드의 이전 노드를 가리키는 prev 포인터를 통해 역방향으로 이동할 수 있습니다. 이로 인해 리스트를 앞뒤로 모두 순회할 수 있습니다.
삽입/삭제: 양방향 연결 리스트는 단방향 연결 리스트와 마찬가지로 삽입과 삭제가 O(1) 시간에 가능합니다. 즉, 특정 노드를 찾지 않고도 바로 앞이나 뒤에 노드를 삽입하거나 삭제할 수 있습니다.
추가적인 메모리: 단방향 연결 리스트와 달리 prev 포인터 때문에 각 노드가 더 많은 메모리를 사용합니다. 하지만 역방향 순회와 삽입/삭제가 더 효율적으로 이루어지는 장점이 있습니다.
양방향 연결 리스트의 구조는 다음과 같습니다:
Node 1 Node 2 Node 3 Node 4
[ data | prev | next ] [ data | prev | next ] [ data | prev | next ] [ data | prev | next ]
양방향 연결 리스트 구현
- 양방향 연결 리스트는 어떤 상황에서는 단방향 연결 리스트보다 유용하게 사용될 수 있습니다.
- 예를 들어 양방향으로 순회해야 하는 상황이나 양방향으로 삽입/삭제가 빈번하게 발생하는 경우에 유용하게 활용할 수 있습니다.
- 하지만 메모리 사용 측면에서는 단방향 연결 리스트보다 더 많은 공간을 사용한다는 점을 고려해야 합니다.
- 따라서 각 상황에 맞게 적절하게 연결 리스트를 선택하여 사용하는 것이 중요합니다.
package LinkedList;
public class DoublyLinkedListLearn {
// 양방향 연결 리스트의 노드 클래스를 정의
private static class Node {
int data; // 저장할 데이터
Node prev; // 이전 데이터
Node next; // 다음 데이터
// 생성자
public Node(int data) {
this.data = data;
this.prev = null;
this.next = null;
}
}
// 양방향 연결 리스트 클래스를 정의
private static class DoublyLinkedList {
Node head;
Node tail;
// 리스트의 맨 뒤에 노드를 추가하는 메서드
public void append(int data) {
// 새로운 노드를 생성하고 데이터를 설정한다.
Node newNode = new Node(data);
// 리스트가 비어있는 경우
if (head == null) {
// head와 tail이 모두 새로운 노드를 가리키게 한다.
head = newNode;
tail = newNode;
} else {
// 리스트가 비어있지 않은 경우
// 현재 tail의 다음 노드로 새로운 노드를 연결한다.
tail.next = newNode;
// 새로운 노드의 이전 노드를 현재 tail로 설정한다.
newNode.prev = tail;
// tail을 새로운 노드로 갱신한다.
tail = newNode;
}
}
public void prepend(int data) {
Node newNode = new Node(data);
if (head == null) {
head = newNode;
tail = newNode;
} else {
newNode.next = head;
head.prev = newNode;
head = newNode;
}
}
public void delete(int data) {
Node current = head;
while (current != null) {
if (current.data == data) {
if (current == head) {
head = current.next;
if (head != null) {
head.prev = null;
}
} else if (current == tail) {
tail = current.prev;
if (tail != null) {
tail.next = null;
}
} else {
current.prev.next = current.next;
current.next.prev = current.prev;
}
break;
}
current = current.next;
}
}
// 리스트의 모든 노드를 출력하는 메서드
public void printList() {
Node current = head;
while (current != null) {
System.out.print(current.data + " ");
current = current.next;
}
System.out.println();
}
}
public static void main(String[] args) {
DoublyLinkedList dll = new DoublyLinkedList();
dll.append(1);
dll.append(2);
dll.append(3);
dll.printList(); // 출력: 1 2 3
dll.prepend(0);
dll.printList(); // 출력: 0 1 2 3
dll.delete(2);
dll.printList(); // 출력: 0 1 3
}
}
'JAVA > Algo 개념' 카테고리의 다른 글
[프로그래머스] 양과 늑대 - JAVA (0) | 2024.07.04 |
---|---|
KMP -JAVA (0) | 2023.08.05 |
슬라이딩 윈도우와 투 포인터 (0) | 2023.07.30 |
TreeMap - Red-Black Tree (0) | 2023.07.26 |
DP - LIS(최장 증가 수열) 및 0-1 Knapsack 개념 (JAVA) (1) | 2023.07.16 |