Post

[Data Structure] Linked List

[Data Structure] Linked List

🧩 Linked List

Linked List & Array

μ—°κ²° λ¦¬μŠ€νŠΈλŠ” μž„μ˜μ˜ λ©”λͺ¨λ¦¬ 곡간에 μžˆλŠ” μš”μ†Œλ₯Ό μ—°κ²°ν•˜μ—¬ μ €μž₯ν•˜λŠ” μžλ£Œκ΅¬μ‘°μž…λ‹ˆλ‹€. λ°°μ—΄κ³Όμ˜ 비ꡐλ₯Ό 톡해 μ—°κ²° 리슀트λ₯Ό 더 μ‰½κ²Œ 이해할 수 μžˆμŠ΅λ‹ˆλ‹€.

배열은 μ—°μ†λœ 곡간에 μš”μ†Œλ₯Ό μ €μž₯ν•©λ‹ˆλ‹€. Cμ—μ„œ λ‹€μŒκ³Ό 같이 μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1
2
3
4
5
int scores[100];
scores[0] = 1;
scores[1] = 2;
scores[2] = 3;
...

scores λ‚΄ 각 μš”μ†ŒλŠ” 자체 λ©”λͺ¨λ¦¬ 곡간을 κ°–μŠ΅λ‹ˆλ‹€. λͺ¨λ“  μš”μ†ŒλŠ” [] μ—°μ‚°μžλ₯Ό 톡해 νŽΈλ¦¬ν•˜κ³  λΉ λ₯΄κ²Œ μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν•˜μ§€λ§Œ 배열은 컴파일 μ‹œμ μ— 크기λ₯Ό μ§€μ •ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ—, κ³„μ†ν•΄μ„œ μš”μ†Œλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•˜λŠ” λŸ°νƒ€μž„ ν™˜κ²½μ—μ„œλŠ” μ μ ˆν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. μ΄λŸ¬ν•œ 단점은 동적 할당을 톡해 μ–΄λŠμ •λ„ 극볡할 수 μžˆμ§€λ§Œ μž¬ν• λ‹Ή λΉ„μš© 및 λ©”λͺ¨λ¦¬ λ‚­λΉ„λΌλŠ” λ¬Έμ œκ°€ μ—¬μ „νžˆ μ‘΄μž¬ν•©λ‹ˆλ‹€. μ—°κ²° 리슀트λ₯Ό μ΄μš©ν•˜λ©΄ 이 문제λ₯Ό μ™„λ²½ν•˜κ²Œ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

Structure

μ—°κ²° λ¦¬μŠ€νŠΈλŠ” λ…Έλ“œ(Node)λΌλŠ” λ‹¨μœ„λ₯Ό μ‚¬μš©ν•˜μ—¬ μš”μ†Œλ₯Ό μ €μž₯ν•©λ‹ˆλ‹€. NodeλŠ” data와 next둜 κ΅¬μ„±λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. nextλŠ” λ‹€μŒ Node 객체 자체λ₯Ό κ°€λ¦¬ν‚€λŠ” μ°Έμ‘°μž…λ‹ˆλ‹€.

1
2
3
4
class Node:
    def __init__(self, data):
        self.data = data
        self.next = None

Iteration & Length

리슀트의 κ°€μž₯ 기초적인 연산은 첫 λ…Έλ“œ(head)λΆ€ν„° 끝(None)κΉŒμ§€ ν›‘λŠ” κ²λ‹ˆλ‹€. μ—¬κΈ°μ„œ μ€‘μš”ν•œ 원칙은 headλΌλŠ” 기쀀점(포인터)을 μ ˆλŒ€ μžƒμ–΄λ²„λ¦¬λ©΄ μ•ˆ λœλ‹€λŠ” κ²λ‹ˆλ‹€.

current 포인터λ₯Ό μ‚¬μš©ν•œ νŒ¨ν„΄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Node:
    def __init__(self, data):
        self.data = data
        self.next = None
    
def build_one_two_three():
    head = Node(1)
    second = Node(2)
    third = Node(3)

    head.next = second
    second.next = third

    return head

def length(head):
    current = head
    count = 0

    while current != None:
        count += 1
        current = current.next        
        
    return count

head = build_one_two_three()
print(length(head)) # 3

