Linked List

Icarus<Wing>ยท2025๋…„ 4์›” 10์ผ

๐Ÿค”Linked List๋ž€?
: Node๋ผ๋Š” ๊ตฌ์กฐ์ฒด๊ฐ€ ์—ฐ๊ฒฐ๋˜๋Š” ํ˜•์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋งํ•œ๋‹ค.

๐Ÿ”–Node: ๋ฐ์ดํ„ฐ ๊ฐ’(value)๊ณผ ๋‹ค์Œ ์ฃผ์†Œ๊ฐ’(next)๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋Š” ๊ตฌ์กฐ์ฒด

๐Ÿ’ปNode๋Š” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํด๋ž˜์Šค๋กœ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค

class Node:
	def __init__(self, value = 0, next = None):
    	self.value = value
        self.next = next

๐Ÿ’ก์ง€๋‚œ ์‹œ๊ฐ„์— ์‚ดํŽด๋ณธ Array๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ Random Access๋ฅผ ์ด์šฉํ•ด์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜์˜€์ง€๋งŒ, Linked List๋Š” next ํฌ์ธํ„ฐ๋กœ ๋‹ค์Œ ๋…ธ๋“œ์˜ ์ฃผ์†Œ๋ฅผ ์ €์žฅํ•˜๋ฉด ๋…ผ๋ฆฌ์ ์œผ๋กœ ์—ฐ์†์„ฑ์„ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์ด ์ข€ ๋” ์ž์œ ๋กญ๋‹ค.

โš™๏ธ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ๋™์ž‘ ๊ณผ์ •

๐Ÿ’ป๋จผ์ € ๊ธฐ๋ณธ์ ์ธ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ํด๋ž˜์Šค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

class LinkedList:
	def __init__(self):
    	self.head = None
  • self.head: Linked List์˜ ์ฒซ ๋ฒˆ์งธ ์›์†Œ(๋…ธ๋“œ)๋ฅผ ๊ฐ€๋ฆฌํ‚ด
    • ๊ทธ๋Ÿฐ๋ฐ, ์ƒ์„ฑ ์ดˆ๊ธฐ์—๋Š” ๋…ธ๋“œ๊ฐ€ ๋น„์–ด์žˆ์œผ๋ฏ€๋กœ None์œผ๋กœ ์„ค์ •ํ•ด์ค€๋‹ค.

์šฐ๋ฆฌ๋Š” ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ๋…ธ๋“œ๋“ค์„ "๋…ผ๋ฆฌ์ ์œผ๋กœ" ์—ฐ์†์„ฑ์„ ๊ฐ–๊ฒŒ ํ•˜๋Š” append ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณผ ๊ฒƒ์ด๋‹ค. ๊ตฌ์ฒด์ ์œผ๋กœ ์‚ดํŽด๋ณด๊ธฐ ์ „์—, ๋‹ค์Œ 2๊ฐ€์ง€๋ฅผ ๋ฐ˜๋“œ์‹œ ๊ธฐ์–ตํ•˜์ž.
1. ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ๋Š” ๋ฌด์กฐ๊ฑด head๋กœ ๊ณ ์ •์‹œ์ผœ์ค€๋‹ค.
2. ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ๋Š” ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ ๋‹ค์Œ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค.
๐Ÿ‘‰๋งˆ์ง€๋ง‰ ๋…ธ๋“œ, ์ฆ‰ Node.next๊ฐ’์ด ์žˆ๋Š”์ง€ "๊ณ„์†" ํ™•์ธํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ•จ

๐Ÿ–ผ๏ธ์œ„์˜ 2๊ฐ€์ง€๋ฅผ ์ˆ™์ง€ํ•œ ์ฑ„๋กœ, ๊ตฌ์ฒด์ ์œผ๋กœ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ append ํ•จ์ˆ˜์˜ ๋™์ž‘ ๊ณผ์ •์„ ์‚ดํŽด๋ณด์ž.

  • head๋Š” ์ฒซ๋ฒˆ์งธ ๋…ธ๋“œ๋กœ ๊ณ ์ •์‹œ์ผœ์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ptr ๋ณ€์ˆ˜๋ฅผ ๋”ฐ๋กœ ๋ถˆ๋Ÿฌ์™€์„œ ์›€์ง์ด๊ฒŒ ํ•˜์˜€๋‹ค.

