diff --git a/Trie/.gitignore b/Trie/.gitignore
new file mode 100644
index 0000000..345e61a
--- /dev/null
+++ b/Trie/.gitignore
@@ -0,0 +1,49 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/dictionaries
+
+# Sensitive or high-churn files:
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.xml
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+
+# Gradle:
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# CMake
+cmake-build-debug/
+
+# Mongo Explorer plugin:
+.idea/**/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/Trie/.idea/compiler.xml b/Trie/.idea/compiler.xml
new file mode 100644
index 0000000..3b1aaf8
--- /dev/null
+++ b/Trie/.idea/compiler.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Trie/.idea/misc.xml b/Trie/.idea/misc.xml
new file mode 100644
index 0000000..56c64d0
--- /dev/null
+++ b/Trie/.idea/misc.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Trie/.idea/modules.xml b/Trie/.idea/modules.xml
new file mode 100644
index 0000000..33b02ce
--- /dev/null
+++ b/Trie/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Trie/Trie.iml b/Trie/Trie.iml
new file mode 100644
index 0000000..00b58f0
--- /dev/null
+++ b/Trie/Trie.iml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Trie/pom.xml b/Trie/pom.xml
new file mode 100644
index 0000000..7f0f184
--- /dev/null
+++ b/Trie/pom.xml
@@ -0,0 +1,20 @@
+
+
+ 4.0.0
+
+ ru.spbau.mit.kazakov
+ Trie
+ 1.0-SNAPSHOT
+ jar
+
+
+
+ junit
+ junit
+ 4.0
+
+
+
+
\ No newline at end of file
diff --git a/Trie/src/main/java/ru/spbau/mit/kazakov/Trie/Trie.java b/Trie/src/main/java/ru/spbau/mit/kazakov/Trie/Trie.java
new file mode 100644
index 0000000..4caf359
--- /dev/null
+++ b/Trie/src/main/java/ru/spbau/mit/kazakov/Trie/Trie.java
@@ -0,0 +1,133 @@
+package ru.spbau.mit.kazakov.Trie;
+
+import java.io.*;
+import java.util.Hashtable;
+
+/**
+ * Prefix tree for storing strings.
+ */
+public class Trie implements Serializable {
+ private Node root = new Node();
+
+ /**
+ * Checks if there is specified string in trie.
+ *
+ * @param element a string to check
+ * @return true if there is specified string in trie, and false otherwise
+ */
+ public boolean contains(String element) {
+ Node current = root;
+
+ for (int i = 0; i < element.length(); i++) {
+ if (!current.edges.containsKey(element.charAt(i))) {
+ return false;
+ }
+ current = current.edges.get(element.charAt(i));
+ }
+
+ return current.isTerminal;
+ }
+
+ /**
+ * Adds specified string to trie.
+ *
+ * @param element a string to add
+ * @return true if there was no specified string in trie, and false otherwise
+ */
+ public boolean add(String element) {
+ if (contains(element)) {
+ return false;
+ }
+
+ Node current = root;
+ for (int i = 0; i < element.length(); i++) {
+ current.numOfContinuations++;
+ if (!current.edges.containsKey(element.charAt(i))) {
+ current.edges.put(element.charAt(i), new Node());
+ }
+ current = current.edges.get(element.charAt(i));
+ }
+ current.numOfContinuations++;
+ current.isTerminal = true;
+
+ return true;
+ }
+
+ /**
+ * Counts how many strings in trie starts with specified string.
+ */
+ public int howManyStartsWithPrefix(String prefix) {
+ Node current = root;
+
+ for (int i = 0; i < prefix.length(); i++) {
+ if (!current.edges.containsKey(prefix.charAt(i))) {
+ return 0;
+ }
+ current = current.edges.get(prefix.charAt(i));
+ }
+
+ return current.numOfContinuations;
+ }
+
+ /**
+ * Returns number of added strings in trie.
+ */
+ public int size() {
+ return root.numOfContinuations;
+ }
+
+ /**
+ * Removes specified string from trie.
+ *
+ * @param element a string to remove
+ * @return true if there was specified string in trie, and false otherwise
+ */
+ public boolean remove(String element) {
+ if (!contains(element)) {
+ return false;
+ }
+
+ Node current = root;
+ for (int i = 0; i < element.length(); i++) {
+ current.numOfContinuations--;
+ Node next = current.edges.get(element.charAt(i));
+ if (next.numOfContinuations == 1) {
+ current.edges.remove(element.charAt(i));
+ }
+ current = next;
+ }
+ current.numOfContinuations--;
+ current.isTerminal = false;
+
+ return true;
+ }
+
+ /**
+ * Serializes current trie to given stream.
+ *
+ * @param out stream for writing
+ */
+ public void serialize(OutputStream out) throws IOException {
+ ObjectOutputStream objectOutputStream = new ObjectOutputStream(out);
+ objectOutputStream.writeObject(this);
+ }
+
+ /**
+ * Deserializes trie from given stream and replaces current trie with new one.
+ *
+ * @param in stream for reading
+ */
+ public void deserialize(InputStream in) throws IOException, ClassNotFoundException {
+ ObjectInputStream objectInputStream = new ObjectInputStream(new BufferedInputStream(in));
+ root = ((Trie) objectInputStream.readObject()).root;
+ }
+
+ /**
+ * Vertex in trie. Stores outgoing edges with corresponding characters.
+ */
+ private class Node implements Serializable {
+ private Hashtable edges = new Hashtable();
+ private boolean isTerminal = false;
+ private int numOfContinuations = 0;
+ }
+}
diff --git a/Trie/src/test/java/ru/spbau/mit/kazakov/Trie/TrieTest.java b/Trie/src/test/java/ru/spbau/mit/kazakov/Trie/TrieTest.java
new file mode 100644
index 0000000..973f392
--- /dev/null
+++ b/Trie/src/test/java/ru/spbau/mit/kazakov/Trie/TrieTest.java
@@ -0,0 +1,173 @@
+package ru.spbau.mit.kazakov.Trie;
+
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class TrieTest {
+ @Test
+ public void testConstructor() {
+ Trie trie = new Trie();
+ }
+
+ @Test
+ public void testAddReturnTrue() {
+ Trie trie = new Trie();
+ assertTrue(trie.add("some string"));
+ }
+
+ @Test
+ public void testAddReturnFalse() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ assertFalse(trie.add("some string"));
+ }
+
+ @Test
+ public void testRemoveEmptyTrie() {
+ Trie trie = new Trie();
+ assertFalse(trie.remove("some string"));
+ }
+
+ @Test
+ public void testRemoveNotExisting() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ assertFalse(trie.remove("another string"));
+ }
+
+ @Test
+ public void testRemoveExisting() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ assertTrue(trie.remove("some string"));
+ }
+
+ @Test
+ public void testContainsEmptyTrie() {
+ Trie trie = new Trie();
+ assertFalse(trie.contains("some string"));
+ }
+
+ @Test
+ public void testContainsExisting() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ assertTrue(trie.contains("some string"));
+ }
+
+ @Test
+ public void testContainsNotExisting() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ assertFalse(trie.contains("another string"));
+ }
+
+ @Test
+ public void testContainsRemoved() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ trie.remove("some string");
+ assertFalse(trie.contains("some string"));
+ }
+
+ @Test
+ public void testHowManyStartsWithPrefixEmptyTrie() {
+ Trie trie = new Trie();
+ assertEquals(0, trie.howManyStartsWithPrefix(""));
+ }
+
+ @Test
+ public void testHowManyStartsWithPrefixEmptyString() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ trie.add("another string");
+ assertEquals(2, trie.howManyStartsWithPrefix(""));
+ }
+
+ @Test
+ public void testHowManyStartsWithPrefixAddedString() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ trie.add("another string");
+ assertEquals(1, trie.howManyStartsWithPrefix("some string"));
+ }
+
+ @Test
+ public void testHowManyStartsWithPrefixTwoStrings() {
+ Trie trie = new Trie();
+ trie.add("super string");
+ trie.add("super mega string");
+ assertEquals(2, trie.howManyStartsWithPrefix("super "));
+ }
+
+ @Test
+ public void testHowManyStartsWithPrefixRemovedString() {
+ Trie trie = new Trie();
+ trie.add("some string");
+ trie.remove("some string");
+ assertEquals(0, trie.howManyStartsWithPrefix("some"));
+ }
+
+ @Test
+ public void testSizeEmptyTrie() {
+ Trie trie = new Trie();
+ assertEquals(0, trie.size());
+ }
+
+ @Test
+ public void testSizeThree() {
+ Trie trie = new Trie();
+ trie.add("first string");
+ trie.add("second string");
+ trie.add("third string");
+ assertEquals(3, trie.size());
+ }
+
+ @Test
+ public void testSizeRemove() {
+ Trie trie = new Trie();
+ trie.add("first string");
+ trie.add("second string");
+ trie.add("third string");
+ trie.remove("first string");
+ assertEquals(2, trie.size());
+ }
+
+ @Test
+ public void testSerializeDeserializeEmpty() throws IOException, ClassNotFoundException {
+ Trie trie = new Trie();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ trie.serialize(os);
+ byte[] serialized = os.toByteArray();
+
+ ByteArrayInputStream is = new ByteArrayInputStream(serialized);
+ Trie newTrie = new Trie();
+ newTrie.add("some string");
+ newTrie.deserialize(is);
+
+ assertFalse(newTrie.contains("some string"));
+ assertEquals(0, newTrie.size());
+ }
+
+ @Test
+ public void testSerializeDeserializeNotEmpty() throws IOException, ClassNotFoundException {
+ Trie trie = new Trie();
+ trie.add("some string");
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ trie.serialize(os);
+ byte[] serialized = os.toByteArray();
+
+ Trie newTrie = new Trie();
+ newTrie.add("another string");
+ ByteArrayInputStream is = new ByteArrayInputStream(serialized);
+ newTrie.deserialize(is);
+
+ assertTrue(newTrie.contains("some string"));
+ assertFalse(newTrie.contains("another string"));
+ }
+}
\ No newline at end of file