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;
+ }
+ }
+}
+