├── .gitignore ├── README.md └── src └── com └── ongdev ├── array ├── DynamicArray.java ├── LinearProbingHashTable.java └── QuadraticProbingHashTable.java ├── hashtable ├── HashTableADT.java ├── Node.java ├── OpenAddressingHashTableBase.java ├── SeparateChainingHashTable.java ├── Test.java └── TestOpenAddressing.java ├── linkedlist ├── DefaultDoublyLinkedList.java ├── DoublyLinkedList.java └── Node.java ├── queue ├── CircularArrayBasedQueue.java ├── LinkedListBasedQueue.java ├── QueueADT.java └── QueueTest.java ├── recursion ├── comparison.txt ├── fib.js └── fib.txt ├── stack ├── ArrayBasedStack.java ├── LinkedListBasedStack.java ├── StackADT.java └── StackTest.java └── tree ├── BinarySearchTree.java ├── BinarySearchTreeTest.java ├── Node.java ├── TreeADT.java └── TreeTraverseType.java /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/intellij+all 3 | # Edit at https://www.gitignore.io/?templates=intellij+all 4 | 5 | ### Intellij+all ### 6 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 7 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 8 | 9 | # User-specific stuff 10 | .idea/**/workspace.xml 11 | .idea/**/tasks.xml 12 | .idea/**/usage.statistics.xml 13 | .idea/**/dictionaries 14 | .idea/**/shelf 15 | 16 | # Generated files 17 | .idea/**/contentModel.xml 18 | 19 | # Sensitive or high-churn files 20 | .idea/**/dataSources/ 21 | .idea/**/dataSources.ids 22 | .idea/**/dataSources.local.xml 23 | .idea/**/sqlDataSources.xml 24 | .idea/**/dynamic.xml 25 | .idea/**/uiDesigner.xml 26 | .idea/**/dbnavigator.xml 27 | 28 | # Gradle 29 | .idea/**/gradle.xml 30 | .idea/**/libraries 31 | 32 | # Gradle and Maven with auto-import 33 | # When using Gradle or Maven with auto-import, you should exclude module files, 34 | # since they will be recreated, and may cause churn. Uncomment if using 35 | # auto-import. 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | # *.iml 40 | # *.ipr 41 | 42 | # CMake 43 | cmake-build-*/ 44 | 45 | # Mongo Explorer plugin 46 | .idea/**/mongoSettings.xml 47 | 48 | # File-based project format 49 | *.iws 50 | 51 | # IntelliJ 52 | out/ 53 | 54 | # mpeltonen/sbt-idea plugin 55 | .idea_modules/ 56 | 57 | # JIRA plugin 58 | atlassian-ide-plugin.xml 59 | 60 | # Cursive Clojure plugin 61 | .idea/replstate.xml 62 | 63 | # Crashlytics plugin (for Android Studio and IntelliJ) 64 | com_crashlytics_export_strings.xml 65 | crashlytics.properties 66 | crashlytics-build.properties 67 | fabric.properties 68 | 69 | # Editor-based Rest Client 70 | .idea/httpRequests 71 | 72 | # Android studio 3.1+ serialized cache file 73 | .idea/caches/build_file_checksums.ser 74 | 75 | ### Intellij+all Patch ### 76 | # Ignores the whole .idea folder and all .iml files 77 | # See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 78 | 79 | .idea/ 80 | 81 | # Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 82 | 83 | *.iml 84 | modules.xml 85 | .idea/misc.xml 86 | *.ipr 87 | 88 | # Sonarlint plugin 89 | .idea/sonarlint 90 | 91 | # End of https://www.gitignore.io/api/intellij+all -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ds-a-tut -------------------------------------------------------------------------------- /src/com/ongdev/array/DynamicArray.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.array; 2 | 3 | import java.util.Iterator; 4 | 5 | public class DynamicArray implements Iterable{ 6 | 7 | private T[] arr; 8 | private int capacity; 9 | private int size = 0; 10 | 11 | public DynamicArray(){ 12 | this(10); 13 | } 14 | 15 | public DynamicArray(int capacity){ 16 | if(capacity<0) throw new IllegalArgumentException("Capacity cannot be negative: "+capacity); 17 | this.capacity = capacity; 18 | arr = (T[]) new Object[capacity]; 19 | } 20 | 21 | public int size(){ 22 | return this.size; 23 | } 24 | 25 | public boolean isEmpty(){ 26 | return size() == 0; 27 | } 28 | 29 | public T get(int index){ 30 | return arr[index]; 31 | } 32 | 33 | public void set(int index, T element){ 34 | arr[index] = element; 35 | } 36 | 37 | public void clear(){ 38 | for(int i =0; i< size; i++){ 39 | arr[i] = null; 40 | } 41 | size = 0; 42 | } 43 | 44 | public void add(T element){ 45 | if(size >= capacity-1){ 46 | if(capacity == 0) capacity =1; 47 | else{ 48 | capacity *=2; 49 | } 50 | T[] newArr = (T[]) new Object[capacity]; 51 | for(int i=0; i=size || removeIndex<0) throw new IndexOutOfBoundsException(); 61 | T[] newArr = (T[]) new Object[size-1]; 62 | 63 | for(int oldArrIndex = 0, newArrIndex = 0; oldArrIndex < size; oldArrIndex++,newArrIndex++){ 64 | if(oldArrIndex == removeIndex) newArrIndex--; 65 | else newArr[newArrIndex] = arr[oldArrIndex]; 66 | } 67 | arr = newArr; 68 | capacity = --size; 69 | } 70 | 71 | public T removeAtWithoutMoving(int removeIndex) { 72 | if(removeIndex>=size || removeIndex<0) throw new IndexOutOfBoundsException(); 73 | T item = arr[removeIndex]; 74 | arr[removeIndex] = null; 75 | capacity = --size; 76 | return item; 77 | } 78 | 79 | public void remove(Object object){ 80 | int removeIndex = indexOf(object); 81 | removeAt(removeIndex); 82 | } 83 | 84 | public int indexOf(Object object) { 85 | for(int i =0;i iterator() { 104 | return new Iterator<>() { 105 | int index = 0; 106 | 107 | @Override 108 | public boolean hasNext() { 109 | return index < size(); 110 | } 111 | 112 | @Override 113 | public T next() { 114 | return arr[index++]; 115 | } 116 | }; 117 | } 118 | 119 | @Override 120 | public String toString() { 121 | if(isEmpty()) return "[]"; 122 | else{ 123 | StringBuilder sb = new StringBuilder(size); 124 | sb.append("["); 125 | for(int i = 0; i< size -1; i++){ 126 | sb.append(arr[i]).append(","); 127 | } 128 | sb.append(arr[size-1]).append("]"); 129 | return sb.toString(); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/com/ongdev/array/LinearProbingHashTable.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.array; 2 | 3 | import com.ongdev.hashtable.OpenAddressingHashTableBase; 4 | 5 | public class LinearProbingHashTable extends OpenAddressingHashTableBase { 6 | private static final int LINEAR_CONSTANT = 13; 7 | 8 | public LinearProbingHashTable() { 9 | super(); 10 | } 11 | 12 | public LinearProbingHashTable(int capacity) { 13 | super(capacity); 14 | } 15 | 16 | public LinearProbingHashTable(double loadFactor, int capacity) { 17 | super(loadFactor, capacity); 18 | } 19 | 20 | @Override 21 | protected void setupProbing(K key) {} 22 | 23 | @Override 24 | protected int probe(int x) { 25 | return x * LINEAR_CONSTANT; 26 | } 27 | 28 | @Override 29 | protected void adjustCapacity() { 30 | while (gcd(LINEAR_CONSTANT, capacity) != 1) { 31 | capacity++; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/ongdev/array/QuadraticProbingHashTable.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.array; 2 | 3 | import com.ongdev.hashtable.OpenAddressingHashTableBase; 4 | 5 | public class QuadraticProbingHashTable extends OpenAddressingHashTableBase { 6 | public QuadraticProbingHashTable() { 7 | super(); 8 | } 9 | 10 | public QuadraticProbingHashTable(int capacity) { 11 | super(capacity); 12 | } 13 | 14 | public QuadraticProbingHashTable(double loadFactor, int capacity) { 15 | super(loadFactor, capacity); 16 | } 17 | 18 | private static int nextPowerOfTwo(int n) { 19 | return Integer.highestOneBit(n) << 1; 20 | } 21 | 22 | @Override 23 | protected void setupProbing(K key) {} 24 | 25 | @Override 26 | protected int probe(int x) { 27 | // (x^2 +x)/2 size: 2^abc 28 | return (x * x + x) >> 1; 29 | } 30 | 31 | @Override 32 | protected void increaseCapacity() { 33 | capacity = nextPowerOfTwo(capacity); 34 | } 35 | 36 | @Override 37 | protected void adjustCapacity() { 38 | int po2 = Integer.highestOneBit(capacity); 39 | if (capacity == po2) return; 40 | increaseCapacity(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/ongdev/hashtable/HashTableADT.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.hashtable; 2 | 3 | public interface HashTableADT extends Iterable{ 4 | int size(); 5 | boolean isEmpty(); 6 | int hashCodeToIndex(int hashedKey); 7 | void clear(); 8 | boolean has(K key); 9 | V insert(K key, V value); 10 | V get(K key); 11 | V remove(K key); 12 | } 13 | -------------------------------------------------------------------------------- /src/com/ongdev/hashtable/Node.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.hashtable; 2 | 3 | public class Node { 4 | private int hash; 5 | private K key; 6 | private V value; 7 | 8 | public Node(K key, V value) { 9 | this.hash = key.hashCode(); 10 | this.key = key; 11 | this.value = value; 12 | } 13 | 14 | public boolean equals(Node other) { 15 | if(other.hash != hash) return false; 16 | return key.equals(other.key); 17 | } 18 | 19 | public int getHash() { 20 | return hash; 21 | } 22 | 23 | public K getKey() { 24 | return key; 25 | } 26 | 27 | public V getValue() { 28 | return value; 29 | } 30 | 31 | public void setValue(V value) { 32 | this.value = value; 33 | } 34 | 35 | public void setKey(K key) { 36 | this.key = key; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return "key=" + key + ", value=" + value; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/com/ongdev/hashtable/OpenAddressingHashTableBase.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.hashtable; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | public abstract class OpenAddressingHashTableBase implements HashTableADT { 8 | protected double loadFactor; 9 | protected int capacity, threshold; 10 | 11 | protected int usedSlots, keyCount; 12 | 13 | protected K[] keys; 14 | protected V[] values; 15 | 16 | protected final K TOMBSTONE = (K) (new Object()); 17 | 18 | protected static final int DEFAULT_CAPACITY = 7; 19 | protected static final double DEFAULT_LOAD_FACTOR = 0.6; 20 | 21 | protected OpenAddressingHashTableBase() { 22 | this(DEFAULT_LOAD_FACTOR, DEFAULT_CAPACITY); 23 | } 24 | 25 | protected OpenAddressingHashTableBase(int capacity) { 26 | this(DEFAULT_LOAD_FACTOR, capacity); 27 | } 28 | 29 | protected OpenAddressingHashTableBase(double loadFactor, int capacity) { 30 | if(capacity < 0) throw new IllegalArgumentException("Capacity bi gi ay ong ei"); 31 | if(loadFactor <= 0 || Double.isNaN(loadFactor) || Double.isInfinite(loadFactor)) { 32 | throw new IllegalArgumentException("load factor bi gi ay ong ei"); 33 | } 34 | this.loadFactor = loadFactor; 35 | this.capacity = Math.max(DEFAULT_CAPACITY, capacity); 36 | adjustCapacity(); 37 | this.threshold = (int) (this.capacity * loadFactor); 38 | 39 | keys = (K[]) new Object[this.capacity]; 40 | values = (V[]) new Object[this.capacity]; 41 | } 42 | 43 | protected abstract void setupProbing(K key); 44 | 45 | protected abstract int probe(int x); 46 | 47 | protected abstract void adjustCapacity(); 48 | 49 | protected void increaseCapacity() { 50 | // capacity = capacity * 2 +1 51 | capacity *= 2; 52 | } 53 | 54 | @Override 55 | public void clear() { 56 | for (int i = 0; i keys() { 83 | List hashtableKeys = new ArrayList<>(size()); 84 | for (int i = 0; i < capacity; i++) { 85 | // keys K[] null, TOMBSTONE, K-V 86 | if (keys[i] != null && keys[i] != TOMBSTONE) hashtableKeys.add(keys[i]); 87 | } 88 | 89 | return hashtableKeys; 90 | } 91 | 92 | public List values() { 93 | List hashtableValues = new ArrayList<>(size()); 94 | for (int i = 0; i < capacity; i++) { 95 | // keys K[] null, TOMBSTONE, K-V 96 | if (keys[i] != null && keys[i] != TOMBSTONE) hashtableValues.add(values[i]); 97 | } 98 | 99 | return hashtableValues; 100 | } 101 | 102 | protected void resizeTable() { 103 | increaseCapacity(); 104 | adjustCapacity(); 105 | 106 | threshold = (int) (capacity * loadFactor); 107 | 108 | // Create new table 109 | 110 | K[] oldKeys = (K[]) new Object[capacity]; 111 | V[] oldValues = (V[]) new Object[capacity]; 112 | 113 | // Swap keys pointer 114 | K[] tempKeys = keys; 115 | keys = oldKeys; 116 | oldKeys = tempKeys; 117 | 118 | // Swap values pointer 119 | V[] tempValues = values; 120 | values = oldValues; 121 | oldValues = tempValues; 122 | 123 | usedSlots = keyCount = 0; 124 | // Insert old key-value to new table 125 | for (int i = 0; i < oldKeys.length; i++) { 126 | if (oldKeys[i] != null && oldKeys != TOMBSTONE) { 127 | insert(oldKeys[i], oldValues[i]); 128 | } 129 | oldKeys[i] = null; 130 | oldValues[i] = null; 131 | } 132 | } 133 | 134 | protected static int gcd(int a, int b) { 135 | if (b == 0) return a; 136 | return gcd(b, a % b); 137 | } 138 | 139 | @Override 140 | public V insert(K key, V value) { 141 | if (key == null) throw new IllegalArgumentException("Null key"); 142 | if (usedSlots >= threshold) resizeTable(); 143 | 144 | setupProbing(key); 145 | 146 | final int offset = hashCodeToIndex(key.hashCode()); 147 | 148 | for (int i = offset, x=1, firstTombstoneIndex = -1; ; i = hashCodeToIndex(offset + probe(x++))) { 149 | if (keys[i] == TOMBSTONE) { 150 | if (firstTombstoneIndex == -1) { 151 | firstTombstoneIndex = i; 152 | } 153 | } else if (keys[i] != null) { 154 | if (keys[i].equals(key)) { 155 | V oldValue = values[i]; 156 | if(firstTombstoneIndex == -1) { 157 | values[i] = value; 158 | } else { 159 | keys[firstTombstoneIndex] = key; 160 | values[firstTombstoneIndex] = value; 161 | keys[i] = TOMBSTONE; 162 | values[i] = null; 163 | } 164 | return oldValue; 165 | } 166 | } else { 167 | if(firstTombstoneIndex == -1) { 168 | usedSlots++; 169 | keyCount++; 170 | keys[i] = key; 171 | values[i] = value; 172 | } else { 173 | keyCount++; 174 | keys[firstTombstoneIndex] = key; 175 | values[firstTombstoneIndex] = value; 176 | } 177 | return null; 178 | } 179 | } 180 | } 181 | 182 | 183 | @Override 184 | public boolean has(K key) { 185 | if (key == null) throw new IllegalArgumentException("Null key"); 186 | 187 | setupProbing(key); 188 | final int offset = hashCodeToIndex(key.hashCode()); 189 | 190 | for (int i = offset, x=1, firstTombstoneIndex = -1; ; i = hashCodeToIndex(offset + probe(x++))) { 191 | if (keys[i] == TOMBSTONE) { 192 | if (firstTombstoneIndex == -1) { 193 | firstTombstoneIndex = i; 194 | } 195 | } else if (keys[i] != null){ 196 | if(keys[i].equals(key)) { 197 | if(firstTombstoneIndex != -1) { 198 | keys[firstTombstoneIndex] = key; 199 | values[firstTombstoneIndex] = values[i]; 200 | keys[i] = TOMBSTONE; 201 | values[i] = null; 202 | } 203 | return true; 204 | } 205 | } else return false; 206 | } 207 | } 208 | 209 | @Override 210 | public V get(K key) { 211 | if (key == null) throw new IllegalArgumentException("Null key"); 212 | 213 | setupProbing(key); 214 | final int offset = hashCodeToIndex(key.hashCode()); 215 | 216 | for (int i = offset, x=1, firstTombstoneIndex = -1; ; i = hashCodeToIndex(offset + probe(x++))) { 217 | if (keys[i] == TOMBSTONE) { 218 | if (firstTombstoneIndex == -1) { 219 | firstTombstoneIndex = i; 220 | } 221 | } else if (keys[i] != null){ 222 | if(keys[i].equals(key)) { 223 | V value = values[i]; 224 | if(firstTombstoneIndex != -1) { 225 | keys[firstTombstoneIndex] = key; 226 | values[firstTombstoneIndex] = values[i]; 227 | keys[i] = TOMBSTONE; 228 | values[i] = null; 229 | } 230 | return value; 231 | } 232 | } else return null; 233 | } 234 | } 235 | 236 | @Override 237 | public V remove(K key) { 238 | if (key == null) throw new IllegalArgumentException("Null key"); 239 | 240 | setupProbing(key); 241 | final int offset = hashCodeToIndex(key.hashCode()); 242 | 243 | for (int i = offset, x=1; ; i = hashCodeToIndex(offset + probe(x++))) { 244 | if (keys[i] == TOMBSTONE) continue; 245 | 246 | if (keys[i] == null) return null; 247 | 248 | if(keys[i] == key){ 249 | keyCount--; 250 | V oldValue = values[i]; 251 | keys[i] = TOMBSTONE; 252 | values[i] = null; 253 | return oldValue; 254 | } 255 | } 256 | } 257 | 258 | @Override 259 | public String toString() { 260 | StringBuilder sb = new StringBuilder(); 261 | sb.append("{"); 262 | for (int i = 0; i < capacity; i++) { 263 | if(keys[i] != null && keys[i] != TOMBSTONE) sb.append(keys[i]).append(" > ").append(values[i]).append(", "); 264 | } 265 | sb.append("}"); 266 | return sb.toString(); 267 | } 268 | 269 | @Override 270 | public Iterator iterator() { 271 | return new Iterator() { 272 | int index, keysLeft = keyCount; 273 | @Override 274 | public boolean hasNext() { 275 | // TODO: Add modification Count 276 | return keysLeft != 0; 277 | } 278 | 279 | @Override 280 | public K next() { 281 | while (keys[index] == null || keys[index] == TOMBSTONE) index++; 282 | keysLeft--; 283 | return keys[index++]; 284 | } 285 | }; 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /src/com/ongdev/hashtable/SeparateChainingHashTable.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.hashtable; 2 | 3 | import com.ongdev.linkedlist.DefaultDoublyLinkedList; 4 | import com.ongdev.linkedlist.DoublyLinkedList; 5 | 6 | import java.util.Arrays; 7 | import java.util.ConcurrentModificationException; 8 | import java.util.Iterator; 9 | 10 | public class SeparateChainingHashTable implements HashTableADT{ 11 | private static final int DEFAULT_CAPACITY = 10; 12 | private static final double DEFAULT_LOAD_FACTOR = 0.5; 13 | 14 | private final double loadFactor; 15 | private int size = 0, capacity, threshold; 16 | 17 | private DoublyLinkedList>[] table; 18 | 19 | public SeparateChainingHashTable() { 20 | this(DEFAULT_LOAD_FACTOR, DEFAULT_CAPACITY); 21 | } 22 | 23 | public SeparateChainingHashTable(int capacity) { 24 | this(DEFAULT_LOAD_FACTOR, capacity); 25 | } 26 | 27 | public SeparateChainingHashTable(double loadFactor, int capacity) { 28 | if(capacity < 0) throw new IllegalArgumentException("Capacity bi gi ay ong ei"); 29 | if(loadFactor <= 0 || Double.isNaN(loadFactor) || Double.isInfinite(loadFactor)) { 30 | throw new IllegalArgumentException("load factor bi gi ay ong ei"); 31 | } 32 | this.loadFactor = loadFactor; 33 | this.capacity = Math.max(DEFAULT_CAPACITY, capacity); 34 | this.threshold = (int) (this.capacity * loadFactor); 35 | table = new DefaultDoublyLinkedList[capacity]; 36 | } 37 | 38 | @Override 39 | public int size() { 40 | return size; 41 | } 42 | 43 | @Override 44 | public boolean isEmpty() { 45 | return size() == 0; 46 | } 47 | 48 | @Override 49 | public int hashCodeToIndex(int hashedKey) { 50 | return (int) ((hashedKey & 0xFFFFFFFFFL) % capacity); 51 | } 52 | 53 | @Override 54 | public void clear() { 55 | Arrays.fill(table, null); 56 | size = 0; 57 | } 58 | 59 | @Override 60 | public boolean has(K key) { 61 | int index = hashCodeToIndex(key.hashCode()); 62 | DoublyLinkedList> linkedList = table[index]; 63 | 64 | if(linkedList == null || linkedList.isEmpty()) return false; 65 | 66 | for(Node node : linkedList) { 67 | if(node.getKey().equals(key)) return true; 68 | } 69 | return false; 70 | } 71 | 72 | @Override 73 | public V insert(K key, V value) { 74 | int index = hashCodeToIndex(key.hashCode()); 75 | DoublyLinkedList> linkedList = table[index]; 76 | if(linkedList == null ) { 77 | table[index] = linkedList = new DefaultDoublyLinkedList<>(); 78 | return addNodeToBucket(key, value, linkedList); 79 | } else if(linkedList.isEmpty()) { 80 | return addNodeToBucket(key, value, linkedList); 81 | }else { 82 | for(Node node : linkedList) { 83 | if(node.getKey().equals(key)){ 84 | V oldValue = node.getValue(); 85 | node.setValue(value); 86 | return oldValue; 87 | } 88 | } 89 | return addNodeToBucket(key, value, linkedList); 90 | } 91 | } 92 | 93 | private V addNodeToBucket(K key, V value, DoublyLinkedList> linkedList) { 94 | linkedList.add(new Node<>(key, value)); 95 | if (++size > threshold) resizeTable(); 96 | return null; 97 | } 98 | 99 | private void resizeTable() { 100 | capacity *= 2; 101 | threshold = (int) (this.capacity * loadFactor); 102 | DoublyLinkedList>[] newTable = new DefaultDoublyLinkedList[capacity]; 103 | for (int i = 0; i< table.length; i++) { 104 | if(table[i] == null) continue; 105 | 106 | for(Node node : table[i]){ 107 | int index = hashCodeToIndex(node.getHash()); 108 | DoublyLinkedList> linkedList = newTable[index]; 109 | if(linkedList == null) 110 | newTable[index] = linkedList = new DefaultDoublyLinkedList<>(); 111 | linkedList.add(node); 112 | } 113 | 114 | table[i].clear(); 115 | table[i] = null; 116 | } 117 | 118 | table = newTable; 119 | } 120 | 121 | @Override 122 | public V get(K key) { 123 | int index = hashCodeToIndex(key.hashCode()); 124 | DoublyLinkedList> linkedList = table[index]; 125 | 126 | if(linkedList == null || linkedList.isEmpty()) return null; 127 | for(Node node: linkedList) { 128 | if(node.getKey().equals(key)) return node.getValue(); 129 | } 130 | 131 | return null; 132 | } 133 | 134 | @Override 135 | public V remove(K key) { 136 | int index = hashCodeToIndex(key.hashCode()); 137 | DoublyLinkedList> linkedList = table[index]; 138 | 139 | if(linkedList == null || linkedList.isEmpty()) return null; 140 | for(Node node: linkedList) { 141 | if(node.getKey().equals(key)) { 142 | linkedList.remove(node); 143 | --size; 144 | return node.getValue(); 145 | } 146 | } 147 | return null; 148 | } 149 | 150 | @Override 151 | public Iterator iterator() { 152 | final int elementCount = size(); 153 | 154 | return new Iterator() { 155 | int index = 0; 156 | Iterator> bucketIterator = table[0] == null ? null : table[0].iterator(); 157 | 158 | @Override 159 | public boolean hasNext() { 160 | if(elementCount != size()) throw new ConcurrentModificationException("Table bi doi mat tieu luonnnnnn!"); 161 | 162 | if(bucketIterator == null || !bucketIterator.hasNext()) { 163 | while(++index < capacity) { 164 | if(table[index] != null || !table[index].isEmpty() ) { 165 | bucketIterator = table[index].iterator(); 166 | break; 167 | } 168 | } 169 | } 170 | return index < capacity; 171 | } 172 | 173 | @Override 174 | public K next() { 175 | return bucketIterator.next().getKey(); 176 | } 177 | }; 178 | } 179 | 180 | @Override 181 | public String toString() { 182 | StringBuilder sb = new StringBuilder(); 183 | sb.append("{"); 184 | for (int i = 0; i < table.length; i ++) { 185 | DoublyLinkedList> linkedList = table[i]; 186 | 187 | if(linkedList == null || linkedList.isEmpty()) continue; 188 | 189 | Iterator> iterator = linkedList.iterator(); 190 | 191 | do { 192 | Node node = iterator.next(); 193 | sb.append(node.toString()).append(", "); 194 | }while (iterator.hasNext()); 195 | } 196 | sb.append("}"); 197 | return sb.toString(); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/com/ongdev/hashtable/Test.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.hashtable; 2 | 3 | import java.util.Random; 4 | 5 | public class Test { 6 | static final int NUMBER_OF_KEYS = 100000000; 7 | static final int MOD = 100000; 8 | static int[] keys = new int[NUMBER_OF_KEYS]; 9 | static int[] values = new int[NUMBER_OF_KEYS]; 10 | 11 | public static void main(String[] args) { 12 | Random random = new Random(); 13 | for(int i = 0; i< keys.length; i++) { 14 | keys[i] = random.nextInt() % MOD; 15 | values[i] = random.nextInt() % MOD; 16 | } 17 | testSeparateChaining(); 18 | } 19 | 20 | private static void testSeparateChaining() { 21 | HashTableADT hashtable = new SeparateChainingHashTable<>(MOD); 22 | long start = System.nanoTime(); 23 | for(int i = 0; i< NUMBER_OF_KEYS; i++){ 24 | hashtable.insert(keys[i], values[i]); 25 | int value = hashtable.get(keys[i]); 26 | if(value != values[i]) System.out.println("Code lai di ma"); 27 | } 28 | long end = System.nanoTime(); 29 | System.out.println("Separate chaining: " + (end - start) / 1e9); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/com/ongdev/hashtable/TestOpenAddressing.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.hashtable; 2 | 3 | import com.ongdev.array.LinearProbingHashTable; 4 | import com.ongdev.array.QuadraticProbingHashTable; 5 | 6 | import java.util.Random; 7 | 8 | public class TestOpenAddressing { 9 | static final int NUMBER_OF_KEYS = 100000000; 10 | static final int MOD = 100000; 11 | static int[] keys = new int[NUMBER_OF_KEYS]; 12 | static int[] values = new int[NUMBER_OF_KEYS]; 13 | 14 | public static void main(String[] args) { 15 | Random random = new Random(); 16 | for(int i = 0; i< keys.length; i++) { 17 | keys[i] = random.nextInt() % MOD; 18 | values[i] = random.nextInt() % MOD; 19 | } 20 | testLinearProbing(); 21 | testQuadraticProbing(); 22 | } 23 | 24 | private static void testQuadraticProbing() { 25 | HashTableADT hashtable = new LinearProbingHashTable<>(); 26 | long start = System.nanoTime(); 27 | for(int i = 0; i< NUMBER_OF_KEYS; i++){ 28 | hashtable.insert(keys[i], values[i]); 29 | int value = hashtable.get(keys[i]); 30 | if(value != values[i]) System.out.println("Code lai di ma"); 31 | } 32 | long end = System.nanoTime(); 33 | System.out.println("Linear probing: " + (end - start) / 1e9); 34 | } 35 | 36 | private static void testLinearProbing() { 37 | HashTableADT hashtable = new QuadraticProbingHashTable<>(); 38 | long start = System.nanoTime(); 39 | for(int i = 0; i< NUMBER_OF_KEYS; i++){ 40 | hashtable.insert(keys[i], values[i]); 41 | int value = hashtable.get(keys[i]); 42 | if(value != values[i]) System.out.println("Code lai di ma"); 43 | } 44 | long end = System.nanoTime(); 45 | System.out.println("Quadratic probing: " + (end - start) / 1e9); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/com/ongdev/linkedlist/DefaultDoublyLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.linkedlist; 2 | 3 | import java.util.Iterator; 4 | 5 | public class DefaultDoublyLinkedList implements DoublyLinkedList{ 6 | private int size; 7 | private Node head = null; 8 | private Node tail = null; 9 | 10 | @Override 11 | public void clear() { 12 | Node currentNode = head; 13 | while (currentNode != null){ 14 | Node nextNode = currentNode.getNext(); 15 | currentNode.setNext(null); 16 | currentNode.setPrev(null); 17 | currentNode.setData(null); 18 | currentNode = nextNode; 19 | } 20 | head = tail = null; 21 | size = 0; 22 | } 23 | 24 | @Override 25 | public int size() { 26 | return size; 27 | } 28 | 29 | @Override 30 | public boolean isEmpty() { 31 | return size() == 0; 32 | } 33 | 34 | @Override 35 | public void add(T element) { 36 | addLast(element); 37 | } 38 | 39 | @Override 40 | public void addFirst(T element) { 41 | if(isEmpty()){ 42 | head = tail = new Node<>(element, null, null); 43 | }else{ 44 | head.setPrev(new Node<>(element, null, head)); 45 | head = head.getPrev(); 46 | } 47 | size++; 48 | } 49 | 50 | @Override 51 | public void addLast(T element) { 52 | if(isEmpty()){ 53 | head = tail = new Node<>(element, null, null); 54 | }else{ 55 | tail.setNext(new Node<>(element, tail, null)); 56 | tail = tail.getNext(); 57 | } 58 | size++; 59 | } 60 | 61 | @Override 62 | public T peekFirst() { 63 | if(isEmpty()) throw new RuntimeException("Empty linked list!"); 64 | return head.getData(); 65 | } 66 | 67 | @Override 68 | public T peekLast() { 69 | if(isEmpty()) throw new RuntimeException("Empty linked list!"); 70 | return tail.getData(); 71 | } 72 | 73 | @Override 74 | public T removeFirst() { 75 | if(isEmpty()) throw new RuntimeException("Empty linked list!"); 76 | T data = head.getData(); 77 | head = head.getNext(); 78 | size--; 79 | if(isEmpty()) tail = null; 80 | else head.setPrev(null); 81 | 82 | return data; 83 | } 84 | 85 | @Override 86 | public T removeLast() { 87 | if(isEmpty()) throw new RuntimeException("Empty linked list!"); 88 | T data = tail.getData(); 89 | tail = tail.getPrev(); 90 | size--; 91 | if(isEmpty()) head = null; 92 | else tail.setNext(null); 93 | 94 | return data; 95 | } 96 | 97 | @Override 98 | public T remove(Node node) { 99 | if(node.getPrev()==null) removeFirst(); 100 | if(node.getNext()==null) removeLast(); 101 | 102 | node.getPrev().setNext(node.getNext()); 103 | node.getNext().setPrev(node.getPrev()); 104 | 105 | T data = node.getData(); 106 | size--; 107 | 108 | node.setData(null); 109 | node.setNext(null); 110 | node.setPrev(null); 111 | node = null; 112 | 113 | return data; 114 | } 115 | 116 | @Override 117 | public boolean remove(Object object) { 118 | Node currentNode = head; 119 | 120 | if(object == null){ 121 | while (currentNode != null){ 122 | if(currentNode.getData() == null){ 123 | remove(currentNode); 124 | return true; 125 | } 126 | currentNode = currentNode.getNext(); 127 | } 128 | }else{ 129 | while (currentNode != null){ 130 | if(currentNode.getData() == object){ 131 | remove(currentNode); 132 | return true; 133 | } 134 | currentNode = currentNode.getNext(); 135 | } 136 | } 137 | return false; 138 | } 139 | 140 | @Override 141 | public T removeAt(int index) { 142 | if(index < 0 || index >= size) throw new IllegalArgumentException(); 143 | 144 | int i; 145 | Node currentNode; 146 | 147 | if(index < size / 2){ 148 | i = 0; 149 | currentNode = head; 150 | while (i != index) { 151 | currentNode = currentNode.getNext(); 152 | i++; 153 | } 154 | }else{ 155 | i = size - 1; 156 | currentNode = tail; 157 | while (i != index) { 158 | currentNode = currentNode.getPrev(); 159 | i--; 160 | } 161 | } 162 | 163 | return remove(currentNode); 164 | } 165 | 166 | @Override 167 | public int indexOf(Object object) { 168 | int index = 0; 169 | Node currentNode = head; 170 | 171 | if(object == null){ 172 | while (currentNode != null){ 173 | if(currentNode.getData()==null){ 174 | return index; 175 | } 176 | currentNode = currentNode.getNext(); 177 | index++; 178 | } 179 | }else{ 180 | while (currentNode != null){ 181 | if(currentNode.getData()==object){ 182 | return index; 183 | } 184 | currentNode = currentNode.getNext(); 185 | index++; 186 | } 187 | } 188 | return -1; 189 | } 190 | 191 | @Override 192 | public boolean contains(Object object) { 193 | return indexOf(object) != -1; 194 | } 195 | 196 | @Override 197 | public Iterator iterator() { 198 | return new Iterator<>() { 199 | private boolean isEntering = true; 200 | private Node currentNode = null; 201 | 202 | @Override 203 | public boolean hasNext() { 204 | if(isEntering) { 205 | return head != null; 206 | } 207 | return currentNode.getNext() != null; 208 | } 209 | 210 | @Override 211 | public T next() { 212 | T data = null; 213 | if(isEntering) { 214 | data = head.getData(); 215 | currentNode = head; 216 | isEntering =false; 217 | }else { 218 | currentNode = currentNode.getNext(); 219 | data = currentNode.getData(); 220 | } 221 | return data; 222 | } 223 | }; 224 | } 225 | 226 | @Override 227 | public String toString() { 228 | if(isEmpty()) return "[]"; 229 | else{ 230 | StringBuilder sb = new StringBuilder(size); 231 | sb.append("[ "); 232 | 233 | Node currentNode = head; 234 | 235 | while (currentNode!=null){ 236 | sb.append(currentNode.getData()); 237 | if(currentNode.getNext()!=null) sb.append(", "); 238 | currentNode = currentNode.getNext(); 239 | } 240 | sb.append(" ]"); 241 | return sb.toString(); 242 | } 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/com/ongdev/linkedlist/DoublyLinkedList.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.linkedlist; 2 | 3 | public interface DoublyLinkedList extends Iterable { 4 | // O(n) 5 | void clear(); 6 | 7 | // constant 8 | int size(); 9 | 10 | // constant 11 | boolean isEmpty(); 12 | 13 | // O(1) 14 | void add(T element); 15 | 16 | // O(1) 17 | void addFirst(T element); 18 | 19 | // O(1) 20 | void addLast(T element); 21 | 22 | // O(1) 23 | T peekFirst(); 24 | 25 | // O(1) 26 | T peekLast(); 27 | 28 | // O(1) 29 | T removeFirst(); 30 | 31 | // O(1) 32 | T removeLast(); 33 | 34 | // O(1) 35 | T remove(Node node); 36 | 37 | // O(n) 38 | boolean remove(Object object); 39 | 40 | // O(n) 41 | T removeAt(int index); 42 | 43 | // O(n) 44 | int indexOf(Object object); 45 | 46 | // O(n) 47 | boolean contains(Object object); 48 | } 49 | -------------------------------------------------------------------------------- /src/com/ongdev/linkedlist/Node.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.linkedlist; 2 | 3 | class Node { 4 | private T data; 5 | 6 | public T getData() { 7 | return data; 8 | } 9 | 10 | public void setData(T data) { 11 | this.data = data; 12 | } 13 | 14 | public Node getPrev() { 15 | return prev; 16 | } 17 | 18 | public void setPrev(Node prev) { 19 | this.prev = prev; 20 | } 21 | 22 | public Node getNext() { 23 | return next; 24 | } 25 | 26 | public void setNext(Node next) { 27 | this.next = next; 28 | } 29 | 30 | private Node prev, next; 31 | 32 | public Node(T data, Node prev, Node next) { 33 | this.data = data; 34 | this.prev = prev; 35 | this.next = next; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return data.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/com/ongdev/queue/CircularArrayBasedQueue.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.queue; 2 | 3 | import java.util.Iterator; 4 | 5 | public class CircularArrayBasedQueue implements QueueADT{ 6 | private final T[] array; 7 | private int front; 8 | private int end; 9 | private final int size; 10 | 11 | public CircularArrayBasedQueue(int maxSize) { 12 | front = end = 0; 13 | size = maxSize + 1; 14 | array = (T[]) new Object[size]; 15 | } 16 | 17 | @Override 18 | public void enQueue(T element) { 19 | array[end] = element; 20 | if(++end == size) end = 0; 21 | if(end == front) throw new RuntimeException("Queue is full!"); 22 | } 23 | 24 | @Override 25 | public T deQueue() { 26 | if(isEmpty()) throw new RuntimeException("Queue empty"); 27 | T deQueuedElem = array[front]; 28 | if(++front == size) front = 0; 29 | return deQueuedElem; 30 | } 31 | 32 | @Override 33 | public T peek() { 34 | if(isEmpty()) throw new RuntimeException("Queue empty"); 35 | return array[front]; 36 | } 37 | 38 | @Override 39 | public int size() { 40 | if (front > end) return (end + size - front); 41 | return end - front; 42 | } 43 | 44 | @Override 45 | public boolean isEmpty() { 46 | return front == end; 47 | } 48 | 49 | @Override 50 | public Iterator iterator() { 51 | return new Iterator() { 52 | @Override 53 | public boolean hasNext() { 54 | return false; 55 | } 56 | 57 | @Override 58 | public T next() { 59 | return null; 60 | } 61 | }; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/com/ongdev/queue/LinkedListBasedQueue.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.queue; 2 | 3 | import com.ongdev.linkedlist.DefaultDoublyLinkedList; 4 | import com.ongdev.linkedlist.DoublyLinkedList; 5 | 6 | import java.util.Iterator; 7 | 8 | public class LinkedListBasedQueue implements QueueADT{ 9 | private final DoublyLinkedList linkedList = new DefaultDoublyLinkedList<>(); 10 | 11 | public LinkedListBasedQueue() { 12 | } 13 | 14 | public LinkedListBasedQueue(T firstElem) { 15 | enQueue(firstElem); 16 | } 17 | 18 | @Override 19 | public void enQueue(T element) { 20 | linkedList.addLast(element); 21 | } 22 | 23 | @Override 24 | public T deQueue() { 25 | if(isEmpty()) throw new RuntimeException("Queue empty"); 26 | return linkedList.removeFirst(); 27 | } 28 | 29 | @Override 30 | public T peek() { 31 | if(isEmpty()) throw new RuntimeException("Queue empty"); 32 | return linkedList.peekFirst(); 33 | } 34 | 35 | @Override 36 | public int size() { 37 | return linkedList.size(); 38 | } 39 | 40 | @Override 41 | public boolean isEmpty() { 42 | return size() == 0; 43 | } 44 | 45 | @Override 46 | public Iterator iterator() { 47 | return linkedList.iterator(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/com/ongdev/queue/QueueADT.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.queue; 2 | 3 | public interface QueueADT extends Iterable { 4 | void enQueue(T element); 5 | T deQueue(); 6 | T peek(); 7 | int size(); 8 | boolean isEmpty(); 9 | } 10 | -------------------------------------------------------------------------------- /src/com/ongdev/queue/QueueTest.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.queue; 2 | 3 | public class QueueTest { 4 | public static void main(String[] args) { 5 | int numberOfOperations = 10000000; 6 | 7 | // Array based stack 8 | QueueADT circularArrayBasedQueue = new CircularArrayBasedQueue<>(numberOfOperations); 9 | 10 | long startTime = System.nanoTime(); 11 | for (int i = 0; i< numberOfOperations; i++){ 12 | circularArrayBasedQueue.enQueue(i); 13 | } 14 | for (int i = 0; i< numberOfOperations/2; i++){ 15 | circularArrayBasedQueue.deQueue(); 16 | } 17 | for (int i = 0; i< numberOfOperations/4; i++){ 18 | circularArrayBasedQueue.enQueue(i); 19 | } 20 | for (int i = 0; i< 3*numberOfOperations/4; i++){ 21 | circularArrayBasedQueue.deQueue(); 22 | } 23 | long endTime = System.nanoTime(); 24 | long arrayTime = endTime - startTime; 25 | System.out.println("Circular array based queue took: "+ arrayTime +"\n"); 26 | 27 | 28 | // Linked list based stack 29 | QueueADT linkedListBasedQueue = new LinkedListBasedQueue<>(); 30 | 31 | startTime = System.nanoTime(); 32 | for (int i = 0; i< numberOfOperations; i++){ 33 | linkedListBasedQueue.enQueue(i); 34 | } 35 | for (int i = 0; i< numberOfOperations; i++){ 36 | linkedListBasedQueue.deQueue(); 37 | } 38 | endTime = System.nanoTime(); 39 | long linkedListTime = endTime - startTime; 40 | System.out.println("Linked list based stack took: "+ linkedListTime +"\n"); 41 | 42 | System.out.println("The difference: "+ (linkedListTime - arrayTime) +"\n"); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/com/ongdev/recursion/comparison.txt: -------------------------------------------------------------------------------- 1 | ### Recursion 2 | - Termination: Base case is reached 3 | - Memory: Each recursion step require more memory 4 | - Infinite: StackOverflowException 5 | 6 | ### Loop 7 | - Termination: false condition 8 | - Memory: Each loop doesn't require more memory 9 | - Infinite: Just run 10 | 11 | -------------------------------------------------------------------------------- /src/com/ongdev/recursion/fib.js: -------------------------------------------------------------------------------- 1 | function fib(n){ 2 | if(n<2) return 1; 3 | else return fib(n-1) + fib(n-2); 4 | } 5 | 6 | console.log(fib(10)) 7 | console.log(fib(6)) -------------------------------------------------------------------------------- /src/com/ongdev/recursion/fib.txt: -------------------------------------------------------------------------------- 1 | #Fibonacci 2 | fib = 1 1 2 3 5 8 13 21 34 55 89 .... 3 | 4 | fib(2) = fib(1) + fib(0) 5 | 6 | fib(n) = fib(n-1) + fib(n-2) 7 | 8 | fib(1) = fib(0) + fib(-1) 9 | 10 | n<2 : fib(n) = 1 11 | n>=2 : fib(n) = fib(n-1) + fib(n-2) 12 | 13 | n = 4 14 | 15 | fib(4) = fib(3) + fib(2) 16 | = fib(2) + fib(1) + fib(1) + fib(0) 17 | = fib(2) + 3 18 | = fib(1) + fib(0) +3 19 | = 5 20 | -------------------------------------------------------------------------------- /src/com/ongdev/stack/ArrayBasedStack.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.stack; 2 | 3 | import com.ongdev.array.DynamicArray; 4 | 5 | import java.util.EmptyStackException; 6 | import java.util.Iterator; 7 | 8 | public class ArrayBasedStack implements StackADT { 9 | private final DynamicArray array; 10 | private int index = -1; 11 | 12 | public ArrayBasedStack(int initSize){ 13 | array = new DynamicArray<>(initSize); 14 | } 15 | 16 | @Override 17 | public void push(T element) { 18 | index++; 19 | array.add(element); 20 | } 21 | 22 | @Override 23 | public T pop() { 24 | if(isEmpty()) { 25 | throw new EmptyStackException(); 26 | } 27 | return array.removeAtWithoutMoving(index--); 28 | } 29 | 30 | @Override 31 | public T top() { 32 | return array.get(index); 33 | } 34 | 35 | @Override 36 | public int size() { 37 | return array.size(); 38 | } 39 | 40 | @Override 41 | public boolean isEmpty() { 42 | return array.isEmpty(); 43 | } 44 | 45 | @Override 46 | public Iterator iterator() { 47 | return array.iterator(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/com/ongdev/stack/LinkedListBasedStack.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.stack; 2 | 3 | import com.ongdev.linkedlist.DefaultDoublyLinkedList; 4 | import com.ongdev.linkedlist.DoublyLinkedList; 5 | 6 | import java.util.EmptyStackException; 7 | import java.util.Iterator; 8 | 9 | public class LinkedListBasedStack implements StackADT{ 10 | private final DoublyLinkedList list = new DefaultDoublyLinkedList<>(); 11 | 12 | public LinkedListBasedStack() {} 13 | 14 | public LinkedListBasedStack(T element) { 15 | push(element); 16 | } 17 | 18 | @Override 19 | public void push(T element) { 20 | list.addLast(element); 21 | } 22 | 23 | @Override 24 | public T pop() { 25 | if(isEmpty()) throw new EmptyStackException(); 26 | return list.removeLast(); 27 | } 28 | 29 | @Override 30 | public T top() { 31 | if(isEmpty()) throw new EmptyStackException(); 32 | return list.peekLast(); 33 | } 34 | 35 | @Override 36 | public int size() { 37 | return list.size(); 38 | } 39 | 40 | @Override 41 | public boolean isEmpty() { 42 | return size() == 0; 43 | } 44 | 45 | @Override 46 | public Iterator iterator() { 47 | return list.iterator(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/com/ongdev/stack/StackADT.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.stack; 2 | 3 | public interface StackADT extends Iterable { 4 | void push(T element); 5 | T pop(); 6 | T top(); 7 | int size(); 8 | boolean isEmpty(); 9 | } 10 | -------------------------------------------------------------------------------- /src/com/ongdev/stack/StackTest.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.stack; 2 | 3 | public class StackTest { 4 | public static void main(String[] args) { 5 | int numberOfOperations = 10000000; 6 | 7 | // Array based stack 8 | StackADT arrayBasedStack = new ArrayBasedStack<>(10); 9 | 10 | long startTime = System.nanoTime(); 11 | for (int i = 0; i< numberOfOperations; i++){ 12 | arrayBasedStack.push(i); 13 | } 14 | for (int i = 0; i< numberOfOperations; i++){ 15 | arrayBasedStack.pop(); 16 | } 17 | long endTime = System.nanoTime(); 18 | System.out.println("Array based stack took: "+ (endTime - startTime) +"\n"); 19 | 20 | 21 | // Linked list based stack 22 | StackADT linkedListBasedStack = new LinkedListBasedStack<>(); 23 | 24 | startTime = System.nanoTime(); 25 | for (int i = 0; i< numberOfOperations; i++){ 26 | linkedListBasedStack.push(i); 27 | } 28 | for (int i = 0; i< numberOfOperations; i++){ 29 | linkedListBasedStack.pop(); 30 | } 31 | endTime = System.nanoTime(); 32 | System.out.println("Linked list based stack took: "+ (endTime - startTime) +"\n"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/ongdev/tree/BinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.tree; 2 | 3 | import com.ongdev.stack.LinkedListBasedStack; 4 | import com.ongdev.stack.StackADT; 5 | 6 | import java.util.ConcurrentModificationException; 7 | import java.util.Iterator; 8 | 9 | public class BinarySearchTree> implements TreeADT { 10 | private int nodeCount = 0; 11 | 12 | private Node root = null; 13 | 14 | @Override 15 | public boolean isEmpty() { 16 | return size() == 0; 17 | } 18 | 19 | @Override 20 | public int size() { 21 | return nodeCount; 22 | } 23 | 24 | @Override 25 | public int height() { 26 | return height(root); 27 | } 28 | 29 | @Override 30 | public boolean contains(T elem) { 31 | return contains(root, elem); 32 | } 33 | 34 | @Override 35 | public boolean add(T elem) { 36 | if(contains(elem)) return false; 37 | 38 | root = add(root, elem); 39 | nodeCount++; 40 | return true; 41 | } 42 | 43 | @Override 44 | public boolean remove(T elem) { 45 | if(!contains(elem)) return false; 46 | root = remove(root, elem); 47 | nodeCount--; 48 | return true; 49 | } 50 | 51 | 52 | @Override 53 | public Iterator traverse(TreeTraverseType type) { 54 | switch (type) { 55 | case PRE_ORDER : return preOrderTraverse(); 56 | case IN_ORDER : return inOderTraverse(); 57 | case POST_ORDER : return postOrderTraverse(); 58 | case LEVEL_ORDER : return levelOrderTraverse(); 59 | default: return null; 60 | } 61 | } 62 | 63 | private Iterator levelOrderTraverse() { 64 | return null; 65 | } 66 | 67 | private Iterator postOrderTraverse() { 68 | return null; 69 | } 70 | 71 | private Iterator inOderTraverse() { 72 | final int expectedCount = nodeCount; 73 | StackADT stack = new LinkedListBasedStack(); 74 | stack.push(root); 75 | 76 | return new Iterator() { 77 | Node trav = root; 78 | @Override 79 | public boolean hasNext() { 80 | if(expectedCount != nodeCount) throw new ConcurrentModificationException(); 81 | 82 | return root != null && !stack.isEmpty(); 83 | } 84 | 85 | @Override 86 | public T next() { 87 | if(expectedCount != nodeCount) throw new ConcurrentModificationException(); 88 | 89 | while (trav != null && trav.getLeft() != null){ 90 | stack.push(trav.getLeft()); 91 | trav = trav.getLeft(); 92 | } 93 | 94 | Node node = stack.pop(); 95 | 96 | if(node.getRight() != null) { 97 | stack.push(node.getRight()); 98 | trav = node.getRight(); 99 | } 100 | return (T) node.getData(); 101 | } 102 | }; 103 | } 104 | 105 | private Iterator preOrderTraverse() { 106 | final int expectedCount = nodeCount; 107 | StackADT stack = new LinkedListBasedStack(); 108 | stack.push(root); 109 | 110 | return new Iterator() { 111 | @Override 112 | public boolean hasNext() { 113 | if(expectedCount != nodeCount) throw new ConcurrentModificationException(); 114 | 115 | return root != null && !stack.isEmpty(); 116 | } 117 | 118 | @Override 119 | public T next() { 120 | if(expectedCount != nodeCount) throw new ConcurrentModificationException(); 121 | 122 | Node node = stack.pop(); 123 | 124 | if(node.getRight() != null)stack.push(node.getRight()); 125 | if(node.getLeft() != null)stack.push(node.getLeft()); 126 | return (T) node.getData(); 127 | } 128 | }; 129 | } 130 | // PRIVATE 131 | 132 | private int height(Node node) { 133 | if(node == null) return 0; 134 | return 1 + Math.max(height(node.getLeft()), height(node.getRight())); 135 | } 136 | private boolean contains(Node node, T elem) { 137 | if(node == null) return false; 138 | 139 | int result = elem.compareTo((T) node.getData()); 140 | 141 | if(result < 0) return contains(node.getLeft(), elem); 142 | 143 | else if (result > 0) return contains(node.getRight(), elem); 144 | 145 | else return true; 146 | } 147 | 148 | private Node add(Node node, T elem) { 149 | if(node == null) { 150 | node = new Node(elem, null, null); 151 | }else { 152 | if(elem.compareTo((T) node.getData()) > 0) { 153 | node.setRight(add(node.getRight(), elem)); 154 | }else { 155 | node.setLeft(add(node.getLeft(), elem)); 156 | } 157 | } 158 | return node; 159 | } 160 | 161 | private Node remove(Node node, T elem) { 162 | int result = elem.compareTo((T) node.getData()); 163 | if(result > 0) { 164 | node.setRight(remove(node.getRight(), elem)); 165 | } else if(result < 0) { 166 | node.setLeft(remove(node.getLeft(), elem)); 167 | } else { 168 | if(node.getLeft() == null) { 169 | Node rightNode = node.getRight(); 170 | 171 | node.setData(null); 172 | node = null; 173 | 174 | return rightNode; 175 | } else if(node.getRight() == null) { 176 | Node leftNode = node.getLeft(); 177 | 178 | node.setData(null); 179 | node = null; 180 | 181 | return leftNode; 182 | } else { 183 | T tmp = minRight(node); 184 | 185 | node.setData(tmp); 186 | 187 | node.setRight(remove(node.getRight(), tmp)); 188 | } 189 | } 190 | return node; 191 | } 192 | 193 | private T minRight(Node node) { 194 | while (node.getLeft() != null) node = node.getLeft(); 195 | return (T) node.getData(); 196 | } 197 | 198 | private T maxLeft(Node node) { 199 | while (node.getRight() != null) node = node.getRight(); 200 | return (T) node.getData(); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/com/ongdev/tree/BinarySearchTreeTest.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.tree; 2 | 3 | import java.util.Iterator; 4 | 5 | public class BinarySearchTreeTest { 6 | public static void main(String[] args) { 7 | TreeADT bst = new BinarySearchTree<>(); 8 | 9 | bst.add(5); 10 | bst.add(4); 11 | bst.add(6); 12 | bst.add(7); 13 | bst.add(3); 14 | bst.add(2); 15 | bst.add(10); 16 | 17 | Iterator traverse = bst.traverse(TreeTraverseType.IN_ORDER); 18 | 19 | while (traverse.hasNext()) { 20 | System.out.println(traverse.next()); 21 | } 22 | 23 | System.out.println(bst.height()); 24 | System.out.println(bst.contains(10)); 25 | System.out.println(bst.contains(9)); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/com/ongdev/tree/Node.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.tree; 2 | 3 | class Node> { 4 | private T data; 5 | 6 | public T getData() { 7 | return data; 8 | } 9 | 10 | public void setData(T data) { 11 | this.data = data; 12 | } 13 | 14 | public com.ongdev.tree.Node getLeft() { 15 | return left; 16 | } 17 | 18 | public void setLeft(com.ongdev.tree.Node left) { 19 | this.left = left; 20 | } 21 | 22 | public com.ongdev.tree.Node getRight() { 23 | return right; 24 | } 25 | 26 | public void setRight(com.ongdev.tree.Node right) { 27 | this.right = right; 28 | } 29 | 30 | private com.ongdev.tree.Node left, right; 31 | 32 | public Node(T data, com.ongdev.tree.Node left, com.ongdev.tree.Node right) { 33 | this.data = data; 34 | this.left = left; 35 | this.right = right; 36 | } 37 | 38 | @Override 39 | public String toString() { 40 | return data.toString(); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/com/ongdev/tree/TreeADT.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.tree; 2 | 3 | import java.util.Iterator; 4 | 5 | public interface TreeADT> { 6 | boolean isEmpty(); 7 | int size(); 8 | int height(); 9 | boolean contains(T elem); 10 | boolean add(T elem); 11 | boolean remove(T elem); 12 | Iterator traverse(TreeTraverseType type); 13 | } 14 | -------------------------------------------------------------------------------- /src/com/ongdev/tree/TreeTraverseType.java: -------------------------------------------------------------------------------- 1 | package com.ongdev.tree; 2 | 3 | public enum TreeTraverseType { 4 | PRE_ORDER, 5 | IN_ORDER, 6 | POST_ORDER, 7 | LEVEL_ORDER 8 | } 9 | --------------------------------------------------------------------------------