headλ₯Ό 직접 움직이지 μ•Šκ³ , currentλ₯Ό μ§€μ—° λ³€μˆ˜μ— λ³΅μ‚¬ν•΄μ„œ μ›€μ§μ΄λŠ” 게 ν•΅μ‹¬μž…λ‹ˆλ‹€. 이 νŒ¨ν„΄μ€ 데이터λ₯Ό μ°Ύκ±°λ‚˜, 좜λ ₯ν•˜κ±°λ‚˜, μˆ˜μ •ν•˜λŠ” λͺ¨λ“  둜직의 기본이 λ©λ‹ˆλ‹€.

current = current.nextλ₯Ό μžŠμ–΄λ²„λ¦¬λ©΄ λ¬΄ν•œ 루프에 빠질 수 μžˆμœΌλ‹ˆ μ£Όμ˜ν•©λ‹ˆλ‹€.

🧩 Programming Philosophy

μž‘λ™ν•˜μ§€ μ•ŠλŠ” Push

기술적 κ΄€μ μ—μ„œ Cμ—μ„œ 리슀트 ꡬ좕 μ‹œ 리슀트의 맨 μ•žμ— 데이터λ₯Ό μΆ”κ°€ν•  λ•Œ ν”νžˆ κ²ͺλŠ” μ‹€μˆ˜κ°€ μžˆμŠ΅λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void WrongPush(struct node* head, int data) {
    struct node* newNode = malloc(sizeof(struct node));

    newNode->data = data;
    newNode->next = head;
    head = newNode;
}

int main() {
    struct node* head = BuildTwoThree();
    printf("%d\n", head->data); // 2
    WrongPush(head, 1);
    printf("%d\n", head->data); // 2
    return 0;
}

ν•¨μˆ˜μ—μ„œ headλ₯Ό 바꿔도, ν•¨μˆ˜ λ°–μ˜ 원본 headκ°€ λ°”λ€Œμ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€. WrongPush()의 headλŠ” main()의 head와 λ³„λ„μ˜ μŠ€νƒ 곡간에 μœ„μΉ˜ν•˜κΈ° λ•Œλ¬Έμ΄μ£ .

Sol 1. λͺ…μ‹œμ  λ°˜ν™˜ μ‚¬μš© (Functional Approach)

이쀑 포인터λ₯Ό μ‚¬μš©ν•˜μ—¬ 포인터에 λŒ€ν•œ μ—­μ°Έμ‘° 연산을 톡해 원본 포인터에 μ ‘κ·Όν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void Push(struct node** headRef, int data) {
    struct node* newNode = malloc(sizeof(struct node));

    newNode->data = data;
    newNode->next = *headRef;
    *headRef = newNode;
}

int main() {
    struct node* head = BuildTwoThree();
    printf("%d\n", head->data); // 2
    Push(&head, 1);
    printf("%d\n", head->data); // 1
    return 0;
}

νŒŒμ΄μ¬μ—μ„œλŠ” 이쀑 포인터(**)λ₯Ό μ‚¬μš©ν•΄ μ™ΈλΆ€ λ³€μˆ˜λ₯Ό 직접 μˆ˜μ •ν•˜λŠ” 게 λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€. λŒ€μ‹ , λ³€κ²½λœ headλ₯Ό λ°˜ν™˜ν•˜κ³  λ°–μ—μ„œ λ‹€μ‹œ λ°›μ•„ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
def push(head, data):
    new_node = Node(data)
    new_node.next = head
    return new_node

head = None
head = push(head, 1)
head = push(head, 2)
print(length(head)) # 2

Sol 2. Wrapper Class μ‚¬μš© (OOP Approach)

headλ₯Ό 클래슀둜 κ°μ‹Έμ„œ κ΄€λ¦¬ν•˜λ©΄, headλŠ” 클래슀의 멀버 λ³€μˆ˜λ‘œμ„œ νž™ 곡간에 μœ„μΉ˜ν•˜κΈ° λ•Œλ¬Έμ— μˆ˜μ •μ΄ μžμœ λ‘œμ›Œμ§‘λ‹ˆλ‹€. μ‹€λ¬΄μ—μ„œλŠ” 이 방법이 더 ꢌμž₯λ©λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
class LinkedList:
    def __init__(self):
        self.head = None

    def push(self, data):
        new_node = Node(data)
        new_node.next = self.head
        self.head = new_node

ll = LinkedList()
ll.push(1)
ll.push(2)
print(ll.head.data) # 2

