๐Ÿ“‚ ์ž๋ฃŒ๊ตฌ์กฐ

[์ž๋ฃŒ๊ตฌ์กฐ] 04. ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Linked List)

seonghye0n 2023. 6. 9. 02:10

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Linked List)

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ๋–จ์–ด์ง„ ๊ณต๊ฐ„์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋“ค์„ ํฌ์ธํ„ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ด๋‹ค. ๋ฐฐ์—ด์€ ์ˆœ์ฐจ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ๊ณต๊ฐ„์— ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์—ฌ์„œ ๋ฐฐ์—ด๊ณผ๋Š” ๋‹ค๋ฅด๋‹ค.

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ๋…ธ๋“œ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์„œ ๋…ธ๋“œ๋ž€ ๋ฐ์ดํ„ฐ์™€ ํฌ์ธํ„ฐ๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” ๊ณต๊ฐ„ ๋‹จ์œ„์ด๋‹ค.

ํฌ์ธํ„ฐ๋Š” ๋‹ค์Œ ๋…ธ๋“œ์˜ ์ฃผ์†Œ ๊ฐ’์„ ์ €์žฅํ•˜๋Š” ๊ณต๊ฐ„์ด๋‹ค.

 

์žฅ์ 

  • ๋ฏธ๋ฆฌ ๊ณต๊ฐ„์„ ํ• ๋‹นํ•˜์ง€ ์•Š์•„๋„ ๋จ

๋‹จ์ 

  • ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ๋ณ„๋„ ๊ณต๊ฐ„์ด ํ•„์š”ํ•˜๋ฏ€๋กœ, ์ €์žฅ๊ณต๊ฐ„ ํšจ์œจ์ด ์ข‹์ง€ ์•Š์Œ
  • ์—ฐ๊ฒฐ ์ •๋ณด๋ฅผ ์ฐพ๋Š” ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๋ฏ€๋กœ ์ ‘๊ทผ ์†๋„๊ฐ€ ๋А๋ฆผ
  • ์ค‘๊ฐ„ ๋ฐ์ดํ„ฐ ์‚ญ์ œ ์‹œ, ์•ž ๋’ค ๋…ธ๋“œ์˜ ์—ฐ๊ฒฐ์„ ์žฌ๊ตฌ์„ฑํ•ด์•ผ ํ•˜๋Š” ๋ถ€๊ฐ€์ ์ธ ์ž‘์—…์ด ํ•„์š”

 

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๋ฉฐ ์žฅ,๋‹จ์ ์„ ์‚ดํŽด๋ณด๊ณ  ์‹œ๊ฐ„ ๋ณต์žก๋„์— ๋Œ€ํ•ด์„œ๋„ ์•Œ์•„๋ณด์ž


๊ตฌํ˜„

IList ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๊ตฌํ˜„์— ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ •์˜ํ–ˆ๋‹ค.

 

IList ์ธํ„ฐํŽ˜์ด์Šค

public interface IList<E> {
	void add(E e);                 		   //๋ฐ์ดํ„ฐ ์ถ”๊ฐ€

	void insert(int index, E e);   		   //index ์œ„์น˜์— ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€

	void clear();				   		   //๋ฐ์ดํ„ฐ ๋ชจ๋‘ ์‚ญ์ œ

	boolean delete(E e);		   		   //ํ•ด๋‹น ๋ฐ์ดํ„ฐ ์‚ญ์ œ

	boolean deleteByIndex(int index);      //index ์œ„์น˜์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ ์‚ญ์ œ

	E get(int index);					   //index ์œ„์น˜์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ ๋ฐ˜ํ™˜

	int indexOf(E e);					   //ํ•ด๋‹น ๋ฐ์ดํ„ฐ index ๋ฐ˜ํ™˜

	boolean isEmpty();					   //๋ฆฌ์ŠคํŠธ์— ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ๋Š”์ง€ ์—†๋Š”์ง€ ๋ฐ˜ํ™˜

	int size();
}

 

ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ implementsํ•˜์—ฌ MyLinkedList ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ํ•ด๋‹น ํด๋ž˜์Šค์— ๊ตฌํ˜„ํ•ด๋ณด์ž.

 

MyLinkedList ํด๋ž˜์Šค

public class MyLinkedList<E> implements IList<E> {
	private int size;
	private Node head;

	public MyLinkedList() {
		this.size = 0;
		this.head = new Node(null);
	}
    
	private class Node {
		E data;
		Node next;

		Node(E data) {
			this.data = data;
		}

		Node(E data, Node next) {
			this.data = data;
			this.next = next;
		}
	}
}

ํ•ด๋‹น ์†Œ์Šค๋ฅผ ๋ณด๋ฉด ๋‚ด์žฅ ํด๋ž˜์Šค๋กœ Node๊ฐ€ ์žˆ๋Š”๋ฐ ์ด๊ฒƒ์ด ์œ„์—์„œ ์„ค๋ช…ํ•œ ๋…ธ๋“œ ์—ญํ• ์„ ํ•ด์ค„ ํด๋ž˜์Šค๋‹ค.

