diff --git a/hw_02/pom.xml b/hw_02/pom.xml new file mode 100644 index 0000000..9a1e742 --- /dev/null +++ b/hw_02/pom.xml @@ -0,0 +1,27 @@ + + 4.0.0 + + 2 + hw_02 + 0.0.1-SNAPSHOT + jar + + hw_02 + http://maven.apache.org + + + UTF-8 + 1.8 + 1.8 + + + + + junit + junit + 3.8.1 + test + + + diff --git a/hw_02/src/main/java/hw_02/DictImpl.java b/hw_02/src/main/java/hw_02/DictImpl.java new file mode 100644 index 0000000..98346f5 --- /dev/null +++ b/hw_02/src/main/java/hw_02/DictImpl.java @@ -0,0 +1,127 @@ +package hw_02; + +public class DictImpl implements Dictionary { + private Node[] arr; + int arrSize; + double maxLoadFactor = 0.75; + private double minLoadFactor = 0.2; + private final int minSize = 4; + private int size = 0; + + public void clear() { + size = 0; + arrSize = minSize; + resetArray(); + } + + private void resetArray() { + arr = new Node[arrSize]; + for (int i = 0; i < arrSize; i++) { + arr[i] = new Node(); + } + } + + public DictImpl() { + clear(); + } + + public DictImpl(double maxLoadFactor) { + this(); + this.minLoadFactor = maxLoadFactor / 3; + this.maxLoadFactor = maxLoadFactor; + } + + public int size() { + return size; + } + + public boolean contains(String key) { + return lookup(key).next != null; + } + + public String get(String key) { + Node p = lookup(key).next; + if (p == null) { + return null; + } + return p.value; + } + + public String put(String key, String value) { + Node p = lookup(key); + String oldValue = null; + if (p.next != null) { + oldValue = p.next.value; + p.next.value = value; + } else { + p.next = new Node(key, value); + size++; + } + rehashIfNeeded(); + return oldValue; + } + + public String remove(String key) { + Node p = lookup(key); + String oldValue = null; + if (p.next != null) { + oldValue = p.next.value; + p.next = p.next.next; + size--; + } + rehashIfNeeded(); + return oldValue; + } + + private Node lookup(String s) { + Node p = arr[arrIdx(s)]; + + while (p.next != null && !p.next.key.equals(s)) { + p = p.next; + } + + return p; + } + + private int arrIdx(String s) { + return s.hashCode() % arrSize; + } + + private void rehashIfNeeded() { + if (size > arrSize * maxLoadFactor) { + arrSize *= 2; + } else if (size < arrSize * minLoadFactor) { + if (arrSize >= 2 * minSize) { + arrSize /= 2; + } + } else { + return; + } + + Node[] oldArr = arr; + + resetArray(); + + for (int i = 0; i < oldArr.length; i++) { + Node p = oldArr[i].next; + while (p != null) { + Node q = p; + p = p.next; + + int currIdx = arrIdx(q.key); + q.next = arr[currIdx].next; + arr[currIdx].next = q; + } + } + } + + private class Node { + public Node(String key2, String value2) { + key = key2; + value = value2; + } + public Node() {} + String key, value; + Node next; + } +} diff --git a/hw_02/src/main/java/hw_02/Dictionary.java b/hw_02/src/main/java/hw_02/Dictionary.java new file mode 100644 index 0000000..60b00b7 --- /dev/null +++ b/hw_02/src/main/java/hw_02/Dictionary.java @@ -0,0 +1,31 @@ +package hw_02; + +public interface Dictionary { + + // хеш-таблица, использующая список + // ключами и значениями выступают строки + // стандартный способ получить хеш объекта -- вызвать у него метод hashCode() + + // кол-во ключей в таблице + int size(); + + // true, если такой ключ содержится в таблице + boolean contains(String key); + + // возвращает значение, хранимое по ключу key + // если такого нет, возвращает null + String get(String key); + + // положить по ключу key значение value + // и вернуть ранее хранимое, либо null; + // провести рехеширование по необходимости + String put(String key, String value); + + // забыть про пару key-value для переданного key + // и вернуть забытое value, либо null, если такой пары не было; + // провести рехеширование по необходимости + String remove(String key); + + // забыть про все пары key-value + void clear(); +} diff --git a/hw_02/src/test/java/hw_02/DictTest.java b/hw_02/src/test/java/hw_02/DictTest.java new file mode 100644 index 0000000..296c150 --- /dev/null +++ b/hw_02/src/test/java/hw_02/DictTest.java @@ -0,0 +1,78 @@ +package hw_02; + +import junit.framework.TestCase; + +public class DictTest extends TestCase { + + private DictImpl d; + + public void setUp() { + d = new DictImpl(); + } + + public void testPutContains() { + assertEquals(0, d.size()); + assertFalse(d.contains("a")); + assertEquals(null, d.put("a", "a1")); + assertEquals("a1", d.put("a", "a2")); + assertEquals(1, d.size()); + } + + public void testGet() { + assertEquals(null, d.get("a")); + d.put("a", "a1"); + d.put("b", "b1"); + assertEquals("a1", d.get("a")); + assertEquals("b1", d.get("b")); + assertEquals(2, d.size()); + } + + public void testRemove() { + assertEquals(null, d.remove("a")); + assertEquals(0, d.size()); + d.put("a", "a1"); + d.put("b", "b1"); + assertEquals("a1", d.remove("a")); + assertEquals(1, d.size()); + assertEquals("b1", d.remove("b")); + assertEquals(0, d.size()); + } + + public void testRehash() { + d.put("a", "a1"); + d.put("b", "b1"); + d.put("c", "c1"); + d.put("d", "d1"); + //после 4 элементов должен произойти rehash + assertEquals(4, d.size()); + assertEquals(8, d.arrSize); + assertEquals("a1", d.get("a")); + assertEquals("b1", d.get("b")); + assertEquals("c1", d.get("c")); + assertEquals("d1", d.get("d")); + } + + public void testList() { + d.arrSize = 1; + d.maxLoadFactor = 100; + + d.put("a", "a1"); + d.put("b", "b1"); + d.put("c", "c1"); + + assertEquals("a1", d.remove("a")); + assertEquals("b1", d.get("b")); + assertEquals("c1", d.remove("c")); + + assertEquals(1, d.size()); + } + + public void testClear() { + d.put("a", "a1"); + + d.clear(); + + assertEquals(0, d.size()); + assertEquals(null, d.get("a")); + } +}