diff --git a/hw_03/pom.xml b/hw_03/pom.xml new file mode 100644 index 0000000..307b47f --- /dev/null +++ b/hw_03/pom.xml @@ -0,0 +1,27 @@ + + 4.0.0 + + 1 + hw_01 + 0.0.1-SNAPSHOT + jar + + hw_01 + http://maven.apache.org + + + UTF-8 + 1.8 + 1.8 + + + + + junit + junit + 3.8.1 + test + + + diff --git a/hw_03/src/main/java/hw_01/Bor.java b/hw_03/src/main/java/hw_01/Bor.java new file mode 100644 index 0000000..d5a4a3a --- /dev/null +++ b/hw_03/src/main/java/hw_01/Bor.java @@ -0,0 +1,145 @@ +package hw_01; + +import java.io.*; + +public class Bor implements Trie, StreamSerializable { + final private Node bor; + + public Bor() { + bor = new Node(); + } + + public boolean add(String element) { + if (contains(element)) { + return false; + } + + Node p = bor; + + p.nwords++; + for (int i = 0; i < element.length(); i++) { + int currIdx = arrayIndex(element.charAt(i)); + + if (p.lifes[currIdx] == null) { + p.lifes[currIdx] = new Node(); + } + p = p.lifes[currIdx]; + p.nwords++; + } + + p.isTerminal = true; + return true; + } + + public boolean contains(String element) { + Node p = bor; + for (int i = 0; i < element.length(); i++) { + int currIdx = arrayIndex(element.charAt(i)); + + if (p.lifes[currIdx] == null) { + return false; + } + p = p.lifes[currIdx]; + } + + return p.isTerminal; + } + + public boolean remove(String element) { + if (!contains(element)) { + return false; + } + + Node p = bor; + p.nwords--; + for (int i = 0; i < element.length(); i++) { + int currIdx = arrayIndex(element.charAt(i)); + + if (p.lifes[currIdx].nwords == 1) { + p.lifes[currIdx] = null; + return true; + } + p = p.lifes[currIdx]; + p.nwords--; + } + + p.isTerminal = false; + + return true; + } + + public int size() { + return bor.nwords; + } + + public int howManyStartsWithPrefix(String prefix) { + Node p = bor; + for (int i = 0; i < prefix.length(); i++) { + int currIdx = arrayIndex(prefix.charAt(i)); + + if (p.lifes[currIdx] == null) { + return 0; + } + p = p.lifes[currIdx]; + } + + return p.nwords; + } + + private int arrayIndex(char a) { + if ('a' <= a && a <= 'z') { + return a - 'a'; + } + + if ('A' <= a && a <= 'Z') { + return a - 'A' + 'z' - 'a' + 1; + } + + return -1; + } + + private class Node { + public boolean isTerminal; + public int nwords; + Node[] lifes = new Node[2*('z' - 'a' + 1)]; + } + + private void serializeNode(Node r, DataOutputStream dos) throws IOException { + dos.writeBoolean(r.isTerminal); + dos.writeInt(r.nwords); + + for(int i = 0; i < r.lifes.length; i++) { + if (r.lifes[i] == null) { + dos.writeBoolean(false); + } else { + dos.writeBoolean(true); + serializeNode(r.lifes[i], dos); + } + } + + } + + private void deserializeNode(Node r, DataInputStream dis) throws IOException { + r.isTerminal = dis.readBoolean(); + r.nwords = dis.readInt(); + + for(int i = 0; i < r.lifes.length; i++) { + boolean b = dis.readBoolean(); + if (b) { + r.lifes[i] = new Node(); + deserializeNode(r.lifes[i], dis); + } + } + } + + @Override + public void serialize(OutputStream out) throws IOException { + serializeNode(bor, new DataOutputStream(out)); + out.flush(); + } + + @Override + public void deserialize(InputStream in) throws IOException { + deserializeNode(bor, new DataInputStream(in));; + } +} diff --git a/hw_03/src/main/java/hw_01/StreamSerializable.java b/hw_03/src/main/java/hw_01/StreamSerializable.java new file mode 100644 index 0000000..e9cb9df --- /dev/null +++ b/hw_03/src/main/java/hw_01/StreamSerializable.java @@ -0,0 +1,15 @@ +package hw_01; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +public interface StreamSerializable { + + void serialize(OutputStream out) throws IOException; + + /** + * Replace current state with data from input stream + */ + void deserialize(InputStream in) throws IOException; +} \ No newline at end of file diff --git a/hw_03/src/main/java/hw_01/Trie.java b/hw_03/src/main/java/hw_01/Trie.java new file mode 100644 index 0000000..5c043b4 --- /dev/null +++ b/hw_03/src/main/java/hw_01/Trie.java @@ -0,0 +1,32 @@ +package hw_01; + +public interface Trie { + + /** + * Expected complexity: O(|element|) + * @return true if this set did not already contain the specified + * element + */ + boolean add(String element); + + /** + * Expected complexity: O(|element|) + */ + boolean contains(String element); + + /** + * Expected complexity: O(|element|) + * @return true if this set contained the specified element + */ + boolean remove(String element); + + /** + * Expected complexity: O(1) + */ + int size(); + + /** + * Expected complexity: O(|prefix|) + */ + int howManyStartsWithPrefix(String prefix); +} diff --git a/hw_03/src/test/java/hw_01/TrieImplTest.java b/hw_03/src/test/java/hw_01/TrieImplTest.java new file mode 100644 index 0000000..20fd175 --- /dev/null +++ b/hw_03/src/test/java/hw_01/TrieImplTest.java @@ -0,0 +1,78 @@ +package hw_01; + +import java.io.*; + +import junit.framework.TestCase; + +public class TrieImplTest extends TestCase { + private Bor b; + + public void setUp() { + b = new Bor(); + } + + public void testAddSizeContains() { + assertFalse(b.contains("Hello")); + assertTrue(b.add("Hello")); + assertTrue(b.contains("Hello")); + assertEquals(1, b.size()); + assertEquals(1, b.howManyStartsWithPrefix("Hell")); + } + + public void testAddContainsPrefix() { + b.add("Hello"); + assertFalse(b.contains("Hell")); + assertTrue(b.add("Hell")); + assertTrue(b.contains("Hell")); + assertEquals(2, b.size()); + assertEquals(2, b.howManyStartsWithPrefix("Hell")); + } + + public void testAddOutstandingWord() { + b.add("Hello"); + assertTrue(b.add("Head")); + assertEquals(2, b.size()); + } + + public void testRemovePrefix() { + b.add("Hello"); + b.add("Hell"); + assertFalse(b.remove("He")); + assertTrue(b.remove("Hell")); + assertEquals(1, b.size()); + assertEquals(1, b.howManyStartsWithPrefix("Hell")); + } + + public void testTemoveSuffix() { + b.add("Hello"); + b.add("Hell"); + assertTrue(b.remove("Hello")); + assertEquals(1, b.size()); + } + + public void testSerialDeserial() throws IOException { + b.add("Hello"); + b.add("Head"); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + b.serialize(baos); + byte[] buf1 = baos.toByteArray(); + + Bor b1 = new Bor(); + b1.deserialize(new ByteArrayInputStream(buf1)); + baos = new ByteArrayOutputStream(); + b1.serialize(baos); + byte[] buf2 = baos.toByteArray(); + + assertEquals(buf1.length, buf2.length); + + for(int i = 0; i < buf1.length; i++) { + assertEquals(buf1[i], buf2[i]); + } + + assertTrue(b1.contains("Hello")); + assertTrue(b1.contains("Head")); + assertEquals(2, b1.size()); + } + +}