Implementation Strategies

A. Head에 μΆ”κ°€ν•˜κΈ° (Stack)

μ•žμ„œ λ³Έ pushλ₯Ό 계속 ν˜ΈμΆœν•˜λŠ” λ°©μ‹μž…λ‹ˆλ‹€. μ½”λ“œλŠ” κ°„λ‹¨ν•˜μ§€λ§Œ, 데이터가 μ—­μˆœμœΌλ‘œ μ €μž₯λ©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, 1, 2, 3 순으둜 μž…λ ₯ν•˜λ©΄ 3, 2, 1 순으둜 μ €μž₯λ©λ‹ˆλ‹€.

B. Tail 포인터와 특수 μΌ€μ΄μŠ€ (Queue)

μˆœμ„œλ₯Ό μ§€ν‚€λ €λ©΄ λ’€μͺ½μ— λΆ™μ—¬μ•Ό ν•©λ‹ˆλ‹€. 맀번 λκΉŒμ§€ μ°Ύμ•„κ°€μ§€ μ•ŠμœΌλ €λ©΄ λ§ˆμ§€λ§‰ λ…Έλ“œλ₯Ό κ°€λ¦¬ν‚€λŠ” tail 포인터λ₯Ό μœ μ§€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

ν•˜μ§€λ§Œ μ—¬κΈ°μ—” 치λͺ…적인 단점이 μžˆλŠ”λ°, β€œμ²« 번째 λ…Έλ“œμΌ λ•Œβ€μ™€ β€œκ·Έ 이후일 λ•Œβ€μ˜ μ½”λ“œκ°€ λ‹€λ¦…λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def build_with_tail_pointer():
    head = None
    tail = None

    for i in range(1, 6):
        new_node = Node(i)

        if head is None:
            head = new_node
            tail = new_node
        else:
            tail.next = new_node
            tail = tail.next

    return head

head = build_with_tail_pointer()
print(head.data) # 1

μΌ€μ΄μŠ€λ₯Ό λ³„λ„λ‘œ μ²˜λ¦¬ν•œλ‹€λŠ” μ μ—μ„œ 쑰금 μ•„μ‰¬μš΄ μ „λž΅μž…λ‹ˆλ‹€.

C. Dummy Node (κ°€μž₯ μš°μ•„ν•œ ν•΄κ²°μ±…)

빈 껍데기 λ…Έλ“œ(Dummy)λ₯Ό ν•˜λ‚˜ λ§Œλ“€κ³  μ‹œμž‘ν•˜λ©΄, headκ°€ None인지 검사할 ν•„μš”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
def build_with_dummy_node():
    dummy = Node("DUMMY")
    tail = dummy

    for i in range(1, 6):
        tail.next = Node(i)
        tail = tail.next
    
    return dummy.next

head = build_with_dummy_node()
print(head.data) # 1

이 방식은 β€œλͺ¨λ“  λ…Έλ“œλŠ” μ•ž λ…Έλ“œμ˜ next에 λΆ™λŠ”λ‹€β€ λŠ” κ·œμΉ™μ„ 첫 번째 λ…Έλ“œμ—λ„ κ°•μ œλ‘œ μ μš©μ‹œμΌœ μ½”λ“œλ₯Ό λ‹¨μˆœν™”ν•©λ‹ˆλ‹€.

Local Reference

더미 λ…Έλ“œ 없이 λͺ¨λ“  λ…Έλ“œλ₯Ό λ™μΌν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆλŠ” Cμ–Έμ–΄μ˜ λ…νŠΉν•œ κΈ°λ²•μž…λ‹ˆλ‹€. tail λ…Έλ“œλ₯Ό κ°€λ¦¬ν‚€λŠ” 게 μ•„λ‹ˆλΌ, λ§ˆμ§€λ§‰ 링크(next 포인터 자체)의 μ£Όμ†Œλ₯Ό κ°€λ¦¬ν‚΅λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct node* BuildWithLocalRef() {
    struct node* head = NULL;
    struct node** lastPtrRef = &head;

    int i;
    for (i = 1; i < 6; i++) {
        Push(lastPtrRef, i);
        lastPtrRef = &((*lastPtrRef)->next);
    }

    return head;
}

int main() {
    struct node* head = BuildWithLocalRef();
    printf("%d\n", head->data); // 1
    return 0;
}

