LinkedList를 구현하세요.
- ListNode 구현
public class ListNode { public int data; public ListNode next; public ListNode() {} public ListNode(int data) { this.data = data; this.next = null; } public ListNode add(ListNode head, ListNode nodeToAdd, int position) { ListNode node = head; for(int i = 0; i < position - 1; i++) { node = node.next; } nodeToAdd.next = node.next; node.next = nodeToAdd; return node; } public ListNode remove(ListNode head, int position) { ListNode node = head; // head를 삭제하는 경우 if(position == 0) { ListNode deleteNode = node; head = node.next; deleteNode.next = null; return deleteNode; } for(int i = 0; i < position - 1; i++) { node = node.next; } ListNode deleteNode = node.next; node.next = deleteNode.next; return deleteNode; } public boolean contains(ListNode head, ListNode nodeToCheck) { ListNode node = head; while(node != null) { if(node.data == nodeToCheck.data) return true; node = node.next; } return false; } }
-
ListNode 테스트
public class ListNodeTest { private ListNode listNode; @BeforeEach public void beforeEach() { listNode = new ListNode(1); ListNode head = listNode; for(int i = 2; i < 5; i++) { ListNode nextNode = new ListNode(i); listNode.next = nextNode; listNode = listNode.next; } listNode = head; } @AfterEach public void afterEach() { while(listNode != null) { ListNode next = listNode.next; listNode = null; listNode = next; } } @Test public void showAll() { int i = 1; while(listNode != null) { assertEquals(i, listNode.data); i += 1; listNode = listNode.next; } assertEquals(i, 5); } @Test public void addTest() { ListNode newNode = new ListNode(5); listNode.add(listNode, newNode, 4); int i = 1; while(listNode != null) { assertEquals(i, listNode.data); i += 1; listNode = listNode.next; } assertEquals(i, 6); } @Test public void removeTest() { for(int i = 3; i >= 0; i--) { ListNode node = listNode.remove(listNode, i); assertEquals(node.data, i + 1); } } @Test public void containsTest() { for(int i = 1; i < 5; i++) { ListNode nodeToCheck = new ListNode(i); assertTrue(listNode.contains(listNode, nodeToCheck)); } } }
Stack을 구현하세요.
-
배열로 구현한 ArrayStack
public class ArrayStack { int maxSize; int index; int[] array; public ArrayStack() { this.maxSize = 10; this.index = 0; array = new int[maxSize]; } public ArrayStack(int maxSize) { this.maxSize = maxSize; this.index = 0; array = new int[maxSize]; } public void push(int data) { // 무제한으로 늘리자 if(index >= maxSize) { maxSize += 5; int[] newArray = new int[maxSize]; for(int i = 0; i < index; i++) { newArray[i] = this.array[i]; } this.array = newArray; } array[index++] = data; } public int pop() { if(index == -1) return -1; int returnValue = this.array[--index]; return returnValue; } }
-
ArrayStack 테스트
public class ArrayStackTest { @Test public void pushTest() { ArrayStack stack = new ArrayStack(5); for(int i = 1; i < 12; i++) { stack.push(i); } assertEquals(stack.index, 11); assertEquals(stack.maxSize, 15); } @Test public void popTest() { ArrayStack stack = new ArrayStack(10); for(int i = 1; i < 12; i++) { stack.push(i); } for(int i = 11; i > 0; i--) { assertEquals(stack.pop(), i); } } }
-
ListNode로 구현한 ListStack
public class ListStack { private ListNode head; private int size; public ListStack() { head = new ListNode(); size = 0; } public void push(int nextValue) { if(size == 0) { head = new ListNode(nextValue); size += 1; return; } ListNode nextToAdd = new ListNode(nextValue); head.add(head, nextToAdd, this.size++); } public int pop() { if(this.size() == 0) { return -1; } ListNode returnValue = head.remove(this.head, --this.size); return returnValue.data; } public int size() { return this.size; } }
-
ListStack 테스트
public class ListStackTest { @Test public void pushTest() { ListStack stack = new ListStack(); for(int i = 1; i < 12; i++) { stack.push(i); } assertEquals(stack.size(), 11); } @Test public void popTest() { ListStack stack = new ListStack(); for(int i = 1; i < 12; i++) { stack.push(i); } for(int i = 11; i > 0; i--) { assertEquals(stack.pop(), i); } assertEquals(stack.pop(), -1); } }
Queue를 구현하세요.
-
배열로 구현한 ArrayQueue
public class ArrayQueue { private int[] array; private int first; private int last; private int maxSize; public ArrayQueue() { maxSize = 10; array = new int[maxSize]; first = 0; last = 0; } public void add(int num) { // 강제로 크기 변환 if(this.last >= this.maxSize) { maxSize += 5; int[] newArray = new int[maxSize]; int j = 0; for(int i = first; i < last; i++) { newArray[j++] = array[i]; } first = 0; last = j; this.array = newArray; } array[last++] = num; } public int get() { if(first >= last) return -1; int returnValue = array[first]; array[first++] = 0; return returnValue; } public boolean contain(int data) { for(int i = first; i < last; i++) { if(array[i] == data) return true; } return false; } public int size() { return last - first; } }
-
ArrayQueue 테스트
public class ArrayQueueTest { @Test public void addTest() { ArrayQueue queue = new ArrayQueue(); for(int i = 0; i < 12; i++) { queue.add(i + 1); } assertEquals(queue.size(), 12); } @Test public void getTest() { ArrayQueue queue = new ArrayQueue(); for(int i = 0; i < 6; i++) { queue.add(i + 1); } assertEquals(queue.size(), 6); for(int i = 0; i < 6; i++) { assertEquals(queue.get(), (i+1)); } assertEquals(queue.size(), 0); for(int i = 0; i < 6; i++) { queue.add(i + 1); } assertEquals(queue.size(), 6); for(int i = 0; i < 6; i++) { assertEquals(queue.get(), (i+1)); } assertEquals(queue.size(), 0); } @Test public void containTest() { ArrayQueue queue = new ArrayQueue(); for(int i = 0; i < 6; i++) { queue.add(i + 1); } assertEquals(queue.size(), 6); for(int i = 0; i< 6; i++) { assertTrue(queue.contain((i+1))); } } }
-
ListNode로 구현한 ListQueue
public class ListQueue { private ListNode head; private int index; public ListQueue() { head = new ListNode(); index = 0; } public void add(int data) { ListNode now = new ListNode(data); head.add(head, now, ++index); } public int get() { if(index == 0) { return -1; } ListNode deleteNode = head.remove(head, 1); index -= 1; return deleteNode.data; } public boolean contain(int data) { ListNode node = head; while(node != null) { if(node.data == data) return true; node = node.next; } return false; } public int size() { return index; } }
-
ListQueue 테스트
public class ListQueueTest { @Test public void addTest() { ListQueue queue = new ListQueue(); for(int i = 0; i < 12; i++) { queue.add(i + 1); } assertEquals(queue.size(), 12); } @Test public void getTest() { ListQueue queue = new ListQueue(); for(int i = 0; i < 6; i++) { queue.add(i + 1); } assertEquals(queue.size(), 6); for(int i = 0; i < 6; i++) { assertEquals(queue.get(), (i+1)); } assertEquals(queue.size(), 0); } @Test public void containTest() { ListQueue queue = new ListQueue(); for(int i = 0; i < 6; i++) { queue.add(i + 1); } assertEquals(queue.size(), 6); for(int i = 0; i< 6; i++) { assertTrue(queue.contain((i+1))); } } }
Binary Search Tree를 구현하시오.
- Binary Tree
- 자식 노드가 최대 2개인 노드로 구성된 트리
- Binary Search Tree
- Binary Tree에 left child < root < right child 로 구성되어야 한다.
- tree 순회
- inorder : left -> root -> right 순으로 순회
- preorder : root -> left -> right 순으로 순회
- postorder : left -> right -> root 순으로 순회
- root위치에 따라 in/pre/post가 나뉜다.
- dfs와 bfs
- dfs: 깊이 우선 탐색으로 stack을 이용한다.
- bfs: 너비 우선 탐색으로 queue를 이용한다.
- Binary Search Tree 구현
public class BinarySearchTree { private int index; private Node root; public BinarySearchTree() { root = null; index = 0; } public BinarySearchTree(int data) { root = new Node(data); index = 0; } public void insert(int data) { if(this.root == null) { this.root = new Node(data); return; } Node node = root; Node prev = new Node(); while(node != null) { prev = node; if(node.getValue() > data) { node = node.getLeft(); } else { node = node.getRight(); } } if(node == prev.getLeft()) { prev.setLeft(new Node(data)); } else { prev.setRight(new Node(data)); } } public void remove(int data) { Node node = root; Node prev = new Node(); while(node != null) { if(node.getValue() == data) { break; } else if(node.getValue() < data) { prev = node; node = node.getRight(); } else { prev = node; node = node.getLeft(); } } if(node.getLeft() == null && node.getRight() == null) { // 1. 지우고자 하는 노드에 자식이 없는 경우 -> 그냥 삭제 if(node == root) { root = null; } else if(node == prev.getLeft()) { prev.setLeft(null); } else { prev.setRight(null); } } else if(node.getLeft() == null) { // 2. 지우고자 하는 노드에 자식이 오른쪽에만 있는 경우 -> 해당 자식과 교체 if(node == root) { root = node.getRight(); } else if(node == prev.getLeft()) { prev.setLeft(node.getRight()); } else { prev.setRight(node.getRight()); } } else if(node.getRight() == null) { // 2. 지우고자 하는 노드에 자식이 왼쪽에만 있는 경우 -> 해당 자식과 교체 if(node == root) { root = node.getLeft(); } else if(node == prev.getLeft()) { prev.setLeft(node.getLeft()); } else { prev.setRight(node.getLeft()); } } else { // 3. 지우고자 하는 노드에 자식이 2개인 경우 -> 오른쪽 자식에 가장 왼쪽 자식을 대체하자 // 오른쪽 자식에 가장 왼쪽 자식 찾기 Node next = node.getRight(); Node nextPrev = node; while(next.getLeft() != null) { nextPrev = next; next = next.getLeft(); } // 대체할 노드가 삭제할 노드의 바로 오른쪽 노드가 아닌 경우, // 대체할 노드의 오른쪽 노드를 대체할 노드의 부모 왼쪽 노드로 대체하고, 대체할 노드의 오른쪽 자식을 삭제할 노드의 오른쪽 자식으로 세팅 if(next != node.getRight()) { nextPrev.setLeft(next.getRight()); next.setRight(node.getRight()); } // 삭제할 대상과 대체 if(node == root) { root = next; } else if(node == prev.getLeft()) { prev.setLeft(next); } else { prev.setRight(next); } // 삭제할 노드의 왼쪽, 오른쪽 자식은 그대로 이어준다. next.setLeft(node.getLeft()); } } public void dfs(Node root) { // inorder와 동일하기 때문에 구현하지 않음 } public int[] bfs(int size) { int[] traversal = new int[size]; this.index = 0; List<Node> queue = new ArrayList<>(); queue.add(root); while(!queue.isEmpty()) { Node next = queue.get(0); queue.remove(0); traversal[index++] = next.getValue(); if(next.getLeft() != null) { queue.add(next.getLeft()); } if(next.getRight() != null) { queue.add(next.getRight()); } } return traversal; } public void inOrder(Node node, int[] traversal) { // left -> root -> right; if(node == null) { return; } inOrder(node.getLeft(), traversal); traversal[index++] = node.getValue(); inOrder(node.getRight(), traversal); } public void preOrder(Node node, int[] traversal) { // root -> left -> right; if(node == null) return; traversal[index++] = node.getValue(); preOrder(node.getLeft(), traversal); preOrder(node.getRight(), traversal); } public void postOrder(Node node, int[] traversal) { // left -> right -> root if(node == null) return; postOrder(node.getLeft(), traversal); postOrder(node.getRight(), traversal); traversal[index++] = node.getValue(); } public int[] getInOrder(int size) { this.index = 0; int[] traversal = new int[size]; inOrder(root, traversal); return traversal; } public int[] getPreOrder(int size) { this.index = 0; int[] traversal = new int[size]; preOrder(root, traversal); return traversal; } public int[] getPostOrder(int size) { this.index = 0; int[] traversal = new int[size]; postOrder(root, traversal); return traversal; } }
- BinarySearchTree 테스트
public class BinaryTreeTest { private BinarySearchTree binarySearchTree; private int[] inorder = {1, 2, 3, 4, 5, 6, 7}; private int[] preorder = {4, 2, 1, 3, 6, 5, 7}; private int[] postorder = {1, 3, 2, 5, 7, 6, 4}; private int[] bfs = {4, 2, 6, 1, 3, 5, 7}; private int[] bfsAfterRemove = {5, 3, 6, 7}; @BeforeEach public void beforeEach() { this.binarySearchTree = new BinarySearchTree(); this.binarySearchTree.insert(4); this.binarySearchTree.insert(2); this.binarySearchTree.insert(1); this.binarySearchTree.insert(3); this.binarySearchTree.insert(6); this.binarySearchTree.insert(5); this.binarySearchTree.insert(7); } @Test public void removeTest() { // leaf node 삭제 binarySearchTree.remove(1); // 자식이 1개인 node 삭제 binarySearchTree.remove(2); // 자식이 2개인 node 삭제 binarySearchTree.remove(4); int[] traversal = binarySearchTree.bfs(4); for(int i = 0; i < traversal.length; i++) { assertEquals(bfsAfterRemove[i], traversal[i]); } } @Test public void inOrderTest() { int[] traversal = this.binarySearchTree.getInOrder(inorder.length); for(int i = 0; i < traversal.length; i++) { assertEquals(inorder[i], traversal[i]); } } @Test public void preOrderTest() { int[] traversal = this.binarySearchTree.getPreOrder(preorder.length); for(int i = 0; i < traversal.length; i++) { assertEquals(preorder[i], traversal[i]); } } @Test public void postOrderTest() { int[] traversal = this.binarySearchTree.getPostOrder(postorder.length); for(int i = 0; i < traversal.length; i++) { assertEquals(postorder[i], traversal[i]); } } @Test public void dfsTest() { //inorder와 동일하기 때문에 구현하지 않음 } @Test public void bfsTest() { int[] traversal = this.binarySearchTree.bfs(bfs.length); for(int i = 0; i < traversal.length; i++) { assertEquals(bfs[i], traversal[i]); } } }