๐Ÿ’ป Knowledge/์ž๋ฃŒ๊ตฌ์กฐ

๐Ÿง‘๐Ÿป‍๐Ÿ’ป Doubly Linked List ์ง์ ‘ ๊ตฌํ˜„ (JAVA)

ming412 2023. 9. 22. 11:25

1. Doubly Linked List ์ž๋ฃŒ๊ตฌ์กฐ

https://ming412.tistory.com/159

 

Singly Linked List vs Doubly Linked List vs Circular Linked List ์‹œ๊ฐ„๋ณต์žก๋„ & ์‚ฌ์šฉ ์‚ฌ๋ก€

Singly Linked List (๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ) ๊ฐ ์š”์†Œ๊ฐ€ ๋‹ค์Œ ์š”์†Œ๋งŒ ๊ฐ€๋ฆฌํ‚ค๋Š” ๋‹จ์ผ ๋ฐฉํ–ฅ ๊ตฌ์กฐ์ด๋‹ค. ์‹œ๊ฐ„ ๋ณต์žก๋„ ๊ฒ€์ƒ‰ - ์ฒ˜์Œ ๋…ธ๋“œ(head)๋ถ€ํ„ฐ ํ•˜๋‚˜์”ฉ ์ˆœํšŒํ•˜๋ฉฐ ์›ํ•˜๋Š” ๊ฐ’์„ ์ฐพ์•„์•ผ ํ•˜๋ฏ€๋กœ O(n) ์‚ฝ์ž… - ์‹œ์ž‘์— ์›

ming412.tistory.com

 

2. Doubly Linked List ์ง์ ‘ ๊ตฌํ˜„ํ•˜๊ธฐ

1) ADT (Abstract Data Type) ์ •์˜

- ๋ฐ์ดํ„ฐ (Data)

    - Node

        - data: ๋ฐ์ดํ„ฐ

        - prev: ์ด์ „ ๋…ธ๋“œ๋ฅผ ์ฐธ์กฐ

        - next: ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ์ฐธ์กฐ

    - MyDoublyLinkedList

        - head: ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ์ฒ˜์Œ ์š”์†Œ๋ฅผ ์ฐธ์กฐ

        - tail: ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋ฅผ ์ฐธ์กฐ

        - size: ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด

 

- ์ž‘์—… 

    - search(idx): ํŠน์ • ์œ„์น˜์˜ ๋…ธ๋“œ ๋ฐ˜ํ™˜

    - addFirst(e): ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž์— ์š”์†Œ ์ถ”๊ฐ€

    - addLast(e): ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ๋งˆ์ง€๋ง‰์— ์š”์†Œ ์ถ”๊ฐ€

    - add(idx, e): ํŠน์ • ์œ„์น˜์— ์š”์†Œ ์ถ”๊ฐ€

    - get(idx): ํŠน์ • ์œ„์น˜์˜ ๋…ธ๋“œ์˜ ๊ฐ’ ๋ฐ˜ํ™˜

    - set(idx, e): ํŠน์ • ์œ„์น˜์˜ ์š”์†Œ๋ฅผ e๋กœ ๋ณ€ํ™˜

    - removeFirst(): ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์•ž ์š”์†Œ ์‚ญ์ œ

    - removeLast(): ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ๋ ์š”์†Œ ์‚ญ์ œ

    - remove(idx): ํŠน์ • ์œ„์น˜์˜ ์š”์†Œ ์‚ญ์ œ

 

2) Node ํด๋ž˜์Šค ์ •์˜

๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋…ธ๋“œ๋Š” ๋‹ค์Œ ๋…ธ๋“œ์˜ ์ฐธ์กฐ(next)๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋…ธ๋“œ๋Š” ๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋…ธ๋“œ์™€ ๋‹ค๋ฅด๊ฒŒ ์ด์ „ ๋…ธ๋“œ์˜ ์ฐธ์กฐ(prev)๋„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. 

๋”ฐ๋ผ์„œ data์™€ prev, next๋ฅผ ์„ ์–ธํ•ด์ค€๋‹ค.

public class Node<E> {
	public E data;
	public Node<E> prev;
	public Node<E> next;

	public Node(E data) {
		this.data = data;
		this.prev = null;
		this.next = null;
	}
}

 