์œ„์—์„œ ์„ค๋ช…ํ–ˆ๋“ฏ์ด ๋…ธ๋“œ๋Š” ๋ฐ์ดํ„ฐ์™€ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ–ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ œ๋„ค๋ฆญ ํƒ€์ž…์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด๋Š” data ๋ณ€์ˆ˜, ๋‹ค์Œ ๋…ธ๋“œ์™€ ์—ฐ๊ฒฐํ•  Node ํƒ€์ž…์˜ next ๋ณ€์ˆ˜๋กœ ๊ตฌ์„ฑํ–ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  MyLinkedList ํด๋ž˜์Šค์— 2๊ฐœ์˜ ํ•„๋“œ๊ฐ€ ์žˆ๋Š”๋ฐ ํ•˜๋‚˜๋Š” ํ•ด๋‹น ๊ฐ์ฒด์— ๋‹ด๊ธด ๋ฐ์ดํ„ฐ์˜ ๊ฐฏ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•  size, ์‹œ์ž‘ ๋…ธ๋“œ๋ฅผ ๋‹ด์„ head๊ฐ€ ์žˆ๋‹ค.

 

๊ทธ ๋‹ค์Œ, ์ด์ œ ์ธํ„ฐํŽ˜์ด์Šค์—์„œ ์ •์˜ํ•œ ์ถ”์ƒ ๋ฉ”์„œ๋“œ๋“ค์„ ๊ตฌํ˜„ํ•ด๋ณด์ž.

 

 

add(E e) ๋ฉ”์„œ๋“œ

 

์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์— ์ฒ˜์Œ ๊ฐ’์„ ์ถ”๊ฐ€ํ•  ๋•Œ, ๋…ธ๋“œ๋ฅผ ์ƒ์„ฑํ•ด์„œ head์˜ ํฌ์ธํ„ฐ์— ์ƒ์„ฑํ•œ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•ด์ค˜์•ผ ํ•œ๋‹ค.

๊ทธ ๋‹ค์Œ ๊ฐ’์„ ์ถ”๊ฐ€ ํ•œ๋‹ค๋ฉด ์ „์— ์ถ”๊ฐ€ํ•œ ๋…ธ๋“œ์™€ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ ๋…ธ๋“œ๋ฅผ ์—ฐ๊ฒฐํ•ด์ค˜์•ผ ํ•œ๋‹ค.

 

๊ทธ๋ž˜์„œ add ๋ฉ”์„œ๋“œ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ–ˆ๋‹ค.

@Override
public void add(E e) {
    Node curr = this.head;

    while (curr.next != null) {
        curr = curr.next;
    }

    Node node = new Node(e);
    curr.next = node;
    size++;
}

curr์— head๋ฅผ ์ฒ˜์Œ์— ๋Œ€์ž…ํ•ด์ฃผ๊ณ , while์„ ํ†ตํ•ด ๋‹ค์Œ ๋…ธ๋“œ๊ฐ€ null์ผ ๋•Œ๊นŒ์ง€ ๊ณ„์† ๋…ธ๋“œ๋“ค์„ ์ˆœํšŒํ•ด์ค€๋‹ค. ๊ทธ๋ž˜์„œ curr์—๋Š” ๋งจ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๊ฐ€ ๋Œ€์ž…๋  ๊ฒƒ์ด๋‹ค.

๊ทธ๋‹ค์Œ ์ถ”๊ฐ€ํ•  ๋…ธ๋“œ์ธ node ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งจ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ์˜ ํฌ์ธํ„ฐ ์—ญํ• ์ธ next์— node๋ฅผ ๋„ฃ์–ด์คŒ์œผ๋กœ์จ ์œ„์˜ ๊ทธ๋ฆผ๊ณผ ๊ฐ™์ด ๋…ธ๋“œ ๊ฐ„์˜ ์—ฐ๊ฒฐ์ด ์ด๋ฃจ์–ด์ง„๋‹ค.

(size++์€ ๋…ธ๋“œ ์ถ”๊ฐ€๋์Œ์œผ๋กœ ์ฆ๊ฐ€)

 

 

insert(int index, E e) ๋ฉ”์„œ๋“œ

์ค‘๊ฐ„์— ๋…ธ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด, ์•ž ๋’ค ๋…ธ๋“œ๋ฅผ ์žฌ์—ฐ๊ฒฐ ํ•ด์ค˜์•ผ ํ•œ๋‹ค. ์œ„์˜ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, ๊ธฐ์กด์— Prev์™€ Curr๊ฐ€ ์„œ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋‹ค๊ฐ€ ์‚ฌ์ด์— insert๋ฅผ ํ•œ๋‹ค๋ฉด Prev์˜ ๋‹ค์Œ ๋…ธ๋“œ๋Š” ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๋…ธ๋“œ๊ฐ€, ๊ทธ๋ฆฌ๊ณ  ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ๋…ธ๋“œ์˜ ๋‹ค์Œ ๋…ธ๋“œ๊ฐ€ Curr๋กœ ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

 