๐Ÿค”ptr๋Š” ๋ณ€์ˆ˜์— ๋ถˆ๊ณผํ•œ๋ฐ ์–ด๋–ป๊ฒŒ ptr.next๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?
โ—ptr = self.head = new_node, ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ptr์ด ๋…ธ๋“œ์˜ ์ฃผ์†Œ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ๋…ธ๋“œ์˜ next ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜๊ฐ€ ์žˆ๋‹ค.

๐Ÿ‘‡์ง€๊ธˆ๋ถ€ํ„ฐ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ CRUD๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์—, head๋Š” ํ•ญ์ƒ 1๋ฒˆ์งธ ๋…ธ๋“œ(์›์†Œ)๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๊ณ , ptr๋Š” ์ž์œ ์ž์žฌ๋กœ ์›€์ง์ผ ์ˆ˜ ์žˆ๋Š” ํฌ์ธํ„ฐ๋ผ๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•ด๋‘์ž.

๐Ÿ–ผ๏ธ์•„๋ž˜์˜ insert ๋™์ž‘ ๊ณผ์ •์„ ์‚ดํŽด๋ณด์ž.

  • idx๊ฐ€ 0์ธ ๊ฒฝ์šฐ์—๋„ idx > 0์ผ ๋•Œ์™€ ์•„์ด๋””์–ด๊ฐ€ ๋™์ผํ•˜๋‹ค.

๐Ÿ’ปappend, get, insert ํ•จ์ˆ˜(in Java)

class Node {
    int value;
    Node next;

    public Node(int value) {
        this.value = value;
        this.next = null;
    }
}

public class MyLinkedList {
    Node head;
    
    public MyLinkedList() {
    	this.head = null;
    }
    
    public void append(int value) {
        Node newNode = new Node(value);
        if (head == null) {
            head = newNode;
        } else {
            Node ptr = head;
            while (ptr.next != null)
                ptr = ptr.next;
            ptr.next = newNode;
        }
    }

    public int get(int idx) {
        Node ptr = head;
        for (int i = 0; i < idx; i++) {
            ptr = ptr.next;
        }
        return ptr.value;
    }

    public void insert(int idx, int value) {
        Node newNode = new Node(value);
        Node ptr = head;

        if (idx == 0) {
            newNode.next = head;
            head = newNode;
        } else {
            for (int i = 0; i < idx - 1; i++) {
                ptr = ptr.next;
            }
            newNode.next = ptr.next;
            ptr.next = newNode;
        }
    }
    
}

๐Ÿ’กnext ํฌ์ธํ„ฐ๋ฅผ Node ํƒ€์ž…์œผ๋กœ ์„ ์–ธํ•œ ์ด์œ ๋Š” ๊ทธ๋ž˜์•ผ ๋‹ค๋ฅธ Node ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.
๐Ÿ’กappend ํ•จ์ˆ˜๋Š” ์Šคํƒ ์˜์—ญ์—์„œ ์ƒ์„ฑ๋˜์–ด ์ง€์—ญ ๋ณ€์ˆ˜๋“ค์ด ์‚ฌ๋ผ์ง€์ง€๋งŒ, ํž™ ์˜์—ญ์— ์žˆ๋Š” Node ๊ฐ์ฒด๋Š” ์—ฌ์ „ํžˆ ๋‚จ์•„์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํฌ์ธํ„ฐ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋Š” ์ฃผ์†Œ๊ฐ’๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์œ ์ง€๋œ๋‹ค.

๐Ÿ–ผ๏ธremove ๋™์ž‘ ๊ณผ์ •๋„ insert์™€ ์œ ์‚ฌํ•˜๋‹ค.

๐Ÿ’ปremove(idx) ํ•จ์ˆ˜