3) MyDoublyLinkedList ํด๋ž˜์Šค ์ •์˜

์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” head์™€ tail ํฌ์ธํ„ฐ๋กœ ํ˜„์žฌ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ์ œ์ผ ์ฒซ ๋…ธ๋“œ์™€ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ์ฐธ์กฐํ•˜๊ณ  ์žˆ๋‹ค.

๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋กœ size๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด, ๋ฆฌ์ŠคํŠธ์˜ ๊ธธ์ด๊ฐ€ ๊ถ๊ธˆํ•  ๋•Œ ๋ชจ๋“  ๋…ธ๋“œ๋ฅผ ์ˆœํšŒํ•˜๋ฉฐ ์นด์šดํŠธํ•˜์ง€ ์•Š์•„๋„ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ํŽธ๋ฆฌํ•˜๋‹ค.

public class MyDoublyLinkedList<E> {
	private Node<E> head;
	private Node<E> tail;
	private int size;

	public MyDoublyLinkedList() {
		this.head = null;
		this.tail = null;
		this.size = 0;
	}
}

 

4) search ๊ตฌํ˜„

search ๋ฉ”์„œ๋“œ๋Š” add์™€ remove์—์„œ ์‚ฌ์šฉ๋  ๋‚ด๋ถ€ ๋ฉ”์„œ๋“œ์ด๋‹ค.

๋…ธ๋“œ๋ฅผ ํŠน์ • ์œ„์น˜์— ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ํŠน์ • ์œ„์น˜์— ์กด์žฌํ•˜๋Š” ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•  ๋•Œ, ๋Œ€์ƒ ๋…ธ๋“œ๋ฅผ ๋จผ์ € ์ฐพ์•„์•ผ ํ•œ๋‹ค.

๋Œ€์ƒ ๋…ธ๋“œ๋ฅผ ์ฐพ์„ ๋•Œ ์‚ฌ์šฉ๋  ์˜ˆ์ •์ด๋‹ค. 

public Node<E> search(int idx) {
    if (size < idx) {
        throw new IndexOutOfBoundsException();
    }
    Node<E> cur = head;
    for (int i=0; i<idx; i++) {
        cur = cur.next;
    }
    return cur;
}

 

5) add ๊ตฌํ˜„

addFirst - ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์ฒ˜์Œ์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ˜„์žฌ ๋ฆฌ์ŠคํŠธ์— ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ํ˜น์€ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ๋Š”์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค.

 

ํ˜„์žฌ ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ๋‹ค๋ฉด head์™€ tail ๋ชจ๋‘๋ฅผ newNode๋กœ ๊ฐฑ์‹ ํ•˜๊ณ ,

๋น„์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด newNode์™€ ๊ธฐ์กด head ๋…ธ๋“œ๋ฅผ ์™„๋ฒฝํžˆ ์—ฐ๊ฒฐํ•ด์ค€ ๋’ค head ๋…ธ๋“œ๋ฅผ newNode๋กœ ๊ฐฑ์‹ ํ•ด์•ผ ํ•œ๋‹ค.

 

"์™„๋ฒฝํžˆ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค"๋Š” ๋ง์˜ ์˜๋ฏธ๋Š” ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ์ ˆ์ฐจ๋ฅผ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

1. newNode์˜ next๊ฐ€ ๊ธฐ์กด head ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•œ๋‹ค.

2. ๊ธฐ์กด head ๋…ธ๋“œ์˜ prev๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•œ๋‹ค.

 

๋‹จ์ผ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ๋Š” ๋ฆฌ์ŠคํŠธ๊ฐ€ ๋น„์–ด์žˆ์ง€ ์•Š์€์ง€ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด if (head != null) ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ,

์•„๋ž˜์ฒ˜๋Ÿผ size๋ฅผ ์ด์šฉํ•ด์„œ ํ™•์ธํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

public void addFirst(E data) {
    Node<E> newNode = new Node<>(data);
    if (size == 0) {
        head = tail = newNode;
    } else {
        newNode.next = head; // newNode์˜ next๊ฐ€ ๊ธฐ์กด ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
        head.prev = newNode; // ๊ธฐ์กด ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ์˜ prev๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
        head = newNode; // head ๋…ธ๋“œ ๊ฐฑ์‹  (tail์€ ๊ทธ๋Œ€๋กœ)
    }
    size++;
}

 

