diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 0000000..e7e7cb3
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,6 @@
+image: Visual Studio 2019
+
+build_script:
+ - For /R %%I in (*.sln) do dotnet test %%I
+
+test: off
\ No newline at end of file
diff --git a/hw3B-tree/hw3B-tree.Test/TestB-tree.cs b/hw3B-tree/hw3B-tree.Test/TestB-tree.cs
new file mode 100644
index 0000000..9a0acf6
--- /dev/null
+++ b/hw3B-tree/hw3B-tree.Test/TestB-tree.cs
@@ -0,0 +1,187 @@
+using NUnit.Framework;
+
+namespace Hw3B_tree.Test
+{
+ public class Tests
+ {
+ private BTree tree;
+
+ public BTree Setup(int minimumDegreeOfTree)
+ {
+ tree = new BTree(minimumDegreeOfTree);
+ for (int i = 1; i < 19; ++i)
+ {
+ tree.Insert(i.ToString(), i.ToString());
+ }
+ return tree;
+ }
+
+ [TestCase]
+ public void CheckInsert()
+ {
+ var tree = Setup(2);
+ for (int i = 1; i <= 18; ++i)
+ {
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckGetValue()
+ {
+ var tree = Setup(2);
+ for (int i = 1; i <= 18; ++i)
+ {
+ Assert.AreEqual(i.ToString(), tree.GetValue(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckChangeValueByKey()
+ {
+ var tree = Setup(2);
+ tree.ChangeValueByKey("5", "ololo");
+ Assert.AreEqual("ololo", tree.GetValue("5"));
+ }
+
+ [TestCase]
+ public void CheckDeleteFromRoot()
+ {
+ var tree = Setup(2);
+ tree.Delete("8");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 8)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckDeleteFromLeaf()
+ {
+ var tree = Setup(2);
+ tree.Delete("5");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 5)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckDeleteFromNotLeafWithChangeRoot()
+ {
+ var tree = Setup(2);
+ tree.Delete("6");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 6)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckDeleteFromLeafWithChangeValueInLeafs()
+ {
+ var tree = Setup(2);
+ tree.Delete("15");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 15)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckInsertWithAnotherDegree()
+ {
+ var tree = Setup(4);
+ for (int i = 1; i <= 18; ++i)
+ {
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckGetValueWithAnotherDegree()
+ {
+ var tree = Setup(4);
+ for (int i = 1; i <= 18; ++i)
+ {
+ Assert.AreEqual(i.ToString(), tree.GetValue(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckChangeValueByKeyWithAnotherDegree()
+ {
+ var tree = Setup(4);
+ tree.ChangeValueByKey("5", "ololo");
+ Assert.AreEqual("ololo", tree.GetValue("5"));
+ }
+
+ [TestCase]
+ public void CheckDeleteFromRootWithAnotherDegree()
+ {
+ var tree = Setup(4);
+ tree.Delete("8");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 8)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckDeleteFromLeafWithMergeLefsWithAnotherDegree()
+ {
+ var tree = Setup(4);
+ tree.Delete("2");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 2)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+
+ [TestCase]
+ public void CheckDeleteFromLeafWithChangeValueInLeafsWithAnotherDegree()
+ {
+ var tree = Setup(4);
+ tree.Delete("10");
+ for (int i = 1; i <= 18; ++i)
+ {
+ if (i == 10)
+ {
+ Assert.IsFalse(tree.Exists(i.ToString()));
+ continue;
+ }
+ Assert.IsTrue(tree.Exists(i.ToString()));
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hw3B-tree/hw3B-tree.Test/hw3B-tree.Test.csproj b/hw3B-tree/hw3B-tree.Test/hw3B-tree.Test.csproj
new file mode 100644
index 0000000..953b990
--- /dev/null
+++ b/hw3B-tree/hw3B-tree.Test/hw3B-tree.Test.csproj
@@ -0,0 +1,20 @@
+
+
+
+ netcoreapp3.1
+ hw3B_tree.Test
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hw3B-tree/hw3B-tree.sln b/hw3B-tree/hw3B-tree.sln
new file mode 100644
index 0000000..6ea80e4
--- /dev/null
+++ b/hw3B-tree/hw3B-tree.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31005.135
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hw3B-tree", "hw3B-tree\Hw3B-tree.csproj", "{53642C16-3AA3-4A57-8380-46B9C2E9651E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hw3B-tree.Test", "hw3B-tree.Test\hw3B-tree.Test.csproj", "{A2EE96D2-650B-457E-87E5-A6410F6DF06D}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {53642C16-3AA3-4A57-8380-46B9C2E9651E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {53642C16-3AA3-4A57-8380-46B9C2E9651E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {53642C16-3AA3-4A57-8380-46B9C2E9651E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {53642C16-3AA3-4A57-8380-46B9C2E9651E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2EE96D2-650B-457E-87E5-A6410F6DF06D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2EE96D2-650B-457E-87E5-A6410F6DF06D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2EE96D2-650B-457E-87E5-A6410F6DF06D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2EE96D2-650B-457E-87E5-A6410F6DF06D}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {A28793F3-951B-4D93-BC1D-F351834FA2F5}
+ EndGlobalSection
+EndGlobal
diff --git a/hw3B-tree/hw3B-tree/BTree.cs b/hw3B-tree/hw3B-tree/BTree.cs
new file mode 100644
index 0000000..b29e31b
--- /dev/null
+++ b/hw3B-tree/hw3B-tree/BTree.cs
@@ -0,0 +1,465 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Hw3B_tree
+{
+ ///
+ /// btree class
+ ///
+ public class BTree
+ {
+ public int MinimumDegreeOfTree { get; }
+
+ private class Node
+ {
+
+ public int CountKeys { get; set; }
+ public (string key, string value)[] Keys { get; set; }
+
+ public Node[] Sons { get; set; }
+
+ public bool Leaf { get; set; }
+
+ public Node(int minimumDegreeOfTree, bool leaf)
+ {
+ CountKeys = 0;
+ Leaf = leaf;
+ Keys = new (string key, string value)[2 * minimumDegreeOfTree - 1];
+ Sons = new Node[2 * minimumDegreeOfTree];
+ }
+ }
+
+ private Node root;
+
+ public BTree(int minimumDegreeOfTree)
+ {
+ if (minimumDegreeOfTree < 2)
+ {
+ throw new ArgumentException("Минимальная степень дерева выбрана неправильно!");
+ }
+ MinimumDegreeOfTree = minimumDegreeOfTree;
+ }
+
+ private Node FindNode(string key)
+ {
+ var node = root;
+ while (!node.Leaf)
+ {
+ for (int i = 0; i < node.CountKeys; ++i)
+ {
+ if (key == node.Keys[i].key)
+ {
+ return node;
+ }
+ if (CompareKey(key, node.Keys[i].key))
+ {
+ node = node.Sons[i];
+ break;
+ }
+ if (i == node.CountKeys - 1)
+ {
+ node = node.Sons[i + 1];
+ break;
+ }
+ }
+ }
+ for (int i = 0; i < node.CountKeys; ++i)
+ {
+ if (key == node.Keys[i].key)
+ {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// checking for the presence of a key in a tree
+ ///
+ /// true - if key is in tree, false - if key isn't in tree
+ public bool Exists(string key)
+ {
+ var node = FindNode(key);
+ if (node == null)
+ {
+ return false;
+ }
+ for (int i = 0; i < node.CountKeys; ++i)
+ {
+ if (key == node.Keys[i].key)
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ ///
+ /// get value by key
+ ///
+ /// return value, if we find key and return null, if we don't find key
+ public string GetValue(string key)
+ {
+ var node = FindNode(key);
+ if (node == null)
+ {
+ return null;
+ }
+ for (int i = 0; i < node.CountKeys; ++i)
+ {
+ if (key == node.Keys[i].key)
+ {
+ return node.Keys[i].value;
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// chenge value in tree by key
+ ///
+ /// return true,if we change value, and false, if we don't change
+ public bool ChangeValueByKey(string key, string value)
+ {
+ var node = FindNode(key);
+ if (node == null)
+ {
+ return false;
+ }
+ for (int i = 0; i < node.CountKeys; ++i)
+ {
+ if (key == node.Keys[i].key)
+ {
+ node.Keys[i].value = value;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public bool CompareKey(string key, string keyInNode)
+ {
+ if (key.Length < keyInNode.Length)
+ {
+ return true;
+ }
+ else if (key.Length > keyInNode.Length)
+ {
+ return false;
+ }
+ return String.Compare(key, keyInNode) < 0;
+ }
+
+ ///
+ /// function of insert (key,value) in tree
+ ///
+ public void Insert(string key, string value)
+ {
+ var runner = root;
+ if (root == null)
+ {
+ root = new Node(MinimumDegreeOfTree, true);
+ root.Keys[0].key = key;
+ root.Keys[0].value = value;
+ root.CountKeys++;
+ }
+ else if (root.CountKeys == (2 * MinimumDegreeOfTree) - 1)
+ {
+ var newRoot = new Node(MinimumDegreeOfTree, false);
+ newRoot.Sons[newRoot.CountKeys] = root;
+ root = newRoot;
+ Split(0, root);
+ InsertInNode(key, value, root);
+ }
+ else
+ {
+ InsertInNode(key, value, runner);
+ }
+ }
+
+ private void Split(int index, Node node)
+ {
+ var helpNode = node.Sons[index];
+ var newNode = new Node(MinimumDegreeOfTree, helpNode.Leaf);
+ newNode.CountKeys = MinimumDegreeOfTree - 1;
+ Array.Copy(helpNode.Keys, MinimumDegreeOfTree, newNode.Keys, 0, MinimumDegreeOfTree - 1);
+ if (!node.Leaf)
+ {
+ Array.Copy(helpNode.Sons, MinimumDegreeOfTree, newNode.Sons, 0, MinimumDegreeOfTree);
+ }
+ helpNode.CountKeys = MinimumDegreeOfTree - 1;
+ for (int i = node.CountKeys; i >= index + 1; i--)
+ {
+ node.Sons[i + 1] = node.Sons[i];
+ }
+ node.Sons[index + 1] = newNode;
+ for (int i = node.CountKeys - 1; i >= index; i--)
+ {
+ node.Keys[i + 1].key = node.Keys[i].key;
+ node.Keys[i + 1].value = node.Keys[i].value;
+ }
+ node.Keys[index].key = helpNode.Keys[MinimumDegreeOfTree - 1].key;
+ node.Keys[index].value = helpNode.Keys[MinimumDegreeOfTree - 1].value;
+ node.CountKeys++;
+ }
+
+ private void InsertInNode(string key, string value, Node node)
+ {
+ int index = node.CountKeys - 1;
+ if (node.Leaf)
+ {
+ while (index >= 0 && CompareKey(key, node.Keys[index].key))
+ {
+ node.Keys[index + 1].key = node.Keys[index].key;
+ node.Keys[index + 1].value = node.Keys[index].value;
+ index--;
+ }
+ node.Keys[index + 1].key = key;
+ node.Keys[index + 1].value = value;
+ node.CountKeys++;
+ }
+ else
+ {
+ while (index >= 0 && CompareKey(key, node.Keys[index].key))
+ {
+ index--;
+ }
+ index++;
+ if (node.Sons[index].CountKeys == (2 * MinimumDegreeOfTree - 1))
+ {
+ Split(index, node);
+ if (!CompareKey(key, node.Keys[index].key))
+ {
+ index++;
+ }
+ }
+ InsertInNode(key, value, node.Sons[index]);
+ }
+ }
+
+ ///
+ /// finction delete (key, value) from tree
+ ///
+ public void Delete(string key)
+ {
+ var runner = root;
+ if (root == null)
+ {
+ return;
+ }
+ Remove(key, ref runner);
+ if (root.CountKeys == 0)
+ {
+ root = root.Leaf ? null : root.Sons[0];
+ }
+ }
+
+ private int FindKeyIndex(string key, Node node)
+ {
+ var index = 0;
+ while (index < node.CountKeys && CompareKey(node.Keys[index].key, key))
+ {
+ index++;
+ }
+ return index;
+ }
+
+ private void Remove(string key, ref Node cursor)
+ {
+ var index = FindKeyIndex(key, cursor);
+ if (index < cursor.CountKeys && cursor.Keys[index].key == key)
+ {
+ if (cursor.Leaf)
+ {
+ DeleteFromLeaf(index, cursor);
+ }
+ else
+ {
+ DeleteFromNotLeaf(index, cursor);
+ }
+ }
+ else
+ {
+ if (cursor.Leaf)
+ {
+ return;
+ }
+ bool check = index == cursor.CountKeys;
+ var helpNode = cursor.Sons[index];
+ if (helpNode.CountKeys < MinimumDegreeOfTree)
+ {
+ Fill(index, ref cursor);
+ }
+ if (check && index < cursor.CountKeys)
+ {
+ cursor = cursor.Sons[index - 1];
+ Remove(key, ref cursor);
+ }
+ else
+ {
+ cursor = cursor.Sons[index];
+ Remove(key, ref cursor);
+ }
+ }
+ }
+
+ private void DeleteFromLeaf(int index, Node node)
+ {
+ for (int i = index + 1; i < node.CountKeys; ++i)
+ {
+ node.Keys[i - 1] = node.Keys[i];
+ }
+ node.CountKeys--;
+ }
+
+ private void DeleteFromNotLeaf(int index, Node node)
+ {
+ string key = node.Keys[index].key;
+ var cursor = node;
+ if (node.Sons[index].CountKeys >= MinimumDegreeOfTree)
+ {
+ (string previousKey, string value) = GetPrev(index, cursor);
+ node.Keys[index].key = previousKey;
+ node.Keys[index].value = value;
+ cursor = cursor.Sons[index];
+ Remove(previousKey, ref cursor);
+ }
+ else if (node.Sons[index + 1].CountKeys >= MinimumDegreeOfTree)
+ {
+ (string succKey, string value) = GetSucc(index, cursor);
+ node.Keys[index].key = succKey;
+ node.Keys[index].value = value;
+ cursor = node.Sons[index + 1];
+ Remove(succKey, ref cursor);
+ }
+ else
+ {
+ Merge(index, ref cursor);
+ cursor = node.Sons[index];
+ Remove(key, ref cursor);
+ }
+ }
+
+ private (string, string) GetPrev(int index, Node node)
+ {
+ var helpNode = node.Sons[index];
+ while (!helpNode.Leaf)
+ {
+ helpNode = helpNode.Sons[helpNode.CountKeys];
+ }
+ return (helpNode.Keys[helpNode.CountKeys - 1].key, helpNode.Keys[helpNode.CountKeys - 1].value);
+ }
+
+ private (string, string) GetSucc(int index, Node node)
+ {
+ var helpNode = node.Sons[index + 1];
+ while (!helpNode.Leaf)
+ {
+ helpNode = helpNode.Sons[0];
+ }
+ return (helpNode.Keys[0].key, helpNode.Keys[0].value);
+ }
+
+ private void Fill(int index, ref Node cursor)
+ {
+ if (index != 0 && cursor.Sons[index - 1].CountKeys >= MinimumDegreeOfTree)
+ {
+ TakeKeyInPrev(index, ref cursor);
+ }
+ else if (index != cursor.CountKeys && cursor.Sons[index + 1].CountKeys >= MinimumDegreeOfTree)
+ {
+ TakeKeyInNext(index, ref cursor);
+ }
+ else
+ {
+ if (index != cursor.CountKeys)
+ {
+ Merge(index, ref cursor);
+ }
+ else
+ {
+ Merge(index - 1, ref cursor);
+ }
+ }
+ }
+
+ private void TakeKeyInPrev(int index, ref Node cursor)
+ {
+ var child = cursor.Sons[index];
+ var siblings = cursor.Sons[index - 1];
+ for (int i = child.CountKeys - 1; i >= 0; --i)
+ {
+ child.Keys[i + 1] = child.Keys[i];
+ }
+ if (!child.Leaf)
+ {
+ for (int i = child.CountKeys; i >= 0; i--)
+ {
+ child.Sons[i + 1] = child.Sons[i];
+ }
+ }
+ child.Keys[0] = cursor.Keys[index - 1];
+ if (!child.Leaf)
+ {
+ child.Sons[0] = siblings.Sons[siblings.CountKeys];
+ }
+ cursor.Keys[index - 1] = siblings.Keys[siblings.CountKeys - 1];
+ child.CountKeys++;
+ siblings.CountKeys--;
+ }
+
+ private void TakeKeyInNext(int index, ref Node cursor)
+ {
+ var child = cursor.Sons[index];
+ var siblings = cursor.Sons[index + 1];
+ child.Keys[child.CountKeys] = cursor.Keys[index];
+ if (!child.Leaf)
+ {
+ child.Sons[child.CountKeys + 1] = siblings.Sons[0];
+ }
+ cursor.Keys[index] = siblings.Keys[0];
+ for (int i = 1; i < siblings.CountKeys; ++i)
+ {
+ siblings.Keys[i - 1] = siblings.Keys[i];
+ }
+ if (!siblings.Leaf)
+ {
+ for (int i = 1; i <= siblings.CountKeys; ++i)
+ {
+ siblings.Sons[i - 1] = siblings.Sons[i];
+ }
+ }
+ child.CountKeys++;
+ siblings.CountKeys--;
+ }
+
+ private void Merge(int index, ref Node cursor)
+ {
+ var child = cursor.Sons[index];
+ var siblings = cursor.Sons[index + 1];
+ child.Keys[MinimumDegreeOfTree - 1] = cursor.Keys[index];
+ for (int i = 0; i < siblings.CountKeys; i++)
+ {
+ child.Keys[i + MinimumDegreeOfTree] = siblings.Keys[i];
+ }
+ if (!child.Leaf)
+ {
+ for (int i = 0; i <= siblings.CountKeys; i++)
+ {
+ child.Sons[i + MinimumDegreeOfTree] = siblings.Sons[i];
+ }
+ }
+ for (int i = index + 1; i < cursor.CountKeys; i++)
+ {
+ cursor.Keys[i - 1] = cursor.Keys[i];
+ }
+ for (int i = index + 2; i <= cursor.CountKeys; i++)
+ {
+ cursor.Sons[i - 1] = cursor.Sons[i];
+ }
+ child.CountKeys += siblings.CountKeys + 1;
+ cursor.CountKeys--;
+ }
+ }
+}
\ No newline at end of file
diff --git a/hw3B-tree/hw3B-tree/Program.cs b/hw3B-tree/hw3B-tree/Program.cs
new file mode 100644
index 0000000..68678b7
--- /dev/null
+++ b/hw3B-tree/hw3B-tree/Program.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Hw3B_tree
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var tree = new BTree(2);
+ tree.Insert("1", "1");
+ tree.Insert("2", "2");
+ tree.Insert("3", "3");
+ tree.Insert("4", "4");
+ tree.Insert("5", "5");
+ tree.Insert("6", "6");
+ tree.Insert("7", "7");
+ tree.Insert("8", "8");
+ tree.Insert("9", "9");
+ }
+ }
+}
\ No newline at end of file
diff --git a/hw3B-tree/hw3B-tree/hw3B-tree.csproj b/hw3B-tree/hw3B-tree/hw3B-tree.csproj
new file mode 100644
index 0000000..5b12930
--- /dev/null
+++ b/hw3B-tree/hw3B-tree/hw3B-tree.csproj
@@ -0,0 +1,9 @@
+
+
+
+ Exe
+ netcoreapp3.1
+ hw3B_tree
+
+
+