diff --git a/HW1/HW1.sln b/HW1/HW1.sln
new file mode 100644
index 0000000..291d9f0
--- /dev/null
+++ b/HW1/HW1.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trie", "Trie\Trie.csproj", "{A87E7018-FB5B-47AB-8323-213DC3A49658}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trie.Test", "Trie.Test\Trie.Test.csproj", "{A2F4F365-7EDC-4ECD-9B8F-6D184B1F9CA3}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A87E7018-FB5B-47AB-8323-213DC3A49658}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A87E7018-FB5B-47AB-8323-213DC3A49658}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A87E7018-FB5B-47AB-8323-213DC3A49658}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A87E7018-FB5B-47AB-8323-213DC3A49658}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2F4F365-7EDC-4ECD-9B8F-6D184B1F9CA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2F4F365-7EDC-4ECD-9B8F-6D184B1F9CA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2F4F365-7EDC-4ECD-9B8F-6D184B1F9CA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2F4F365-7EDC-4ECD-9B8F-6D184B1F9CA3}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+EndGlobal
diff --git a/HW1/Trie.Test/Trie.Test.csproj b/HW1/Trie.Test/Trie.Test.csproj
new file mode 100644
index 0000000..7cefcd9
--- /dev/null
+++ b/HW1/Trie.Test/Trie.Test.csproj
@@ -0,0 +1,40 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+ false
+ true
+ Trie.Tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/HW1/Trie.Test/TrieTest.cs b/HW1/Trie.Test/TrieTest.cs
new file mode 100644
index 0000000..8906613
--- /dev/null
+++ b/HW1/Trie.Test/TrieTest.cs
@@ -0,0 +1,172 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace Trie.Tests;
+
+///
+/// Unit tests for Trie data structure.
+///
+public class TrieTest
+{
+ private Trie trie;
+
+ ///
+ /// Initializes a new trie before each test.
+ ///
+ [SetUp]
+ public void Setup()
+ => this.trie = new();
+
+ ///
+ /// Tests Add method when inserting fresh words.
+ ///
+ [Test]
+ public void Trie_Add_NewWords_ShouldReturnTrue()
+ {
+ List words = ["apple", "app", "application"];
+
+ foreach (var word in words)
+ {
+ Assert.That(this.trie.Add(word), Is.True);
+ }
+ }
+
+ ///
+ /// Tests WordCount after adding multiple words.
+ ///
+ [Test]
+ public void Trie_WordCount_AfterAddingSeveralWords()
+ {
+ List words = ["alpha", "beta", "gamma", "delta"];
+
+ foreach (var word in words)
+ {
+ this.trie.Add(word);
+ }
+
+ Assert.That(this.trie.WordCount, Is.EqualTo(words.Count));
+ }
+
+ ///
+ /// Tests Add method when the same word is inserted twice.
+ ///
+ [Test]
+ public void Trie_Add_SameWordTwice_ShouldReturnFalse()
+ {
+ const string word = "matrix";
+
+ this.trie.Add(word);
+
+ Assert.That(this.trie.Add(word), Is.False);
+ }
+
+ ///
+ /// Tests Add method after removing a word.
+ ///
+ [Test]
+ public void Trie_Add_AfterRemovingWord_ShouldReturnTrue()
+ {
+ const string word = "sun";
+
+ this.trie.Add(word);
+ this.trie.Remove(word);
+
+ Assert.That(this.trie.Add(word), Is.True);
+ }
+
+ ///
+ /// Tests WordCount after removing words.
+ ///
+ [Test]
+ public void Trie_WordCount_AfterRemovingSomeWords()
+ {
+ List words = ["dog", "cat", "bird", "fish"];
+
+ foreach (var word in words)
+ {
+ this.trie.Add(word);
+ }
+
+ this.trie.Remove("dog");
+ this.trie.Remove("bird");
+
+ var expectedCount = words.Count - 2;
+
+ Assert.That(this.trie.WordCount, Is.EqualTo(expectedCount));
+ }
+
+ ///
+ /// Tests WordCount of an empty trie.
+ ///
+ [Test]
+ public void Trie_WordCount_OfEmptyTrie_ShouldBeZero()
+ {
+ const int expected = 0;
+
+ Assert.That(this.trie.WordCount, Is.EqualTo(expected));
+ }
+
+ ///
+ /// Tests Contains method after adding a word.
+ ///
+ [Test]
+ public void Trie_Contains_AfterAddingWord_ShouldReturnTrue()
+ {
+ const string word = "cloud";
+
+ this.trie.Add(word);
+
+ Assert.That(this.trie.Contains(word), Is.True);
+ }
+
+ ///
+ /// Tests Contains method with a word that was never added.
+ ///
+ [Test]
+ public void Trie_Contains_NonExistingWord_ShouldReturnFalse()
+ {
+ const string word = "universe";
+
+ Assert.That(this.trie.Contains(word), Is.False);
+ }
+
+ ///
+ /// Tests Contains method after removing a word.
+ ///
+ [Test]
+ public void Trie_Contains_AfterRemovingWord_ShouldReturnFalse()
+ {
+ const string word = "planet";
+
+ this.trie.Add(word);
+ this.trie.Remove(word);
+
+ Assert.That(this.trie.Contains(word), Is.False);
+ }
+
+ ///
+ /// Tests Remove method with a word that exists.
+ ///
+ [Test]
+ public void Trie_Remove_ExistingWord_ShouldRemoveSuccessfully()
+ {
+ const string word = "river";
+
+ this.trie.Add(word);
+ this.trie.Remove(word);
+
+ Assert.That(this.trie.Contains(word), Is.False);
+ }
+
+ ///
+ /// Tests Remove method with a word that does not exist.
+ ///
+ [Test]
+ public void Trie_Remove_NonExistingWord_ShouldReturnFalse()
+ {
+ const string word = "mountain";
+
+ Assert.That(this.trie.Remove(word), Is.False);
+ }
+}
\ No newline at end of file
diff --git a/HW1/Trie.Test/stylecop.json b/HW1/Trie.Test/stylecop.json
new file mode 100644
index 0000000..76c8e76
--- /dev/null
+++ b/HW1/Trie.Test/stylecop.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "khusainovilas",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved."
+ }
+ }
+}
\ No newline at end of file
diff --git a/HW1/Trie/Trie.cs b/HW1/Trie/Trie.cs
new file mode 100644
index 0000000..3071921
--- /dev/null
+++ b/HW1/Trie/Trie.cs
@@ -0,0 +1,161 @@
+//
+// Copyright (c) khusainovilas. All rights reserved.
+//
+
+namespace Trie;
+
+///
+/// realization of Trie.
+///
+public class Trie
+{
+ private readonly TrieNode root = new();
+
+ ///
+ /// Gets the number of words added to the tree.
+ ///
+ public int WordCount { get; private set; }
+
+ ///
+ /// Add a new word into the trie.
+ ///
+ /// The word to be inserted.
+ /// Returns false if the word is already present.
+ public bool Add(string? word)
+ {
+ if (word is null)
+ {
+ return false;
+ }
+
+ var current = this.root;
+
+ foreach (var letter in word)
+ {
+ if (!current.Children.TryGetValue(letter, out var value))
+ {
+ value = new TrieNode();
+ current.Children[letter] = value;
+ }
+
+ current = value;
+ current.PrefixCount++;
+ }
+
+ if (current.IsEnd)
+ {
+ return false;
+ }
+
+ current.IsEnd = true;
+ this.WordCount++;
+ return true;
+ }
+
+ ///
+ /// Determines whether the trie contains a specific word.
+ ///
+ /// The word to look for.
+ /// Returns true if the word exists in the trie.
+ public bool Contains(string? word)
+ {
+ if (word is null)
+ {
+ return false;
+ }
+
+ var current = this.root;
+
+ foreach (var letter in word)
+ {
+ if (!current.Children.TryGetValue(letter, out var value))
+ {
+ return false;
+ }
+
+ current = value;
+ }
+
+ return current.IsEnd;
+ }
+
+ ///
+ /// Deletes a word from the trie.
+ ///
+ /// The word to delete.
+ /// Returns true if the word was present in the trie.
+ public bool Remove(string? word)
+ {
+ if (word is null)
+ {
+ return false;
+ }
+
+ var current = this.root;
+ var path = new Stack();
+
+ foreach (var letter in word)
+ {
+ if (!current.Children.TryGetValue(letter, out var value))
+ {
+ return false;
+ }
+
+ path.Push(current);
+ current = value;
+ }
+
+ if (!current.IsEnd)
+ {
+ return false;
+ }
+
+ current.IsEnd = false;
+ this.WordCount--;
+
+ foreach (var trieNode in path)
+ {
+ trieNode.PrefixCount--;
+ }
+
+ current.PrefixCount--;
+
+ return true;
+ }
+
+ ///
+ /// Returns the number of words in the trie that start with a given prefix.
+ ///
+ /// The prefix to search for.
+ /// The count of words that begin with the specified prefix.
+ public int HowManyStartsWithPrefix(string? prefix)
+ {
+ if (prefix is null)
+ {
+ return this.WordCount;
+ }
+
+ var current = this.root;
+
+ foreach (var letter in prefix)
+ {
+ if (!current.Children.TryGetValue(letter, out var value))
+ {
+ return 0;
+ }
+
+ current = value;
+ }
+
+ return current.PrefixCount;
+ }
+
+ private class TrieNode
+ {
+ public Dictionary Children { get; } = new();
+
+ public bool IsEnd { get; set; }
+
+ public int PrefixCount { get; set; }
+ }
+}
diff --git a/HW1/Trie/Trie.csproj b/HW1/Trie/Trie.csproj
new file mode 100644
index 0000000..b158c23
--- /dev/null
+++ b/HW1/Trie/Trie.csproj
@@ -0,0 +1,21 @@
+
+
+
+ Library
+ net9.0
+ enable
+ enable
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
diff --git a/HW1/Trie/stylecop.json b/HW1/Trie/stylecop.json
new file mode 100644
index 0000000..76c8e76
--- /dev/null
+++ b/HW1/Trie/stylecop.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "khusainovilas",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved."
+ }
+ }
+}
\ No newline at end of file