addLast - ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ๋์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ ๋งˆ์ง€๋ง‰์— ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ๋•Œ์—๋Š” newNode์™€ ๊ธฐ์กด tail ๋…ธ๋“œ๋ฅผ ์™„๋ฒฝํžˆ ์—ฐ๊ฒฐํ•ด์ค€ ๋’ค tail ๋…ธ๋“œ๋ฅผ newNode๋กœ ๊ฐฑ์‹ ํ•ด์•ผ ํ•œ๋‹ค.

 

"์™„๋ฒฝํžˆ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค"๋Š” ๋ง์˜ ์˜๋ฏธ๋Š” ์•„๋ž˜ ๋‘ ๊ฐ€์ง€ ์ ˆ์ฐจ๋ฅผ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

1. newNode์˜ prev๊ฐ€ ๊ธฐ์กด tail ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•œ๋‹ค.

2. ๊ธฐ์กด tail ๋…ธ๋“œ์˜ next๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ํ•œ๋‹ค.

public void addLast(E data) {
    Node<E> newNode = new Node<>(data);
    if (size == 0) {
        head = tail = newNode;
    } else {
        newNode.prev = tail; // newNode์˜ prev๊ฐ€ ๊ธฐ์กด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
        tail.next = newNode; // ๊ธฐ์กด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์˜ next๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
        tail = newNode; // tail ๋…ธ๋“œ ๊ฐฑ์‹ 
    }
    size++;
}

 

add - ๋ฆฌ์ŠคํŠธ์˜ ํŠน์ • ์œ„์น˜์— ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค.

targetNode๋Š” newNode๊ฐ€ ์‚ฝ์ž…๋˜๊ธฐ ์›ํ•˜๋Š” ์œ„์น˜์— ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ๋งํ•œ๋‹ค.

๋งŒ์•ฝ idx๊ฐ€ 0๋˜๋Š” size๋ผ๋ฉด ์•ž์„œ ๋งŒ๋“ค์—ˆ๋˜ addFirst์™€ addLast๋ฅผ ํ™œ์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด search(idx)๋ฅผ ํ†ตํ•ด targetNode๋ฅผ ์ฐพ๋Š”๋‹ค.

 

์—ฐ๊ฒฐ์ด ๋Š๊ธฐ์ง€ ์•Š๋„๋ก, targetNode์˜ ์ด์ „(prev) ๋…ธ๋“œ์™€ newNode๋ฅผ ๋จผ์ € ์—ฐ๊ฒฐํ•ด์•ผ ํ•œ๋‹ค โ—๏ธ

์ด๋•Œ targetNode์˜ ์ด์ „ ๋…ธ๋“œ์˜ next ์ฐธ์กฐ๊ฐ’์„ newNode๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š”๋ฐ, ํ•ด๋‹น ์—ฐ์‚ฐ์ด targetNode.prev.next = newNode ์ด๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  newNode์™€ targetNode๋ฅผ ์—ฐ๊ฒฐํ•˜๋ฉด ๋œ๋‹ค.

public void add(int idx, E data) {
    Node<E> newNode = new Node<>(data);
    if (idx < 0 || idx > size) {
        throw new IndexOutOfBoundsException();
    }
    if (idx == 0) {
        addFirst(data);
    } else if (idx == size) {
        addLast(data);
    } else {
        Node<E> targetNode = search(idx);
        // newNode์™€ targetNode์˜ ์ด์ „ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐ
        targetNode.prev.next = newNode;
        newNode.prev = targetNode.prev;
        // newNode์™€ targetNode๋ฅผ ์—ฐ๊ฒฐ
        targetNode.prev = newNode;
        newNode.next = targetNode;
        
        size++;
    }
}

 

6) get ๊ตฌํ˜„

get ํ•จ์ˆ˜๋Š” ํŠน์ • ์œ„์น˜์˜ ๋…ธ๋“œ๋ฅผ ์ฐพ์•„ ๊ทธ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๋ฉด ๋œ๋‹ค.

๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” search ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•˜๋ฉด ๋˜๊ณ , idx์˜ ๋ฒ”์œ„๊นŒ์ง€ ๊ฒ€์ฆํ•˜์ž.