파이썬의 λ©”λͺ¨λ¦¬ μ£Όμ†Œ μ‘°μž‘ 및 μ°Έμ‘° μ œν•œ

νŒŒμ΄μ¬μ€ λ³€μˆ˜μ˜ λ©”λͺ¨λ¦¬ μ£Όμ†Œλ₯Ό 직접 μ‘°μž‘ν•˜κ±°λ‚˜, next ν•„λ“œ 자체의 μ°Έμ‘°λ₯Ό κ°€μ Έμ˜€λŠ” κΈ°λŠ₯이 μ—†μŠ΅λ‹ˆλ‹€.

Copy

Iterative + Dummy Node ν™œμš©

원본 리슀트λ₯Ό 순회(current)ν•˜λ©΄μ„œ μƒˆ 리슀트(new_list)λ₯Ό λ§Œλ“­λ‹ˆλ‹€. 이 λ•Œ Dummy Nodeλ₯Ό μ“°λ©΄ μ½”λ“œκ°€ 맀우 κΉ”λ”ν•΄μ§‘λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
def copy_list(head):
    current = head # 원본 순회용
    dummy = Node(0) # 볡사본을 μœ„ν•œ Dummy
    tail = dummy # λ³΅μ‚¬λ³Έμ˜ 끝을 가리킴

    while current is not None:
        tail.next = Node(current.data)

        tail = tail.next
        current = current.next

    return dummy.next

μž¬κ·€μ  μ ‘κ·Ό (Recursive)

1
2
3
4
5
6
7
8
def copy_list_recursive(head):
    if head is None:
        return None

    new_node = Node(head.data)
    new_node.next = copy_list_recursive(head.next)

    return new_node

파이썬의 μž¬κ·€ ν•œλ„μ™€ 리슀트 크기 μ œμ•½

λ¦¬μŠ€νŠΈκ°€ κΈΈλ©΄ 파이썬의 μž¬κ·€ ν•œλ„(Recursion Limit)에 걸릴 수 μžˆλ‹€λŠ” 점에 μ£Όμ˜ν•©λ‹ˆλ‹€.

Implementation in Java

1. Fields

first와 lastλŠ” μ‹€μ œ 데이터가 μ•„λ‹Œ Dummy μ—­ν• λ§Œ μˆ˜ν–‰ν•©λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
public class MyLinkedList<E> implements Iterable<E> {
    private int size = 0;

    private final Node<E> first;
    private final Node<E> last;

    public MyLinkedList() {
        first = new Node<>(null, null, null);
        last = new Node<>(first, null, null);
        first.next = last;
    }
}

2. Inner Class

이전 λ…Έλ“œλ₯Ό κ°€λ¦¬ν‚€λŠ” prevλ₯Ό μΆ”κ°€ν•˜μ—¬ 이쀑 μ—°κ²° ꡬ쑰λ₯Ό κ°€μ§‘λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyLinkedList<E> implements Iterable<E> {
    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;
        }
    }
}

3. Methods

linkLast(), linkBefore()

linkLast()λŠ” 리슀트의 κ°€μž₯ 뒀에 λ…Έλ“œλ₯Ό μΆ”κ°€(append)ν•˜κ³ , linkBefore()λŠ” νŠΉμ • λ…Έλ“œ(succ)의 μ•žμ— μ‚½μž…(insert)ν•©λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyLinkedList<E> implements Iterable<E> {
    void linkLast(E e) {
        linkBefore(e, last);
    }

    void linkBefore(E e, Node<E> succ) {
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        pred.next = newNode;
        size++;
    }
}

λ…Έλ“œ xλ₯Ό μ‚­μ œ(unlink)ν•©λ‹ˆλ‹€. GC νš¨μœ¨μ„ μœ„ν•΄ λ‚΄λΆ€ μ°Έμ‘°λ₯Ό λͺ¨λ‘ null둜 μ§€μ›λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyLinkedList<E> implements Iterable<E> {
    E unlink(Node<E> x) {
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        prev.next = next;
        next.prev = prev;

        x.item = null;
        x.prev = null;
        x.next = null;
        size--;
        return element;
    }
}

node()