public void remove(int idx) {
        Node ptr = head;

        if (idx == 0) {
            head = head.next; // head๋ฅผ ์ด๋™
        } else {
            for (int i = 0; i < idx - 1; i++) {
                ptr = ptr.next; // ๋ฐ”๋กœ ์ง์ „ ๋…ธ๋“œ๊นŒ์ง€ ์ด๋™
            }
            ptr.next = ptr.next.next; // ์‚ญ์ œํ•˜๋ ค๊ณ  ํ•˜๋Š” ๋…ธ๋“œ์˜ next๊ฐ’์„ ๋ฐ”๋กœ ์ง์ „ ๋…ธ๋“œ๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•จ
        }
    }

โš™๏ธtail์„ ์ถ”๊ฐ€ํ•œ append ํ•จ์ˆ˜

์ด์ „์— ๊ตฌํ˜„ํ•œ append ํ•จ์ˆ˜๋Š” ptr ๋…ธ๋“œ๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด while๋ฌธ์„ ํƒ€๊ณ  ์ด๋™์‹œ์ผฐ์ง€๋งŒ, tail์ด ํ•ญ์ƒ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋งŒ๋“ค๋ฉด append ํ•จ์ˆ˜๋Š” O(1)๋งŒ ๊ฑธ๋ฆฌ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ปappend(value)ํ•จ์ˆ˜ ๊ตฌํ˜„


public class LinkedList {
	Node head;
    Node tail;
    
    public LinkedList() {
    	this.head = null;
        this.tail = null;
    }
    
	public void append(int value) {
        Node newNode = new Node(value);
        if (head == null) {
            head = newNode;
            tail = newNode;
        } else {
            tail.next = newNode;
            tail = tail.next; // tail์€ ํ•ญ์ƒ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ด
        }
    }
} 
  • ๊ฒฐ๊ตญ, head๋Š” ํ•ญ์ƒ 1๋ฒˆ์งธ ๋…ธ๋“œ(์›์†Œ)๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ํ•˜๊ณ , tail์€ ํ•ญ์ƒ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ(์›์†Œ)๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ๋งŒ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.

โš™๏ธDoubly LinkedList์˜ append ๋™์ž‘ ๊ณผ์ •

๋ณ„๊ฑฐ์—†๋‹ค. ๊ทธ๋ƒฅ Node ํด๋ž˜์Šค์—์„œ ์ด์ „์˜ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ธฐ ์œ„ํ•œ prev ํฌ์ธํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์œ„์˜ ๊ตฌํ˜„ํ•œ tail ํฌ์ธํ„ฐ๋ฅผ ํ™œ์šฉํ•œ append ํ•จ์ˆ˜์—์„œ ์•ฝ๊ฐ„์˜ ์ฝ”๋“œ๋งŒ ์ˆ˜์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๐Ÿ’ป๋”๋ธ” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ append ํ•จ์ˆ˜

class DoublyNode {
    int value;
    DoublyNode next;
    DoublyNode prev;

    public DoublyNode(int value) {
        this.value = value;
        this.next = null;
        this.prev = null;
    }
}

public class MyDoublyLinkedList {
    DoublyNode head = null;
    DoublyNode tail = null;

    public void append(int value) {
        DoublyNode newNode = new DoublyNode(value);
        if (head == null) {
            head = newNode;
            tail = newNode;
        } else {
            tail.next = newNode;
            newNode.prev = tail;
            tail = tail.next; // tail ์—…๋ฐ์ดํŠธ
        }
    }
}

โฐLinkedList์™€ Array์˜ ์‹œ๊ฐ„๋ณต์žก๋„ ๋น„๊ต

์•ž์—๋Š” ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋ฌด์—‡์ด๊ณ  CRUD ๋™์ž‘ ๊ณผ์ •์ด ์–ด๋–ป๊ฒŒ ๋˜๋Š”์ง€ ์‚ฌ์„ค์ด ์ข€ ๊ธธ์—ˆ์ง€๋งŒ, ๋ฌผ๋ฆฌ์ ์ธ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌํ˜„ํ•œ Array์™€ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๋น„๊ตํ•ด๋ณด๋ฉด์„œ ์™œ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”์ง€๋ฅผ ์•Œ์•„๋ณด์ž.