public E get(int idx) {
    if (idx < 0 || idx > size) {
        throw new IndexOutOfBoundsException();
    }
    return search(idx).data;
}

 

7) set ๊ตฌํ˜„

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ search ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด์„œ idx ์œ„์น˜์— ์žˆ๋Š” ๋…ธ๋“œ๋ฅผ ๊ฐ€์ ธ์˜จ ๋’ค data ๊ฐ’๋งŒ ๋ณ€๊ฒฝํ•˜๋ฉด ๋œ๋‹ค.

public void set(int idx, E data) {
    if (idx < 0 || idx > size) {
        throw new IndexOutOfBoundsException();
    }
    search(idx).data = data;
}

 

8) remove ๊ตฌํ˜„

removeFirst - ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ์ฒ˜์Œ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

๋งจ ์ฒ˜์Œ ์š”์†Œ๋Š” head ๋…ธ๋“œ๋ฅผ ๋งํ•œ๋‹ค.

head ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค๋Š” ๊ฒƒ์€, head ๋…ธ๋“œ์˜ ๋ฐ”๋กœ ๋‹ค์Œ ๋…ธ๋“œ๊ฐ€ ์ƒˆ๋กœ์šด head ๋…ธ๋“œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ head ๋…ธ๋“œ์˜ ๋‹ค์Œ(next) ๋…ธ๋“œ์˜ prev๋ฅผ null๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น ์—ฐ์‚ฐ์ด head.next.prev = null ์ด๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋ฆฌ์ŠคํŠธ์˜ head ๊ฐ’์„ ๊ธฐ์กด head ๋…ธ๋“œ์˜ ๋ฐ”๋กœ ๋‹ค์Œ ๋…ธ๋“œ๋กœ ๊ฐฑ์‹ ํ•˜๋ฉด ๋œ๋‹ค.

public void removeFirst() {
    if (size == 0) {
        throw new IndexOutOfBoundsException();
    }
    head.next.prev = null; // head ๋…ธ๋“œ์™€ head ๋…ธ๋“œ์˜ ๋‹ค์Œ ๋…ธ๋“œ์™€์˜ ์—ฐ๊ฒฐ ๋Š๊ธฐ
    head = head.next; // head ๋…ธ๋“œ ๊ฐฑ์‹ 
    size--;
}

 

removeLast - ๋ฆฌ์ŠคํŠธ์˜ ๋งจ ๋ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

๋งจ ๋งˆ์ง€๋ง‰ ์š”์†Œ๋Š” tail ๋…ธ๋“œ๋ฅผ ๋งํ•œ๋‹ค.

tail ๋…ธ๋“œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค๋Š” ๊ฒƒ์€, tail ๋…ธ๋“œ์˜ ๋ฐ”๋กœ ์•ž ๋…ธ๋“œ๊ฐ€ ์ƒˆ๋กœ์šด tail ๋…ธ๋“œ๊ฐ€ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ tail ๋…ธ๋“œ์˜ ์ด์ „(prev) ๋…ธ๋“œ์˜ next๋ฅผ null๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น ์—ฐ์‚ฐ์ด tail.prev.next = null ์ด๋‹ค.

 

๊ทธ๋ฆฌ๊ณ  ๋ฆฌ์ŠคํŠธ์˜ tail ๊ฐ’์„ ๊ธฐ์กด tail ๋…ธ๋“œ์˜ ๋ฐ”๋กœ ์•ž ๋…ธ๋“œ๋กœ ๊ฐฑ์‹ ํ•˜๋ฉด ๋œ๋‹ค. 

public void removeLast() {
    if (size == 0) {
        throw new IndexOutOfBoundsException();
    }
    tail.prev.next = null; // tail ๋…ธ๋“œ์˜ ์ด์ „ ๋…ธ๋“œ์™€ tail ๋…ธ๋“œ์˜ ์—ฐ๊ฒฐ ๋Š๊ธฐ
    tail = tail.prev; // head ๋…ธ๋“œ ๊ฐฑ์‹ 
    size--;
}

 

remove - ๋ฆฌ์ŠคํŠธ์˜ ํŠน์ • ์œ„์น˜์˜ ์š”์†Œ๋ฅผ ์‚ญ์ œํ•œ๋‹ค.