μΈλ±μŠ€κ°€ μ ˆλ°˜λ³΄λ‹€ μ•žμ΄λ©΄ μ•žμ—μ„œ, λ’€λ©΄ λ’€μ—μ„œ νƒμƒ‰ν•©λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyLinkedList<E> implements Iterable<E> {
    Node<E> node(int index) {
        if (index < size / 2) {
            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;
        }
    }
}

λ§Œμ•½ Dummy Nodeκ°€ μ—†λ‹€λ©΄?

각 λ©”μ„œλ“œμ— λΆˆν•„μš”ν•œ null 체크가 λ°œμƒν•©λ‹ˆλ‹€.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class MyLinkedList<E> implements Iterable<E> {
    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;
        } else {
            l.next = newNode;
        }

        size++;
    }

    void linkBefore(E e, Node<E> succ) {
        // assert succ != null
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;

        if (pred == null) {
            first = newNode;
        } else {
            pred.next = newNode;
        }

        size++;
    }

    E unlink(Node<E> x) {
        // assert x != null
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = next;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        return element;
    }

    Node<E> node(int index) {
        if (index < size / 2) {
            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;
        }
    }
}

4. 곡개 API (Public Methods)

add()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class MyLinkedList<E> implements Iterable<E> {
    public boolean add(E e) {
        linkLast(e);
        return true;
    }

    public void add(int index, E element) {
        checkPositionIndex(index);

        if (index == size) {
            linkLast(element);
        } else {
            linkBefore(element, node(index));
        }
    }
}

get()

1
2
3
4
5
6
public class MyLinkedList<E> implements Iterable<E> {
    public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }
}

remove()

1
2
3
4
5
6
public class MyLinkedList<E> implements Iterable<E> {
    public E remove(int index) {
        checkElementIndex(index);
        return unlink(node(index));
    }
}

size()

1
2
3
4
5
public class MyLinkedList<E> implements Iterable<E> {
    public int size() {
        return size;
    }
}

toString()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class MyLinkedList<E> implements Iterable<E> {
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("[");
        Node<E> curr = first.next;
        while (curr != last) {
            sb.append(curr.item);
            if (curr.next != last) sb.append(", ");
            curr = curr.next;
        }
        sb.append("]");
        return sb.toString();
    }
}

Helpers

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class MyLinkedList<E> implements Iterable<E> {
    private void checkElementIndex(int index) {
        if (!isElementIndex(index)) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
    }

    private void checkPositionIndex(int index) {
        if (!isPositionIndex(index)) {
            throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
        }
    }

    private boolean isElementIndex(int index) {
        return index >= 0 && index < size;
    }

    private boolean isPositionIndex(int index) {
        return index >= 0 && index <= size;
    }
}

5. Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Main {
    public static void main(String[] args) {
        MyLinkedList<Integer> list = new MyLinkedList<>();

        // 1. μΆ”κ°€
        list.add(10);
        list.add(20);
        list.add(30);
        System.out.println("κΈ°λ³Έ μΆ”κ°€: " + list); // [10, 20, 30]

        // 2. 쀑간 μ‚½μž…
        list.add(1, 15);
        System.out.println("쀑간 μ‚½μž…: " + list); // [10, 15, 20, 30]

        // 3. μ‚­μ œ
        list.remove(2); 
        System.out.println("μ‚­μ œ ν›„:   " + list); // [10, 15, 30]
        
        // 4. μ΄ν„°λ ˆμ΄ν„° 순회
        System.out.print("순회: ");
        for (Integer i : list) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}

μ—¬κΈ°μ—μ„œ 전체 μ½”λ“œλ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

Summary

μ—°κ²° 리슀트λ₯Ό λ‹€λ£° λ•Œ, λ‹€μŒ 3κ°€μ§€ ν”„λ‘œκ·Έλž˜λ° 철학이 μ€‘μš”ν•©λ‹ˆλ‹€.

  1. Memory Model: λ³€μˆ˜λŠ” 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” μ°Έμ‘°μž…λ‹ˆλ‹€.
  2. Pointer Manipulation: current 같은 μž„μ‹œ 포인터λ₯Ό 적극적으둜 ν™œμš©ν•©λ‹ˆλ‹€.
  3. Dummy Node: if head is None 같은 μ§€μ €λΆ„ν•œ μ½”λ“œλ₯Ό μ—†μ• λŠ” 졜고의 νŒ¨ν„΄μœΌλ‘œ ν™œμš©ν•©λ‹ˆλ‹€.

References

This post is licensed under CC BY 4.0 by the author.