๐Ÿ“ขArray๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ Random Access๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฐ์†์„ฑ์„ ๊ฐ–๋Š” ๋ฐ˜๋ฉด, Linked List๋Š” ๋ฌผ๋ฆฌ์ ์œผ๋กœ ์—ฐ์†์„ฑ์„ ๊ฐ–์ง€๋Š” ์•Š์ง€๋งŒ, next ํฌ์ธํ„ฐ๋กœ ๋‹ค์Œ ๋…ธ๋“œ์˜ ์ฐธ์กฐ๊ฐ’์„ ๊ฐ–๊ธฐ ๋•Œ๋ฌธ์— "๋…ผ๋ฆฌ์ ์œผ๋กœ ์—ฐ์†์„ฑ์„ ๊ฐ–๋Š”๋‹ค"๋Š” ์ ์— ์œ ์˜ํ•˜์ž.

Linked ListArray
access/updateO(N)O(1)
insert_frontO(1)O(N)
insert_atO(N)O(N)
insert_backO(N) ๋˜๋Š” O(1)O(1)
remove_frontO(1)O(N)
remove_atO(N)O(N)
remove_backO(N) ๋˜๋Š” O(1)O(1)
  • access/update: ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ๊ฒฝ์šฐ next ํฌ์ธํ„ฐ๋ฅผ ํƒ€์•ผํ•˜๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ, Array๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ Random Access๋ฅผ ์ด์šฉํ•ด์„œ O(1)๋งŒ ๊ฑธ๋ฆฐ๋‹ค.
  • insert_front/remove_front: ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” head์˜ ํฌ์ธํ„ฐ๋ฅผ ์ด์šฉ๋งŒ ํ•˜๋ฉด ๋˜๊ธฐ ๋•Œ๋ฌธ์— O(1)์ด ๊ฑธ๋ฆฌ๋Š” ๋ฐ˜๋ฉด, Array๋Š” ์›์†Œ๋“ค์„ ๋ชจ๋‘ right-shift ํ•ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— O(N)์ด ๊ฑธ๋ฆฐ๋‹ค.
    • insert_back/remove_back: ์œ„์™€ ๋‹ค๋ฅด๊ฒŒ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋Š” next ํฌ์ธํ„ฐ๋ฅผ ํƒ€์•ผ๋˜์„œ O(N)์ด ๊ฑธ๋ฆฌ๋Š” ๊ฒƒ๊ณผ ๋‹ฌ๋ฆฌ, Array๋Š” ๊ทธ๋ƒฅ ๋งจ ๋’ค์— ์‚ฝ์ž…ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œํ•˜๋ฉด ๋˜์„œ O(1)์ด ๊ฑธ๋ฆฐ๋‹ค.

๐Ÿ’กinsert_back๊ณผ remove_back์˜ ๊ฒฝ์šฐ tail ํฌ์ธํ„ฐ๊ฐ€ ์ถ”๊ฐ€๋œ Doubly Linked List๋กœ ๊ตฌํ˜„๋˜์–ด์žˆ์œผ๋ฉด O(1)๋งŒ ๊ฑธ๋ฆฐ๋‹ค.

๐Ÿ“๊ฒฐ๊ตญ, (๋”๋ธ”)๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ ๋Š” head ํฌ์ธํ„ฐ(ํ•„์š”ํ•˜๋‹ค๋ฉด tail ํฌ์ธํ„ฐ)๋ฅผ ์‚ฌ์šฉํ•จ์œผ๋กœ์จ ์‚ฝ์ž…/์‚ญ์ œ๊ฐ€ O(1)๋งŒ ๊ฑธ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

profile
๋ชจ๋“  ์ฝ”๋“œ์—๋Š” ์ด์œ ๊ฐ€ ์žˆ๊ธฐ์— ์›์ธ์„ ํŒŒ์•…ํ•  ๋•Œ๊นŒ์ง€ ์ง‘์š”ํ•˜๊ฒŒ ํƒ๊ตฌํ•˜๋Š” ๊ฒƒ์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€