targetNode๋Š” ์‚ญ์ œํ•  ๋…ธ๋“œ๋ฅผ ๋งํ•œ๋‹ค.

๋งŒ์•ฝ idx๊ฐ€ 0๋˜๋Š” size๋ผ๋ฉด ์•ž์„œ ๋งŒ๋“ค์—ˆ๋˜ removeFirst์™€ removeLast๋ฅผ ํ™œ์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด search(idx)๋ฅผ ํ†ตํ•ด targetNode๋ฅผ ์ฐพ๋Š”๋‹ค.

 

๋…ธ๋“œ ์‚ญ์ œ๋Š”, ์‚ญ์ œ๋  ๋…ธ๋“œ๋ฅผ ๊ณ ๋ฆฝ์‹œํ‚ค๋ฉด ๋œ๋‹ค.

์ฆ‰, ์‚ญ์ œ๋  ๋…ธ๋“œ์˜ ์•ž/๋’ค ๋…ธ๋“œ์™€ ์‚ญ์ œ๋  ๋…ธ๋“œ์™€์˜ ์—ฐ๊ฒฐ์„ ๋Š๊ธฐ๋งŒ ํ•˜๋ฉด ์ฐธ์กฐ๋˜์ง€ ์•Š๋Š” ๋…ธ๋“œ๋Š” GC๊ฐ€ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค. 

 

targetNode ์ด์ „ ๋…ธ๋“œ์˜ next๋ฅผ targetNode ๋‹ค์Œ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐํ•˜๊ณ ,

targetNode ๋‹ค์Œ ๋…ธ๋“œ์˜ prev๋ฅผ targetNode ์ด์ „ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐํ•ด targetNode๋ฅผ ๊ณ ๋ฆฝ์‹œํ‚จ๋‹ค. 

public void remove(int idx) {
    if (idx < 0 || idx > size) {
        throw new IndexOutOfBoundsException();
    }
    if (idx == 0) {
        removeFirst();
    } else if (idx == size - 1) {
        removeLast();
    } else {
        Node<E> targetNode = search(idx);
        targetNode.prev.next = targetNode.next; // targetNode ์ด์ „๋…ธ๋“œ์˜ next๋ฅผ targetNode ๋‹ค์Œ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐ
        targetNode.next.prev = targetNode.prev; // targetNode ๋‹ค์Œ ๋…ธ๋“œ์˜ prev๋ฅผ targetNode ์ด์ „ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐ
        size--;
    }
}

 

9) toString ์˜ค๋ฒ„๋ผ์ด๋”ฉ

์•„๋ž˜์ฒ˜๋Ÿผ toString์„ ์˜ค๋ฒ„๋ผ์ด๋”ฉํ•˜๋ฉด ๋””๋ฒ„๊น…ํ•˜๊ธฐ ์ข‹๋‹ค.

@Override
public String toString() {
    Node<E> cur = head;
    while (cur != null) {
        System.out.print(cur.data + " ");
        cur = cur.next;
    }
    System.out.println();
    return "MyDoublyLinkedList{" +
        "head=" + head.data +
        ", tail=" + tail.data +
        ", size=" + size +
        '}';
}

 

10) ์ „์ฒด ์ฝ”๋“œ

package doubly;

import doubly.Node;

public class MyDoublyLinkedList<E> {
	private Node<E> head;
	private Node<E> tail;
	private int size;

	public MyDoublyLinkedList() {
		this.head = null;
		this.tail = null;
		this.size = 0;
	}

	public Node<E> search(int idx) {
		if (size < idx) {
			throw new IndexOutOfBoundsException();
		}
		Node<E> cur = head;
		for (int i=0; i<idx; i++) {
			cur = cur.next;
		}
		return cur;
	}

	public void addFirst(E data) {
		Node<E> newNode = new Node<>(data);
		if (size == 0) {
			head = tail = newNode;
		} else {
			newNode.next = head; // newNode์˜ next๊ฐ€ ๊ธฐ์กด ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
			head.prev = newNode; // ๊ธฐ์กด ์ฒซ ๋ฒˆ์งธ ๋…ธ๋“œ์˜ prev๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
			head = newNode; // head ๋…ธ๋“œ ๊ฐฑ์‹  (tail์€ ๊ทธ๋Œ€๋กœ)
		}
		size++;
	}

