diff --git a/src/main/java/basic/algorithm/AbstractTreeAlogorithm.java b/src/main/java/basic/algorithm/AbstractTreeAlogorithm.java new file mode 100644 index 0000000..56757e5 --- /dev/null +++ b/src/main/java/basic/algorithm/AbstractTreeAlogorithm.java @@ -0,0 +1,45 @@ +package basic.algorithm; + +public class AbstractTreeAlogorithm { + + public static int[] field = {0,1,2,3,4,5,6,7,8,9,10}; + + public static void printAsBinaryTree() { + int n = field.length; + int height = (int) Math.ceil(Math.log(n + 1) / Math.log(2)); // 트리 높이 + int maxNodeWidth = getMaxWidth(field); // 가장 긴 숫자의 자리수 + int maxWidth = (int) Math.pow(2, height) * (maxNodeWidth + 2); // 총 가로 폭 (간격 포함) + + int index = 0; + + for (int level = 0; level < height; level++) { + int levelNodeCount = (int) Math.pow(2, level); + int spaceBetween = maxWidth / levelNodeCount; // 노드 사이 간격 + + // 시작 여백 + System.out.print(" ".repeat(spaceBetween / 2 - maxNodeWidth / 2)); + + for (int i = 0; i < levelNodeCount && index < n; i++) { + String formatted = String.format("%" + maxNodeWidth + "d", field[index++]); + System.out.print(formatted); + + // 간격 + if (i != levelNodeCount - 1) { + System.out.print(" ".repeat(spaceBetween - maxNodeWidth)); + } + } + + System.out.println(); + } + } + + // 숫자 중 가장 긴 자리수 계산 + private static int getMaxWidth(int[] arr) { + int maxLen = 0; + for (int num : arr) { + int len = String.valueOf(num).length(); + if (len > maxLen) maxLen = len; + } + return maxLen; + } +} diff --git a/src/main/java/basic/algorithm/BFS.java b/src/main/java/basic/algorithm/BFS.java index 2f02a7a..48c3c85 100644 --- a/src/main/java/basic/algorithm/BFS.java +++ b/src/main/java/basic/algorithm/BFS.java @@ -7,55 +7,15 @@ import java.util.Queue; import java.util.StringTokenizer; -public class BFS { - public static int[] field = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18}; - - public static void printAsBinaryTree() { - int n = field.length; - int height = (int) Math.ceil(Math.log(n + 1) / Math.log(2)); // 트리 높이 - int maxNodeWidth = getMaxWidth(field); // 가장 긴 숫자의 자리수 - int maxWidth = (int) Math.pow(2, height) * (maxNodeWidth + 2); // 총 가로 폭 (간격 포함) - - int index = 0; - - for (int level = 0; level < height; level++) { - int levelNodeCount = (int) Math.pow(2, level); - int spaceBetween = maxWidth / levelNodeCount; // 노드 사이 간격 - - // 시작 여백 - System.out.print(" ".repeat(spaceBetween / 2 - maxNodeWidth / 2)); - - for (int i = 0; i < levelNodeCount && index < n; i++) { - String formatted = String.format("%" + maxNodeWidth + "d", field[index++]); - System.out.print(formatted); - - // 간격 - if (i != levelNodeCount - 1) { - System.out.print(" ".repeat(spaceBetween - maxNodeWidth)); - } - } - - System.out.println(); - } - } - - // 숫자 중 가장 긴 자리수 계산 - private static int getMaxWidth(int[] arr) { - int maxLen = 0; - for (int num : arr) { - int len = String.valueOf(num).length(); - if (len > maxLen) maxLen = len; - } - return maxLen; - } +public class BFS extends AbstractTreeAlogorithm{ public static void main(String[] args){ printAsBinaryTree(); System.out.print("BFS : "); - bfs(0); + bfs(); } - private static void bfs(int index){ + private static void bfs(){ Queue queue = new LinkedList<>(); queue.add(0); diff --git a/src/main/java/basic/algorithm/DFS.java b/src/main/java/basic/algorithm/DFS.java index f55089c..7a5a38a 100644 --- a/src/main/java/basic/algorithm/DFS.java +++ b/src/main/java/basic/algorithm/DFS.java @@ -10,47 +10,7 @@ dfs 의 경우 0 1 3 4 5 6 */ -public class DFS { - public static int[] field = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18}; - - public static void printAsBinaryTree() { - int n = field.length; - int height = (int) Math.ceil(Math.log(n + 1) / Math.log(2)); // 트리 높이 - int maxNodeWidth = getMaxWidth(field); // 가장 긴 숫자의 자리수 - int maxWidth = (int) Math.pow(2, height) * (maxNodeWidth + 2); // 총 가로 폭 (간격 포함) - - int index = 0; - - for (int level = 0; level < height; level++) { - int levelNodeCount = (int) Math.pow(2, level); - int spaceBetween = maxWidth / levelNodeCount; // 노드 사이 간격 - - // 시작 여백 - System.out.print(" ".repeat(spaceBetween / 2 - maxNodeWidth / 2)); - - for (int i = 0; i < levelNodeCount && index < n; i++) { - String formatted = String.format("%" + maxNodeWidth + "d", field[index++]); - System.out.print(formatted); - - // 간격 - if (i != levelNodeCount - 1) { - System.out.print(" ".repeat(spaceBetween - maxNodeWidth)); - } - } - - System.out.println(); - } - } - - // 숫자 중 가장 긴 자리수 계산 - private static int getMaxWidth(int[] arr) { - int maxLen = 0; - for (int num : arr) { - int len = String.valueOf(num).length(); - if (len > maxLen) maxLen = len; - } - return maxLen; - } +public class DFS extends AbstractTreeAlogorithm{ public static void main(String[] args){ printAsBinaryTree(); diff --git a/src/main/java/basic/algorithm/Order.java b/src/main/java/basic/algorithm/Order.java new file mode 100644 index 0000000..552b694 --- /dev/null +++ b/src/main/java/basic/algorithm/Order.java @@ -0,0 +1,67 @@ +package basic.algorithm; + +public class Order extends AbstractTreeAlogorithm { + + public static void main(String[] args){ + printAsBinaryTree(); + + System.out.print("preOrder : "); + preOrder(0); + System.out.print("\ninOrder : "); + inOrder(0); + System.out.print("\npostOrder : "); + postOrder(0); + } + + private static void preOrder(int index){ + + int left = index *2+1; + int right = index*2+2; + + System.out.print(field[index]+" -> "); + + if(left < field.length){ + preOrder(left); + } + if(right < field.length){ + preOrder(right); + } + + } + + + private static void inOrder(int index){ + + int left = index *2+1; + int right = index*2+2; + + if(left < field.length){ + inOrder(left); + } + + System.out.print(field[index]+" -> "); + if(right < field.length){ + inOrder(right); + } + } + + + + private static void postOrder(int index){ + + int left = index *2+1; + int right = index*2+2; + + + if(left < field.length){ + postOrder(left); + } + + if(right < field.length){ + postOrder(right); + } + + System.out.print(field[index]+" -> "); + } + +} diff --git a/src/main/java/basic/datastructure/list/ArrayList.java b/src/main/java/basic/datastructure/list/ArrayList.java index 133a874..a3a6560 100644 --- a/src/main/java/basic/datastructure/list/ArrayList.java +++ b/src/main/java/basic/datastructure/list/ArrayList.java @@ -26,6 +26,10 @@ public ArrayList(List array){ this.size = array.getSize(); } + public int getCapacity(){ + return array.length; + } + @Override public T get(int index) { checkOutBoundsIndex(index); diff --git a/src/main/java/basic/datastructure/map/AbstractMap.java b/src/main/java/basic/datastructure/map/AbstractMap.java index e217088..a3715a8 100644 --- a/src/main/java/basic/datastructure/map/AbstractMap.java +++ b/src/main/java/basic/datastructure/map/AbstractMap.java @@ -2,7 +2,6 @@ public abstract class AbstractMap implements Map{ - protected void checkNullKey(K key){ if(key==null) throw new NullPointerException(); } diff --git a/src/main/java/basic/datastructure/map/HashMap.java b/src/main/java/basic/datastructure/map/HashMap.java new file mode 100644 index 0000000..7e5a1af --- /dev/null +++ b/src/main/java/basic/datastructure/map/HashMap.java @@ -0,0 +1,159 @@ +package basic.datastructure.map; + +import basic.datastructure.list.ArrayList; + +public class HashMap extends AbstractMap { + + int size = 0; + + private ArrayList hashMap; + + private final int DEFAULT_SIZE = 16; + + private final double LOAD_FACTOR = 0.75; + + public HashMap(){ + this.hashMap = new ArrayList<>(DEFAULT_SIZE); + + for(int i = 0 ; i < hashMap.getCapacity(); i++){ + hashMap.add(new Node(null,null)); + } + } + + @Override + public void put(K key, V value) { + checkNullKey(key); + int hash = hash(key); + + Node node = hashMap.get(hash); + + while(node.next!=null){ + node = node.getNext(); + if(node.getKey().equals(key)){ + node.setValue(value); + return; + } + } + + node.setNext(new Node(key,value)); + size++; + } + + @Override + public boolean containsKey(K key) { + checkNullKey(key); + int hash = hash(key); + + Node node = hashMap.get(hash).getNext(); + + while(node != null){ + if(node.getKey().equals(key)){ + return true; + } + node = node.getNext(); + } + + return false; + } + + @Override + public V get(K key) { + checkNullKey(key); + int hash = hash(key); + + Node node = hashMap.get(hash).getNext(); + + while(node!=null){ + if(node.getKey().equals(key)){ + return node.getValue(); + } + node = node.getNext(); + } + + return null; + } + + @Override + public V remove(K key) { + checkNullKey(key); + int hash = hash(key); + + Node pre = hashMap.get(hash); + Node node = pre.next; + while(node != null){ + if(node.key.equals(key)){ + pre.setNext(node.getNext()); + size--; + return node.value; + } + pre = node; + node = node.getNext(); + } + + return null; + } + + @Override + public void clear() { + hashMap = new ArrayList<>(DEFAULT_SIZE); + + for(int i = 0 ; i < hashMap.getCapacity();i++){ + hashMap.add(new Node(null,null)); + } + + size = 0; + } + + @Override + public int size() { + return this.size; + } + + @Override + public boolean isEmpty() { + return size==0; + } + + private int hash(K key){ + return Math.abs(key.hashCode()) % hashMap.getCapacity(); + } + + private class Node implements Map.Entry{ + + private K key; + + private V value; + + private Node next; + + Node(K key, V value){ + this.key = key; + + this.value = value; + + this.next = null; + } + + public Node getNext() { return this.next;} + + public void setNext(Node next) { this.next = next;} + + @Override + public K getKey() { + return this.key; + } + + @Override + public V getValue() { + return this.value; + } + + + + @Override + public V setValue(V value) { + this.value = value; + return this.value; + } + } +} diff --git a/src/test/java/datastructure/map/HashMapTest.java b/src/test/java/datastructure/map/HashMapTest.java new file mode 100644 index 0000000..0879e85 --- /dev/null +++ b/src/test/java/datastructure/map/HashMapTest.java @@ -0,0 +1,143 @@ +package datastructure.map; + +import basic.datastructure.map.HashMap; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +//통과 +//이후 Resize HashMap을 만들었을때를 대비해 수행 시간도 기록 +public class HashMapTest { + + private HashMap map; + + @BeforeEach + public void setUp() { + map = new HashMap<>(); + } + + @Test + public void testPutAndGet() { + map.put("apple", 1); + map.put("banana", 2); + map.put("carrot", 3); + + assertEquals(1, map.get("apple")); + assertEquals(2, map.get("banana")); + assertEquals(3, map.get("carrot")); + } + + @Test + public void testPutDuplicateKeyOverrides() { + map.put("apple", 1); + map.put("apple", 999); // override + + assertEquals(999, map.get("apple")); + assertEquals(1, map.size()); // size should stay 1 + } + + @Test + public void testContainsKey() { + map.put("apple", 1); + map.put("banana", 2); + + assertTrue(map.containsKey("apple")); + assertTrue(map.containsKey("banana")); + assertFalse(map.containsKey("carrot")); + } + + @Test + public void testRemove() { + map.put("apple", 1); + map.put("banana", 2); + + assertEquals(1, map.remove("apple")); + assertNull(map.get("apple")); + assertFalse(map.containsKey("apple")); + assertEquals(1, map.size()); + + assertNull(map.remove("not_exist")); + } + + @Test + public void testClear() { + map.put("apple", 1); + map.put("banana", 2); + map.put("carrot", 3); + + assertFalse(map.isEmpty()); + map.clear(); + assertTrue(map.isEmpty()); + assertEquals(0, map.size()); + assertNull(map.get("apple")); + } + + @Test + public void testSize() { + assertEquals(0, map.size()); + map.put("a", 1); + map.put("b", 2); + assertEquals(2, map.size()); + map.remove("a"); + assertEquals(1, map.size()); + map.clear(); + assertEquals(0, map.size()); + } + + @Test + public void testIsEmpty() { + assertTrue(map.isEmpty()); + map.put("x", 100); + assertFalse(map.isEmpty()); + map.remove("x"); + assertTrue(map.isEmpty()); + } + + @Test + public void testBulkInsertPerformance() { + int N = 100; + long start = System.nanoTime(); + for (int i = 0; i < N; i++) { + map.put("key" + i, i); + } + long end = System.nanoTime(); + + assertEquals(N, map.size()); + System.out.println("[PUT 100개] 걸린 시간: " + (end - start) / 1_000_000.0 + " ms"); + } + + @Test + public void testGetPerformance() { + int N = 100; + for (int i = 0; i < N; i++) { + map.put("key" + i, i); + } + + long start = System.nanoTime(); + for (int i = 0; i < N; i++) { + assertEquals(i, map.get("key" + i)); + } + long end = System.nanoTime(); + + System.out.println("[GET 100개] 걸린 시간: " + (end - start) / 1_000_000.0 + " ms"); + } + + @Test + public void testRemovePerformance() { + int N = 100; + for (int i = 0; i < N; i++) { + map.put("key" + i, i); + } + + long start = System.nanoTime(); + for (int i = 0; i < N; i++) { + assertEquals(i, map.remove("key" + i)); + } + long end = System.nanoTime(); + + assertEquals(0, map.size()); + System.out.println("[REMOVE 100개] 걸린 시간: " + (end - start) / 1_000_000.0 + " ms"); + } +} +