๊ทธ๋ž˜์„œ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌํ˜„ํ–ˆ๋‹ค.

@Override
public void insert(int index, E e) {
    if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException();

    Node prev = this.head;
    Node curr = prev.next;

    int i = 0;
    while (i++ < index) {
        prev = prev.next;
        curr = curr.next;
    }

    Node node = new Node(e, curr);
    prev.next = node;
    size++;
}

 

 

clear() ๋ฉ”์„œ๋“œ

@Override
public void clear() {
    this.size = 0;
    this.head.next = null;
}

clear ๋ฉ”์„œ๋“œ๋Š” ๋…ธ๋“œ์˜ ์—ฐ๊ฒฐ์„ ๋Š์–ด์ฃผ๋ฉด ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ๋งจ ์ฒ˜์Œ ๋…ธ๋“œ์ธ head์˜ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ null๋กœ ๋ฐ”๊ฟ” ์—ฐ๊ฒฐ์„ ๋Š์–ด์คฌ๋‹ค.

 

 

delete(E e) ๋ฉ”์„œ๋“œ

delete๋Š” ์ค‘๊ฐ„ ๋…ธ๋“œ๊ฐ€ ์‚ญ์ œ ๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ insert ๋ฉ”์„œ๋“œ์™€ ๊ฐ™์ด prev, curr ๋…ธ๋“œ ๋‘๊ฐœ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

๊ทธ๋ž˜์„œ curr ๋…ธ๋“œ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๋งค๊ฐœ๋ณ€์ˆ˜์™€ ๊ฐ™์œผ๋ฉด prev์˜ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ curr์˜ ๋‹ค์Œ ๋…ธ๋“œ๋กœ ์—ฐ๊ฒฐํ•˜๊ณ , curr์˜ ๋‹ค์Œ ๋…ธ๋“œ๋ฅผ null๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ๋Š์–ด์ค€๋‹ค.

@Override
public boolean delete(E e) {
    Node prev = this.head;
    Node curr = prev.next;

    while (curr != null) {
        if (curr.data.equals(e)) {
            prev.next = curr.next;
            curr.next = null;
            size--;

            return true;
        }

        prev = prev.next;
        curr = curr.next;
    }

    return false;
}

 

 

deleteByIndex(int index) ๋ฉ”์„œ๋“œ

@Override
public boolean deleteByIndex(int index) {
    if (index < 0 || index >= size)
        throw new IndexOutOfBoundsException();

    Node prev = this.head;
    Node curr = prev.next;

    int i = 0;
    while (i++ < index) {
        prev = prev.next;
        curr = curr.next;
    }

    prev.next = curr.next;
    curr.next = null;
    size--;

    return true;
}

delete ๋ฉ”์„œ๋“œ์™€ ๊ฐœ๋…์€ ๊ฐ™์œผ๋ฏ€๋กœ ์ฝ”๋“œ๋งŒ ์ฒจ๋ถ€ํ•ด๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค.

 

 

๊ธฐํƒ€ ๋ฉ”์„œ๋“œ

๋‚˜๋จธ์ง€ get์ด๋‚˜ indexOf ๋“ฑ ๊ธฐํƒ€ ๋ฉ”์„œ๋“œ๋“ค์€ ๋…ธ๋“œ ๊ฐ„์˜ ์—ฐ๊ฒฐ์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ๊ฒŒ ํ•„์š”์—†์–ด์„œ ์ถ”๊ฐ€, ์‚ญ์ œ๋ฅผ ์ดํ•ดํ–ˆ๋‹ค๋ฉด ์ฝ”๋“œ๋งŒ ๋ด๋„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

@Override
	public E get(int index) {
		Node curr = this.head;

		int i = 0;
		while (i++ < index) {
			curr = curr.next;
		}

		return curr.data;
	}

	@Override
	public int indexOf(E e) {
		Node curr = this.head;

		int i = 0;
		while (curr != null) {
			if (curr.data.equals(e)) {
				return i;
			}

			curr = curr.next;
			i++;
		}

		return -1;
	}

	@Override
	public boolean isEmpty() {
		return this.size == 0;
	}

	@Override
	public int size() {
		return size;
	}

๊ตฌํ˜„์„ ํ•ด๋ณธ ๊ฒฐ๊ณผ, ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ๋Š” ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€, ์‚ญ์ œ ์‹œ ๋Œ€์ƒ ๋…ธ๋“œ๊ฐ€ ๋งจ ์•ž์ด๋ผ๋ฉด O(1)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ทธ๊ฒŒ ์•„๋‹ˆ๋ผ๋ฉด O(n)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ–๊ฒŒ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ฒ€์ƒ‰ ์—ญ์‹œ ์ˆœํšŒ๋ฅผ ํ•ด์•ผํ•˜๋ฏ€๋กœ O(n)์˜ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค.


์‹œ๊ฐ„๋ณต์žก๋„

  • ์ถ”๊ฐ€, ์‚ญ์ œ : O(1), O(n)
  • ๊ฒ€์ƒ‰ : O(n)
๋ฐ˜์‘ํ˜•