	public void addLast(E data) {
		Node<E> newNode = new Node<>(data);
		if (size == 0) {
			head = tail = newNode;
		} else {
			newNode.prev = tail; // newNode์˜ prev๊ฐ€ ๊ธฐ์กด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
			tail.next = newNode; // ๊ธฐ์กด ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์˜ next๊ฐ€ newNode๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก
			tail = newNode; // tail ๋…ธ๋“œ ๊ฐฑ์‹ 
		}
		size++;
	}

	public void add(int idx, E data) {
		Node<E> newNode = new Node<>(data);
		if (idx < 0 || idx > size) {
			throw new IndexOutOfBoundsException();
		}
		if (idx == 0) {
			addFirst(data);
		} else if (idx == size) {
			addLast(data);
		} else {
			Node<E> targetNode = search(idx);
			// newNode์™€ targetNode์˜ ์ด์ „ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐ
			targetNode.prev.next = newNode;
			newNode.prev = targetNode.prev;
			// newNode์™€ targetNode๋ฅผ ์—ฐ๊ฒฐ
			targetNode.prev = newNode;
			newNode.next = targetNode;

			size++;
		}
	}

	public E get(int idx) {
		if (idx < 0 || idx > size) {
			throw new IndexOutOfBoundsException();
		}
		return search(idx).data;
	}

	public void set(int idx, E data) {
		if (idx < 0 || idx > size) {
			throw new IndexOutOfBoundsException();
		}
		search(idx).data = data;
	}

	public void removeFirst() {
		if (size == 0) {
			throw new IndexOutOfBoundsException();
		}
		head.next.prev = null; // head ๋…ธ๋“œ์™€ head ๋…ธ๋“œ์˜ ๋‹ค์Œ ๋…ธ๋“œ์™€์˜ ์—ฐ๊ฒฐ ๋Š๊ธฐ
		head = head.next; // head ๋…ธ๋“œ ๊ฐฑ์‹ 
		size--;
	}

	public void removeLast() {
		if (size == 0) {
			throw new IndexOutOfBoundsException();
		}
		tail.prev.next = null; // tail ๋…ธ๋“œ์˜ ์ด์ „ ๋…ธ๋“œ์™€ tail ๋…ธ๋“œ์˜ ์—ฐ๊ฒฐ ๋Š๊ธฐ
		tail = tail.prev; // head ๋…ธ๋“œ ๊ฐฑ์‹ 
		size--;
	}

	public void remove(int idx) {
		if (idx < 0 || idx > size) {
			throw new IndexOutOfBoundsException();
		}
		if (idx == 0) {
			removeFirst();
		} else if (idx == size - 1) {
			removeLast();
		} else {
			Node<E> targetNode = search(idx);
			targetNode.prev.next = targetNode.next; // targetNode ์ด์ „๋…ธ๋“œ์˜ next๋ฅผ targetNode ๋‹ค์Œ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐ
			targetNode.next.prev = targetNode.prev; // targetNode ๋‹ค์Œ ๋…ธ๋“œ์˜ prev๋ฅผ targetNode ์ด์ „ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐ
			size--;
		}
	}

	@Override
	public String toString() {
		Node<E> cur = head;
		while (cur != null) {
			System.out.print(cur.data + " ");
			cur = cur.next;
		}
		System.out.println();
		return "MyDoublyLinkedList{" +
			"head=" + head.data +
			", tail=" + tail.data +
			", size=" + size +
			'}';
	}
}
public class Main {
	public static void main(String[] args) {
		MyDoublyLinkedList<String> linkedList = new MyDoublyLinkedList<>();
		linkedList.addFirst("A");
		linkedList.addFirst("B");
		linkedList.addLast("C");
		linkedList.addLast("D");
		System.out.println(linkedList.toString());

		linkedList.add(1, "E");
		System.out.println(linkedList.toString());

		System.out.println(linkedList.get(1));
		linkedList.set(1, "F");
		System.out.println(linkedList.toString());

		linkedList.remove(3);
		linkedList.remove(0);
		System.out.println(linkedList.toString());
	}
}

์‹คํ–‰ ๊ฒฐ๊ณผ