diff --git a/contents/data-structure/README.md b/contents/data-structure/README.md index 881c033..22849cb 100644 --- a/contents/data-structure/README.md +++ b/contents/data-structure/README.md @@ -54,10 +54,14 @@ String[] name = {"Stacy", "Tracy", "Dorothy"}; ### Linked List 구현 +- [Singly Linked List](./code/LinkedList/SinglyLinkedList.java) +- [Doubly Linked List](./code/LinkedList/DoublyLinkedList.java) +- 위 코드 실행 : [LinkedListExample.java](./code/LinkedList/LinkedListExample.java) + ### Linked List 시간 복잡도 - 데이터 조회 : O(n) -- **맨 앞/뒤에** 데이터 삽입/삭제하기 : O(1) +- **맨 앞/뒤에** 데이터 삽입/삭제하기 : O(1) (SinglyLinkedList의 경우 맨 뒤의 데이터 삭제 연산은 O(n)) - **중간의 원하는 위치에** 데이터 삽입/삭제하기 : O(n) _(원하는 원소까지 데이터를 조회하는 과정이 있으므로 O(n) + O(1))_ --- @@ -314,6 +318,25 @@ class Trie { ## 질의응답 +
+Array와 Linked List를 그 차이점을 이용해 설명해봅시다. + +- 데이터 접근 속도 + - Array는 인덱스를 통한 Random Access를 지원하므로 시간 복잡도 O(1)로 빠르게 찾을 수 있다. + - LinkedList는 순차 접근 방식을 사용하므로 시간 복잡도 O(N)이 걸린다. +- 데이터의 삽입/삭제 속도 + - Array는 데이터를 중간이나 맨 앞에 삽입/삭제하는 경우 shift가 필요하므로 데이터가 많을수록 비효율적이다. + - LinkedList는 중간 삽입/삭제는 똑같이 O(N)의 시간 복잡도를 갖지만, 맨 앞 또는 뒤에 삽입할 경우 O(1)의 시간복잡도를 갖는다. + - 다만 LinkedList는 데이터 삽입/삭제마다 메모리 할당/해제가 일어나므로 시간복잡도는 빠를지라도 시스템 콜(System Call)에 있어서 Array보다 더 시간이 걸린다. +- 메모리 할당 + - Array는 정적 메모리 할당이 이루어진다. (Compile time) + - LinkedList는 동적 메모리 할당이 이루어진다. (Runtime) + - Array의 경우 데이터 삽입 시 모든 공간이 다 차버렸다면 새로운 메모리 공간이 필요하지만 LinkedList는 동적으로 할당받을 수 있다. + +데이터 삽입/삭제가 빈번하다면 LinkedList를 사용하는 것이 좋고, 데이터 접근 속도가 중요하다면 Array를 사용하는 것이 좋다. + +
+
스택으로 큐를 구현할 수 있을까요? 네, 2개의 스택을 이용하여 구현할 수 있습니다. Enqueue 연산은 첫번째 스택에 원소를 추가하면 됩니다. Dequeue 연산은 두번째 스택을 이용합니다. 우선 두번째 스택이 비어있다면 첫번째 스택이 빌 때까지 첫번째 스택의 원소를 pop하고 두번째 스택에 push하는 것을 반복합니다. 그리고 두번째 스택이 비어있지 않다면 두번째 스택의 원소를 pop하면 됩니다. diff --git a/contents/data-structure/code/LinkedList/DoublyLinkedList.java b/contents/data-structure/code/LinkedList/DoublyLinkedList.java new file mode 100644 index 0000000..3cecb64 --- /dev/null +++ b/contents/data-structure/code/LinkedList/DoublyLinkedList.java @@ -0,0 +1,128 @@ +package LinkedList; + +public class DoublyLinkedList implements ILinkedList { + private Node header; + private Node trailer; + private int size; + + public DoublyLinkedList() { + header = new Node<>(null, null, null); + trailer = new Node<>(null, header, null); + header.setNext(trailer); + size = 0; + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + @Override + public E first() { + if (isEmpty()) return null; + return header.getNext().getElement(); + } + + @Override + public E last() { + if (isEmpty()) return null; + return trailer.getPrev().getElement(); + } + + @Override + public void addFirst(E e) { + addBetween(e, header, header.getNext()); + } + + @Override + public void addLast(E e) { + addBetween(e, trailer.getPrev(), trailer); + } + + @Override + public E removeFirst() { + if (isEmpty()) return null; + return remove(header.getNext()); + } + + @Override + public E removeLast() { + if (isEmpty()) return null; + return remove(trailer.getPrev()); + } + + @Override + public String toString() { + if (isEmpty()) return "[]"; + + StringBuilder sb = new StringBuilder("["); + DoublyLinkedList.Node current = header.getNext(); + while (current.getNext() != trailer) { + sb.append(current.getElement()).append(", "); + current = current.getNext(); + } + sb.append(current.getElement()).append("]"); + return sb.toString(); + } + + private void addBetween(E e, Node predecessor, Node successor) { + Node newest = new Node<>(e, predecessor, successor); + predecessor.setNext(newest); + successor.setPrev(newest); + size ++; + } + + private E remove(Node node) { + Node predecessor = node.getPrev(); + Node successor = node.getNext(); + predecessor.setNext(successor); + successor.setPrev(predecessor); + size --; + return node.getElement(); + } + + private static class Node { + private E element; + private Node prev; + private Node next; + + public Node() { + this(null, null, null); + } + + public Node(E element, Node prev, Node next) { + this.element = element; + this.prev = prev; + this.next = next; + } + + public E getElement() { + return element; + } + + public void setElement(E element) { + this.element = element; + } + + public Node getPrev() { + return prev; + } + + public void setPrev(Node prev) { + this.prev = prev; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } + } +} \ No newline at end of file diff --git a/contents/data-structure/code/LinkedList/ILinkedList.java b/contents/data-structure/code/LinkedList/ILinkedList.java new file mode 100644 index 0000000..ba44940 --- /dev/null +++ b/contents/data-structure/code/LinkedList/ILinkedList.java @@ -0,0 +1,16 @@ +package LinkedList; + +public interface ILinkedList { + + public int size(); + public boolean isEmpty(); + + public E first(); + public E last(); + + public void addFirst(E e); + public void addLast(E e); + + public E removeFirst(); + public E removeLast(); +} diff --git a/contents/data-structure/code/LinkedList/LinkedListExample.java b/contents/data-structure/code/LinkedList/LinkedListExample.java new file mode 100644 index 0000000..8d5d20f --- /dev/null +++ b/contents/data-structure/code/LinkedList/LinkedListExample.java @@ -0,0 +1,46 @@ +package LinkedList; + +public class LinkedListExample { + public static void main(String[] args) { + System.out.println("==================Singly Linked List=================="); + ILinkedList sll = new SinglyLinkedList<>(); + sll.addFirst(3); + sll.addLast(10); + sll.addFirst(2); + sll.addLast(12); + System.out.println(sll); + System.out.println("size : " + sll.size()); + System.out.println("first : " + sll.first()); + System.out.println("last : " + sll.last()); + System.out.println("removeFirst : " + sll.removeFirst()); + System.out.println(sll); + System.out.println("removeLast : " + sll.removeLast()); + System.out.println(sll); + System.out.println("removeFirst : " + sll.removeFirst()); + System.out.println(sll); + System.out.println("removeLast : " + sll.removeLast()); + System.out.println(sll); + System.out.println("size : " + sll.size()); + + System.out.println("==================Doubly Linked List=================="); + ILinkedList dll = new DoublyLinkedList<>(); + dll.addFirst(3); + dll.addLast(10); + dll.addFirst(2); + dll.addLast(12); + System.out.println(dll); + System.out.println("size : " + dll.size()); + System.out.println("first : " + dll.first()); + System.out.println("last : " + dll.last()); + System.out.println("removeFirst : " + dll.removeFirst()); + System.out.println(dll); + System.out.println("removeLast : " + dll.removeLast()); + System.out.println(dll); + System.out.println("removeFirst : " + dll.removeFirst()); + System.out.println(dll); + System.out.println("removeLast : " + dll.removeLast()); + System.out.println(dll); + System.out.println("size : " + dll.size()); + } +} + diff --git a/contents/data-structure/code/LinkedList/SinglyLinkedList.java b/contents/data-structure/code/LinkedList/SinglyLinkedList.java new file mode 100644 index 0000000..83231f7 --- /dev/null +++ b/contents/data-structure/code/LinkedList/SinglyLinkedList.java @@ -0,0 +1,125 @@ +package LinkedList; + +public class SinglyLinkedList implements ILinkedList { + private Node head; + private Node tail; + private int size; + + public SinglyLinkedList() { + head = tail = null; + size = 0; + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return size == 0; + } + + @Override + public E first() { + if (isEmpty()) return null; + return head.getElement(); + } + + @Override + public E last() { + if (isEmpty()) return null; + return tail.getElement(); + } + + @Override + public void addFirst(E e) { + head = new Node<>(e, head); + if (isEmpty()) tail = head; + size ++; + } + + @Override + public void addLast(E e) { + Node newest = new Node<>(e, null); + if (isEmpty()) head = newest; + else tail.setNext(newest); + tail = newest; + size ++; + } + + @Override + public E removeFirst() { + if (isEmpty()) return null; + E target = head.getElement(); + head = head.getNext(); + size --; + if (isEmpty()) tail = null; + return target; + } + + @Override + public E removeLast() { + if (isEmpty()) return null; + E target; + if (head == tail) { + target = head.getElement(); + head = tail = null; + } else { + Node current = head; + while (current.getNext() != tail) { + current = current.getNext(); + } + target = tail.getElement(); + tail = current; + tail.setNext(null); + } + size --; + return target; + } + + @Override + public String toString() { + if (isEmpty()) return "[]"; + + StringBuilder sb = new StringBuilder("["); + Node current = head; + while (current.getNext() != null) { + sb.append(current.getElement()).append(", "); + current = current.getNext(); + } + sb.append(current.getElement()).append("]"); + return sb.toString(); + } + + private static class Node { + private E element; + private Node next; + + public Node() { + this(null, null); + } + + public Node(E element, Node next) { + this.element = element; + this.next = next; + } + + public E getElement() { + return element; + } + + public void setElement(E element) { + this.element = element; + } + + public Node getNext() { + return next; + } + + public void setNext(Node next) { + this.next = next; + } + } +} +