├── .gitignore
├── .travis.yml
├── Algorithms.sln
├── Algorithms
├── Algorithms.csproj
├── App.config
├── CrackingTheCodeInterview
│ ├── 01ChapterStringArray
│ │ ├── Array.cs
│ │ └── String.cs
│ ├── 02ChapterLinkedLists
│ │ └── LinkedList.cs
│ ├── 03ChapterStackQueue
│ │ ├── QueueBasedOnStacks.cs
│ │ ├── StackExt.cs
│ │ ├── StackSet.cs
│ │ └── StackWithMin.cs
│ └── 04ChapterTreeGraph
│ │ └── Tree.cs
├── DataStructures
│ ├── Graph
│ │ ├── Graph.cs
│ │ └── GraphNode.cs
│ ├── HashTable
│ │ ├── DoubleHashTable.cs
│ │ ├── HashTableItem.cs
│ │ ├── HashTableWithLinkedList.cs
│ │ ├── IHashTable.cs
│ │ ├── LinearHashTable.cs
│ │ └── QuadraticHashTable.cs
│ ├── Heap
│ │ └── Heap.cs
│ ├── LinkedList
│ │ ├── LinkedList.cs
│ │ └── LinkedListNode.cs
│ └── Tree
│ │ ├── AVLTree.cs
│ │ ├── AVLTreeNode.cs
│ │ ├── BinarySearchTree.cs
│ │ ├── BinarySearchTreeNode.cs
│ │ ├── ITree.cs
│ │ ├── ITreeNode.cs
│ │ ├── RedBlackTree.cs
│ │ └── RedBlackTreeNode.cs
├── Helpers
│ ├── PrimeList.cs
│ └── SortHelper.cs
├── Properties
│ └── AssemblyInfo.cs
└── SortAlgorithms
│ ├── ISorter.cs
│ ├── NonComparison
│ ├── BucketSorter.cs
│ ├── CountingSorter.cs
│ ├── CountingStableSorter.cs
│ ├── LSDRadixSorter.cs
│ └── MSDRadixSorter.cs
│ ├── Stable
│ ├── BubbleSorter.cs
│ ├── CocktailSorter.cs
│ ├── GnomeSorter.cs
│ ├── InsertionSorter.cs
│ ├── MergeSorter.cs
│ └── OddEvenSorter.cs
│ └── Unstable
│ ├── HeapSorter.cs
│ ├── QuickSorter.cs
│ ├── SelectionSorter.cs
│ └── ShellSorter.cs
├── AlgorithmsTests
├── AlgorithmsTests.csproj
├── CrackingTheCodeInterview
│ ├── 01ChapterStringArray
│ │ ├── ArrayTests.cs
│ │ └── StringTests.cs
│ ├── 02ChapterLinkedLists
│ │ └── LinkedListTests.cs
│ ├── 03ChapterStackQueue
│ │ ├── QueueTests.cs
│ │ └── StackTests.cs
│ └── 04ChapterTreeGraph
│ │ └── TreeTests.cs
├── DataStructures
│ ├── Graph
│ │ └── GraphTests.cs
│ ├── HashTable
│ │ └── HashTableTestsFactory.cs
│ ├── Heap
│ │ └── HeapTests.cs
│ └── Tree
│ │ ├── AVLTreeTests.cs
│ │ ├── BinarySearchTreeNodeTests.cs
│ │ ├── BinarySearchTreeTests.cs
│ │ └── RedBlackTreeTests.cs
├── HelperTests
│ └── PrimeListTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── SortAlgorithms
│ ├── SorterTestsFactory.cs
│ └── SorterTestsHelper.cs
├── SorterHelper
│ ├── ISorterTester.cs
│ ├── SorterCharTester.cs
│ ├── SorterDoubleTester.cs
│ ├── SorterIntegerTester.cs
│ └── SorterStringTester.cs
└── packages.config
├── LICENSE
├── README.md
└── appveyor.yml
/.gitignore:
--------------------------------------------------------------------------------
1 | Algorithms/bin/*
2 | Algorithms/obj/*
3 | .vs/Algorithms/v14/.suo
4 | AlgorithmsTests/bin/*
5 | AlgorithmsTests/obj/*
6 | packages/*
7 | */*.csproj.user
8 | *.DotSettings.user
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: csharp
2 | solution: Algorithms.sln
3 | install:
4 | - nuget restore Algorithms.sln
5 | - nuget install NUnit.Console -Version 3.4.1 -OutputDirectory testrunner
6 | script:
7 | - xbuild Algorithms.sln /p:Configuration=Debug
8 | - mono ./testrunner/NUnit.ConsoleRunner.3.4.1/tools/nunit3-console.exe ./AlgorithmsTests/bin/Debug/AlgorithmsTests.dll
--------------------------------------------------------------------------------
/Algorithms.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25123.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Algorithms", "Algorithms\Algorithms.csproj", "{80FA8F11-8329-4C23-891C-BD4F9FADAA91}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlgorithmsTests", "AlgorithmsTests\AlgorithmsTests.csproj", "{3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Release|Any CPU = Release|Any CPU
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Debug|x64.ActiveCfg = Debug|x64
21 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Debug|x64.Build.0 = Debug|x64
22 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Release|Any CPU.Build.0 = Release|Any CPU
24 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Release|x64.ActiveCfg = Release|x64
25 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}.Release|x64.Build.0 = Release|x64
26 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Debug|x64.ActiveCfg = Debug|x64
29 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Debug|x64.Build.0 = Debug|x64
30 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Release|x64.ActiveCfg = Release|Any CPU
33 | {3EA5ACEF-6FFF-4EA6-B1B5-FB5CBF96E02D}.Release|x64.Build.0 = Release|Any CPU
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | EndGlobal
39 |
--------------------------------------------------------------------------------
/Algorithms/Algorithms.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {80FA8F11-8329-4C23-891C-BD4F9FADAA91}
8 | Library
9 | Properties
10 | Algorithms
11 | Algorithms
12 | v4.5.2
13 | 512
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 | true
40 | bin\x64\Debug\
41 | DEBUG;TRACE
42 | full
43 | x64
44 | prompt
45 | MinimumRecommendedRules.ruleset
46 | true
47 |
48 |
49 | bin\x64\Release\
50 | TRACE
51 | true
52 | pdbonly
53 | x64
54 | prompt
55 | MinimumRecommendedRules.ruleset
56 | true
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
128 |
--------------------------------------------------------------------------------
/Algorithms/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/01ChapterStringArray/Array.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Interview.Chapter1
2 | {
3 | public static class Array
4 | {
5 | ///
6 | /// Rotating square array on 90 degrees clockwise
7 | ///
8 | /// Input array
9 | public static void Rotate(this T[,] array)
10 | {
11 | if (array == null || array.GetLength(0) != array.GetLength(1))
12 | {
13 | return;
14 | }
15 |
16 | // goes by layers
17 | for (var layer = 0; layer < array.GetLength(0) / 2; layer++)
18 | {
19 | var first = layer;
20 | var last = array.GetLength(0) - layer - 1;
21 |
22 | // goes by elements
23 | for (var j = first; j < last; j++)
24 | {
25 | var offset = j - first;
26 |
27 | // save top
28 | var temp = array[layer, j];
29 |
30 | // left to top
31 | array[layer, j] = array[last - offset, layer];
32 |
33 | // bottom to left
34 | array[last - offset, layer] = array[last, last - offset];
35 |
36 | // right to bottom
37 | array[last, last - offset] = array[j, last];
38 |
39 | // top to right
40 | array[j, last] = temp;
41 | }
42 | }
43 | }
44 |
45 | ///
46 | /// Set zero in columns and rows where array has at least 1 zero
47 | ///
48 | /// Input array
49 | public static void Zerofy(this int[,] array)
50 | {
51 | if (array == null)
52 | {
53 | return;
54 | }
55 |
56 | bool[] zeroRows = new bool[array.GetLength(0)];
57 | bool[] zeroColumns = new bool[array.GetLength(1)];
58 |
59 | for (var i = 0; i < array.GetLength(0); i++)
60 | {
61 | for (var j = 0; j < array.GetLength(1); j++)
62 | {
63 | if (array[i,j] == 0)
64 | {
65 | zeroRows[i] = true;
66 | zeroColumns[j] = true;
67 | }
68 | }
69 | }
70 |
71 | for (var i = 0; i < array.GetLength(0); i++)
72 | {
73 | for (var j = 0; j < array.GetLength(1); j++)
74 | {
75 | if (zeroRows[i] || zeroColumns[j])
76 | {
77 | array[i, j] = 0;
78 | }
79 | }
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/01ChapterStringArray/String.cs:
--------------------------------------------------------------------------------
1 | using System.Text;
2 | using Algorithms.Helpers;
3 |
4 | namespace Algorithms.Interview.Chapter1
5 | {
6 | ///
7 | /// Solutions for tasks from chapter1: strings and arrays
8 | ///
9 | public static class String
10 | {
11 | private static int asciiLength = 256;
12 |
13 | ///
14 | /// This methos guess that string is using only ASCII
15 | ///
16 | /// String to check
17 | /// True if all chars are unique
18 | public static bool IsUniqueChars(this string s)
19 | {
20 | if (string.IsNullOrEmpty(s))
21 | {
22 | return true;
23 | }
24 |
25 | /// ASCII has only 256 characters
26 | if (s.Length > asciiLength)
27 | {
28 | return false;
29 | }
30 |
31 | var presenceCheck = new bool[asciiLength];
32 | for (var i = 0; i < s.Length; i++)
33 | {
34 | var charCode = s[i];
35 | if (presenceCheck[charCode])
36 | {
37 | return false;
38 | }
39 |
40 | presenceCheck[charCode] = true;
41 | }
42 |
43 | return true;
44 | }
45 |
46 | ///
47 | /// Reverse string
48 | ///
49 | /// String to reverse
50 | public static string Reverse(this string s)
51 | {
52 | if (string.IsNullOrEmpty(s))
53 | {
54 | return string.Empty;
55 | }
56 |
57 | var charArray = s.ToCharArray();
58 | for (var i = 0; i < s.Length / 2; i++)
59 | {
60 | var endIndex = s.Length - i - 1;
61 | SortHelper.swap(charArray, i, endIndex);
62 | }
63 |
64 | return new string(charArray);
65 | }
66 |
67 | ///
68 | /// Checks if this string is permutation of another string
69 | ///
70 | /// String to check
71 | /// Another string
72 | /// True if this string is permutation
73 | ///
74 | /// Case sensitive? Assume yes
75 | /// Space sensitive? Assume yes
76 | /// ASCII or UNICODE? Assume ASCII
77 | ///
78 | public static bool IsPermutationOf(this string s1, string s2)
79 | {
80 | if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2))
81 | {
82 | return false;
83 | }
84 |
85 | if (s1.Length != s2.Length)
86 | {
87 | return false;
88 | }
89 |
90 | var counter = getAsciiCounter(s1);
91 |
92 | for (var i = 0; i < s2.Length; i++)
93 | {
94 | if (--counter[s2[i]] < 0)
95 | {
96 | return false;
97 | }
98 | }
99 |
100 | return true;
101 | }
102 |
103 | ///
104 | /// Replace space to %20
105 | ///
106 | /// input string
107 | /// String with replacements
108 | public static string ReplaceSpace(this string s)
109 | {
110 | if (string.IsNullOrEmpty(s))
111 | {
112 | return s;
113 | }
114 |
115 | var spaceCounts = 0;
116 | for (var i = 0; i < s.Length; i++)
117 | {
118 | if (s[i] == ' ')
119 | {
120 | spaceCounts++;
121 | }
122 | }
123 |
124 | if (spaceCounts == 0)
125 | {
126 | return s;
127 | }
128 |
129 | var inputArray = s.ToCharArray();
130 | var currentLength = inputArray.Length + spaceCounts * 2;
131 | var result = new char[currentLength];
132 | currentLength--;
133 | for (var i = s.Length - 1; i >= 0; i--)
134 | {
135 | if (s[i] == ' ')
136 | {
137 | result[currentLength--] = '0';
138 | result[currentLength--] = '2';
139 | result[currentLength--] = '%';
140 | }
141 | else
142 | {
143 | result[currentLength--] = s[i];
144 | }
145 | }
146 |
147 | return new string(result);
148 | }
149 |
150 | ///
151 | /// Check is current string is permutation of palindrome
152 | ///
153 | /// String to check
154 | /// True if current string is permutation of palindrome
155 | ///
156 | /// Case sensetive? Assume, yes
157 | /// Space sensitive? Assume, yes
158 | /// ASCII or UNICODE? Assume ASCII
159 | ///
160 | public static bool IsPermutationOfPalindrome(this string s)
161 | {
162 | if (string.IsNullOrEmpty(s))
163 | {
164 | return false;
165 | }
166 |
167 | var counter = new bool[asciiLength];
168 | for (var i = 0; i < s.Length; i++)
169 | {
170 | counter[s[i]] = !counter[s[i]];
171 | }
172 |
173 | var hasSingleChar = false;
174 | for (var i = 0; i < counter.Length; i++)
175 | {
176 | if (counter[i])
177 | {
178 | if (hasSingleChar)
179 | {
180 | return false;
181 | }
182 | else
183 | {
184 | hasSingleChar = true;
185 | }
186 | }
187 | }
188 |
189 | return true;
190 | }
191 |
192 | ///
193 | /// Check if current string differ from another with just 1 edit/add/remove
194 | ///
195 | /// Current string
196 | /// Another string
197 | /// True of current string differ from another with just 1 edit/add/remove
198 | public static bool IsSimilarLike(this string s1, string s2)
199 | {
200 | if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2))
201 | {
202 | return false;
203 | }
204 |
205 | var l1 = s1.Length;
206 | var l2 = s2.Length;
207 |
208 | if (l1 == l2)
209 | {
210 | return checkSingleEdit(s1, s2);
211 | }
212 | else if (l1 - l2 == 1)
213 | {
214 | return checkSingleRemoval(s1, s2);
215 | }
216 | else if (l2 - l1 == 1)
217 | {
218 | return checkSingleRemoval(s2, s1);
219 | }
220 | else
221 | {
222 | return false;
223 | }
224 | }
225 |
226 | ///
227 | /// Archiving string: aaabbc -> a3b2c1 only if result less than origin
228 | ///
229 | /// Origin string to acrhive
230 | /// Archived string or origin of its less
231 | public static string Archive(this string s)
232 | {
233 | if (string.IsNullOrEmpty(s))
234 | {
235 | return string.Empty;
236 | }
237 |
238 | var result = new StringBuilder();
239 | char currentChar = s[0];
240 | var currentLength = 1;
241 | for (var i = 1; i < s.Length; i++)
242 | {
243 | if (s[i] != currentChar)
244 | {
245 | result.Append(currentChar);
246 | result.Append(currentLength);
247 | currentChar = s[i];
248 | currentLength = 1;
249 | }
250 | else
251 | {
252 | currentLength++;
253 | }
254 | }
255 |
256 | result.Append(currentChar);
257 | result.Append(currentLength);
258 |
259 | return s.Length >= result.Length ? result.ToString() : s;
260 | }
261 |
262 | ///
263 | /// Using Contains method, checks is other string - cycle shift of original
264 | ///
265 | /// Original string
266 | /// String to check
267 | /// True if other string is cycle substring of origin
268 | public static bool IsCycleShift(this string s1, string s2)
269 | {
270 | if (string.IsNullOrEmpty(s1) || string.IsNullOrEmpty(s2))
271 | {
272 | return false;
273 | }
274 |
275 | if (s1.Length != s2.Length)
276 | {
277 | return false;
278 | }
279 |
280 | return (s2 + s2).Contains(s1);
281 | }
282 |
283 | private static int[] getAsciiCounter(string s)
284 | {
285 | var counter = new int[asciiLength];
286 |
287 | for (var i = 0; i < asciiLength; i++)
288 | {
289 | counter[i] = 0;
290 | }
291 |
292 | for (var i = 0; i < s.Length; i++)
293 | {
294 | counter[s[i]]++;
295 | }
296 |
297 | return counter;
298 | }
299 |
300 | private static bool checkSingleEdit(string s1, string s2)
301 | {
302 | var foundEdit = false;
303 | for (var i = 0; i < s1.Length; i++)
304 | {
305 | if (s1[i] != s2[i])
306 | {
307 | if (foundEdit)
308 | {
309 | return false;
310 | }
311 |
312 | foundEdit = true;
313 | }
314 | }
315 |
316 | return true;
317 | }
318 |
319 | ///
320 | /// Check can we remove 1 char from s1 and get s2
321 | ///
322 | /// String where we can remove 1 symbol
323 | /// String where 1 symbol already removed
324 | /// True if we remove 1 char from s1 and get s2
325 | private static bool checkSingleRemoval(string s1, string s2)
326 | {
327 | var index1 = 0;
328 | var index2 = 0;
329 |
330 | while (index1 < s1.Length && index2 < s2.Length)
331 | {
332 | if (s1[index1] != s2[index2])
333 | {
334 | if (index1 != index2)
335 | {
336 | return false;
337 | }
338 |
339 | index1++;
340 | }
341 | else
342 | {
343 | index1++;
344 | index2++;
345 | }
346 | }
347 |
348 | return true;
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/02ChapterLinkedLists/LinkedList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Algorithms.Interview.Chapter2
5 | {
6 | public static class LinkedListExtension
7 | {
8 | ///
9 | /// Remove duplicates from list
10 | ///
11 | /// Type of list's content
12 | /// Linked list
13 | public static void RemoveDuplicates(this DataStructures.LinkedList.LinkedList list)
14 | {
15 | if (list == null || list.IsEmpty)
16 | {
17 | return;
18 | }
19 |
20 | var valuesHash = new HashSet();
21 | var previous = list.Head;
22 | var currentListItem = list.Head;
23 |
24 | while (currentListItem != null)
25 | {
26 | if (valuesHash.Contains(currentListItem.Content))
27 | {
28 | previous.Next = currentListItem.Next;
29 | currentListItem = currentListItem.Next;
30 | }
31 | else
32 | {
33 | valuesHash.Add(currentListItem.Content);
34 | previous = currentListItem;
35 | currentListItem = currentListItem.Next;
36 | }
37 | }
38 | }
39 |
40 | ///
41 | /// Get k-th element from end of linked list (based 0)
42 | ///
43 | /// Type of list's content
44 | /// Linked list
45 | /// K-th element from end or null if length of list is less
46 | public static DataStructures.LinkedList.LinkedListNode GetKFromEnd(this DataStructures.LinkedList.LinkedList list, int k)
47 | {
48 | if (list == null || list.IsEmpty)
49 | {
50 | return null;
51 | }
52 |
53 | var secondRunner = list.Head;
54 | var currentPosition = 0;
55 | while (secondRunner != null && secondRunner.Next != null && currentPosition < k)
56 | {
57 | secondRunner = secondRunner.Next;
58 | currentPosition++;
59 | }
60 |
61 | if (currentPosition < k)
62 | {
63 | return null;
64 | }
65 |
66 | var firstRunner = list.Head;
67 | while (secondRunner.Next != null)
68 | {
69 | secondRunner = secondRunner.Next;
70 | firstRunner = firstRunner.Next;
71 | }
72 |
73 | return firstRunner;
74 | }
75 |
76 | ///
77 | /// Removed given element from list
78 | ///
79 | /// Type of list's content
80 | /// Linked list node
81 | public static void RemoveFromMiddle(this DataStructures.LinkedList.LinkedListNode node)
82 | {
83 | if (node == null || node.Next == null)
84 | {
85 | return;
86 | }
87 |
88 | node.Content = node.Next.Content;
89 | node.Next = node.Next.Next;
90 | }
91 |
92 | ///
93 | /// Sort linked list: all items less X should in left part, and greater or equals - in right part
94 | ///
95 | /// Type of list's content
96 | /// Linked list
97 | /// Content to be X
98 | public static void SortAround(this DataStructures.LinkedList.LinkedList list, T content) where T : IComparable
99 | {
100 | if (list == null || list.IsEmpty)
101 | {
102 | return;
103 | }
104 |
105 | DataStructures.LinkedList.LinkedListNode listBeforeHead = null;
106 | DataStructures.LinkedList.LinkedListNode listAfterHead = null;
107 | DataStructures.LinkedList.LinkedListNode currentBefore = null;
108 | DataStructures.LinkedList.LinkedListNode currentAfter = null;
109 |
110 | var current = list.Head;
111 |
112 | while (current != null)
113 | {
114 | if (content.CompareTo(current.Content) > 0)
115 | {
116 | if (listBeforeHead == null)
117 | {
118 | listBeforeHead = currentBefore = current;
119 | }
120 | else
121 | {
122 | currentBefore.Next = current;
123 | currentBefore = current;
124 | }
125 | }
126 | else
127 | {
128 | if (listAfterHead == null)
129 | {
130 | listAfterHead = currentAfter = current;
131 | }
132 | else
133 | {
134 | currentAfter.Next = current;
135 | currentAfter = current;
136 | }
137 | }
138 |
139 | current = current.Next;
140 | }
141 |
142 | if (listBeforeHead != null)
143 | {
144 | list.Head = listBeforeHead;
145 | currentBefore.Next = listAfterHead;
146 | }
147 | else if (listAfterHead != null)
148 | {
149 | list.Head = listAfterHead;
150 |
151 | }
152 |
153 | if (currentAfter != null)
154 | {
155 | currentAfter.Next = null;
156 | }
157 | }
158 |
159 | ///
160 | /// Calculates sum of numbers stored on linked list in reversed order
161 | ///
162 | /// First summand
163 | /// Second summand
164 | /// Sum result in linked list
165 | public static DataStructures.LinkedList.LinkedList SumReversed(this DataStructures.LinkedList.LinkedList a, DataStructures.LinkedList.LinkedList b)
166 | {
167 | if (a == null || a.IsEmpty)
168 | {
169 | return b;
170 | }
171 |
172 | if (b == null || b.IsEmpty)
173 | {
174 | return a;
175 | }
176 |
177 | var result = new DataStructures.LinkedList.LinkedList();
178 | var overflow = 0;
179 | var first = a.Head;
180 | var second = b.Head;
181 |
182 | while (first != null || second != null)
183 | {
184 | var sum = (first?.Content ?? 0) + (second?.Content ?? 0) + overflow;
185 | var currentValue = sum % 10;
186 | overflow = sum / 10;
187 | result.AddToEnd(currentValue);
188 |
189 | first = first?.Next;
190 | second = second?.Next;
191 | }
192 |
193 | if (overflow > 0)
194 | {
195 | result.AddToEnd(overflow);
196 | }
197 |
198 | return result;
199 | }
200 |
201 | ///
202 | /// Calculates sum of numbers stored on linked list in odinal order
203 | ///
204 | /// First summand
205 | /// Second summand
206 | /// Sum result in linked list
207 | public static DataStructures.LinkedList.LinkedList Sum(this DataStructures.LinkedList.LinkedList a, DataStructures.LinkedList.LinkedList b)
208 | {
209 | if (a == null || a.IsEmpty)
210 | {
211 | return b;
212 | }
213 |
214 | if (b == null || b.IsEmpty)
215 | {
216 | return a;
217 | }
218 |
219 | int length1 = a.Length;
220 | int length2 = b.Length;
221 |
222 | if (length1 < length2)
223 | {
224 | padLeft(a, length2 - length1);
225 | }
226 |
227 | if (length2 < length1)
228 | {
229 | padLeft(b, length1 - length2);
230 | }
231 |
232 | var result = sumHelper(a.Head, b.Head);
233 | if (result.Overflow > 0)
234 | {
235 | result.result.AddToBegin(result.Overflow);
236 | }
237 |
238 | return result.result;
239 | }
240 |
241 | private static void padLeft(DataStructures.LinkedList.LinkedList list, int count)
242 | {
243 | for (var i = 0; i < count; i++)
244 | {
245 | list.AddToBegin(0);
246 | }
247 | }
248 |
249 | private static SumResult sumHelper(DataStructures.LinkedList.LinkedListNode a, DataStructures.LinkedList.LinkedListNode b)
250 | {
251 | if (a == null || b == null)
252 | {
253 | return new SumResult();
254 | }
255 |
256 | var result = sumHelper(a.Next, b.Next);
257 |
258 | var sum = result.Overflow + a.Content + b.Content;
259 | result.result.AddToBegin(sum % 10);
260 | result.Overflow = sum / 10;
261 |
262 | return result;
263 | }
264 |
265 | ///
266 | /// Checks is given list is palindrome
267 | ///
268 | /// Content type
269 | /// Given list
270 | /// First intersection node
271 | public static bool IsPalindrome(this DataStructures.LinkedList.LinkedList list)
272 | {
273 | if (list == null || list.IsEmpty)
274 | {
275 | return false;
276 | }
277 |
278 | var fast = list.Head;
279 | var slow = list.Head;
280 | var stack = new Stack();
281 |
282 | while (fast != null && fast.Next != null)
283 | {
284 | stack.Push(slow.Content);
285 | slow = slow.Next;
286 | fast = fast.Next.Next;
287 | }
288 |
289 | // odd length
290 | if (fast != null)
291 | {
292 | slow = slow.Next;
293 | }
294 |
295 | while (stack.Count > 0)
296 | {
297 | if (!stack.Pop().Equals(slow.Content))
298 | {
299 | return false;
300 | }
301 |
302 | slow = slow.Next;
303 | }
304 |
305 | return true;
306 | }
307 |
308 | ///
309 | /// Return node of intersecion (by ref) between lists. Is no intersection - return null
310 | ///
311 | /// Content type
312 | /// First list
313 | /// Second list
314 | /// Node of intersection
315 | public static DataStructures.LinkedList.LinkedListNode GetIntersection(this DataStructures.LinkedList.LinkedList list1, DataStructures.LinkedList.LinkedList list2)
316 | {
317 | if (list1 == null || list1.IsEmpty || list2 == null || list2.IsEmpty)
318 | {
319 | return null;
320 | }
321 |
322 | var countAndTail1 = GetCountAndTail(list1);
323 | var countAndTail2 = GetCountAndTail(list2);
324 |
325 | if (countAndTail1.Tail != countAndTail2.Tail)
326 | {
327 | return null;
328 | }
329 |
330 | var shorter = countAndTail1.Count < countAndTail2.Count
331 | ? list1.Head : list2.Head;
332 |
333 | var longer = countAndTail1.Count < countAndTail2.Count
334 | ? list2.Head : list1.Head;
335 |
336 | for (var i = 0; i < Math.Abs(countAndTail1.Count - countAndTail2.Count); i++)
337 | {
338 | longer = longer.Next;
339 | }
340 |
341 | while (shorter != null)
342 | {
343 | if (shorter == longer)
344 | {
345 | return shorter;
346 | }
347 |
348 | shorter = shorter.Next;
349 | longer = longer.Next;
350 | }
351 |
352 | return null;
353 | }
354 |
355 | private static CountAndTail GetCountAndTail(DataStructures.LinkedList.LinkedList list)
356 | {
357 | var result = new CountAndTail();
358 | var current = list.Head;
359 |
360 | while (current != null)
361 | {
362 | result.Count++;
363 | result.Tail = current;
364 | current = current.Next;
365 | }
366 |
367 | return result;
368 | }
369 |
370 | ///
371 | /// Returns start of loop if it exists
372 | ///
373 | /// Content type
374 | /// Linked list
375 | /// Start of loop is exists
376 | public static DataStructures.LinkedList.LinkedListNode GetStartOfLoop(this DataStructures.LinkedList.LinkedList list)
377 | {
378 | if (list == null || list.IsEmpty)
379 | {
380 | return null;
381 | }
382 |
383 | var slow = list.Head;
384 | var fast = list.Head;
385 |
386 | // after K steps: slow is on the beginning of the loop, fast in the loop.
387 | // Distance between them = loop length - k
388 | // after more LL - k steps, they are collised at K steps before loop start
389 | while (fast != null && fast.Next != null)
390 | {
391 | slow = slow.Next;
392 | fast = fast.Next.Next;
393 |
394 | if (fast == slow)
395 | {
396 | break;
397 | }
398 | }
399 |
400 | // no loop
401 | if (fast == null || fast.Next == null)
402 | {
403 | return null;
404 | }
405 |
406 | // move slow to Head and go K steps until collision = loop start
407 | slow = list.Head;
408 | while (slow != fast)
409 | {
410 | slow = slow.Next;
411 | fast = fast.Next;
412 | }
413 |
414 | return slow;
415 | }
416 | }
417 |
418 | class SumResult
419 | {
420 | public DataStructures.LinkedList.LinkedList result;
421 | public int Overflow;
422 |
423 | public SumResult()
424 | {
425 | this.result = new DataStructures.LinkedList.LinkedList();
426 | this.Overflow = 0;
427 | }
428 | }
429 |
430 | class CountAndTail
431 | {
432 | public int Count = 0;
433 | public DataStructures.LinkedList.LinkedListNode Tail;
434 | }
435 | }
436 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/03ChapterStackQueue/QueueBasedOnStacks.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.Interview.Chapter3
4 | {
5 | ///
6 | /// Implementation of queue based on 2 stacks
7 | ///
8 | /// Content type
9 | public class QueueBasedOnStacks
10 | {
11 | private Stack inputStack;
12 | private Stack outputStack;
13 |
14 | public QueueBasedOnStacks()
15 | {
16 | this.inputStack = new Stack();
17 | this.outputStack = new Stack();
18 | }
19 |
20 | public void Enqueue(T value)
21 | {
22 | this.inputStack.Push(value);
23 | }
24 |
25 | public T Dequeue()
26 | {
27 | if (this.outputStack.Count == 0)
28 | {
29 | this.MoveInputToOutput();
30 | }
31 |
32 | return this.outputStack.Pop();
33 | }
34 |
35 | private void MoveInputToOutput()
36 | {
37 | while (this.inputStack.Count > 0)
38 | {
39 | this.outputStack.Push(this.inputStack.Pop());
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/03ChapterStackQueue/StackExt.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Algorithms.Interview.Chapter3
5 | {
6 | public static class StackExt
7 | {
8 | ///
9 | /// Sorting of stack with usage of just 1 stack. Minimal element of result should be on top
10 | ///
11 | /// Content type
12 | /// Stack to sort
13 | /// Sorted stack
14 | public static Stack Sort(this Stack stack) where T : IComparable
15 | {
16 | var result = new Stack();
17 |
18 | while (stack.Count > 0)
19 | {
20 | var currentValue = stack.Pop();
21 | if (result.Count == 0 || result.Peek().CompareTo(currentValue) >= 0)
22 | {
23 | result.Push(currentValue);
24 | }
25 | else
26 | {
27 | var countOfMoved = 0;
28 | while (result.Count > 0 && result.Peek().CompareTo(currentValue) < 0)
29 | {
30 | stack.Push(result.Pop());
31 | countOfMoved++;
32 | }
33 |
34 | result.Push(currentValue);
35 |
36 | for (var i = 0; i < countOfMoved; i++)
37 | {
38 | result.Push(stack.Pop());
39 | }
40 | }
41 | }
42 |
43 | return result;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/03ChapterStackQueue/StackSet.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Algorithms.Interview.Chapter3
5 | {
6 | ///
7 | /// Implementation of stack set
8 | ///
9 | /// Content type
10 | public class StackSet
11 | {
12 | private List> stackSet;
13 | private int maxStackCapacity;
14 |
15 | public StackSet(int maxStackCapacity)
16 | {
17 | this.maxStackCapacity = maxStackCapacity;
18 | this.stackSet = new List>();
19 |
20 | this.stackSet.Add(new Stack());
21 | }
22 |
23 | public void Push(T value)
24 | {
25 | var currentStack = this.GetCurrentStack();
26 | if (currentStack.Count >= this.maxStackCapacity)
27 | {
28 | var newStack = new Stack();
29 | newStack.Push(value);
30 | this.stackSet.Add(newStack);
31 | }
32 | else
33 | {
34 | currentStack.Push(value);
35 | }
36 | }
37 |
38 | public T Pop()
39 | {
40 | var currentStack = this.GetCurrentStack();
41 | return this.PopFromStack(currentStack, this.stackSet.Count - 1);
42 | }
43 |
44 | public T PopAt(int stackIndex)
45 | {
46 | if (stackIndex >= this.stackSet.Count)
47 | {
48 | throw new OverflowException();
49 | }
50 |
51 | var stack = this.stackSet[stackIndex];
52 | return this.PopFromStack(stack, stackIndex);
53 | }
54 |
55 | private T PopFromStack(Stack stack, int stackIndex)
56 | {
57 | var value = stack.Pop();
58 | if (stack.Count == 0 && this.stackSet.Count > 1)
59 | {
60 | this.stackSet.RemoveAt(stackIndex);
61 | }
62 |
63 | return value;
64 | }
65 |
66 | private Stack GetCurrentStack()
67 | {
68 | return this.stackSet[this.stackSet.Count - 1];
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/03ChapterStackQueue/StackWithMin.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.Interview.Chapter3
4 | {
5 | public class StackWithMin : Stack
6 | {
7 | private Stack stackOfMins;
8 |
9 | public StackWithMin() : base()
10 | {
11 | this.stackOfMins = new Stack();
12 | }
13 |
14 | public int Min
15 | {
16 | get
17 | {
18 | return this.stackOfMins.Count == 0
19 | ? int.MaxValue
20 | : stackOfMins.Peek();
21 | }
22 | }
23 |
24 | public new void Push(int value)
25 | {
26 | if (value <= this.Min)
27 | {
28 | this.stackOfMins.Push(value);
29 | }
30 |
31 | base.Push(value);
32 | }
33 |
34 | public new int Pop()
35 | {
36 | var value = base.Pop();
37 | if (value == this.Min)
38 | {
39 | this.stackOfMins.Pop();
40 | }
41 |
42 | return value;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Algorithms/CrackingTheCodeInterview/04ChapterTreeGraph/Tree.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Algorithms.DataStructures.Tree;
3 |
4 | namespace Algorithms.Interview.Chapter4
5 | {
6 | public static class TreeExtensions
7 | {
8 | ///
9 | /// Created balanced binary search tree from sorted array
10 | ///
11 | /// Sorted values
12 | public static BinarySearchTree CreateBalancedBinarySearchTreeFromSortedArray(T[] values)
13 | where T:IComparable
14 | {
15 | var tree = new BinarySearchTree();
16 | tree.Root = CreateBST(values, 0, values.Length - 1);
17 |
18 | return tree;
19 | }
20 |
21 | private static BinarySearchTreeNode CreateBST(T[] values, int start, int end)
22 | where T:IComparable
23 | {
24 | if (end < start)
25 | {
26 | return null;
27 | }
28 |
29 | int middle = (int)Math.Ceiling((start + end) / 2.0);
30 | var node = new BinarySearchTreeNode(values[middle]);
31 |
32 | node.Left = CreateBST(values, start, middle - 1);
33 | node.Right = CreateBST(values, middle + 1, end);
34 |
35 | return node;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Graph/Graph.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Algorithms.DataStructures.Graph
6 | {
7 | ///
8 | /// Graph, could be oriented or not
9 | ///
10 | /// Content type
11 | public class Graph
12 | {
13 | public List> Nodes { get; }
14 |
15 | public Graph()
16 | {
17 | this.Nodes = new List>();
18 | }
19 |
20 | public bool IsEmpty
21 | {
22 | get
23 | {
24 | return this.Nodes.Count == 0;
25 | }
26 | }
27 |
28 | public GraphNode AddNode(T value)
29 | {
30 | var newNode = new GraphNode(value);
31 | this.Nodes.Add(newNode);
32 | return newNode;
33 | }
34 |
35 | public bool AddEdge(GraphNode node1, GraphNode node2, bool directed = false)
36 | {
37 | if (!this.Nodes.Contains(node1) || !this.Nodes.Contains(node2))
38 | {
39 | return false;
40 | }
41 |
42 | this.AddToCollection(node1.OutputNodes, node2);
43 | this.AddToCollection(node2.InputNodes, node1);
44 |
45 | if (!directed)
46 | {
47 | this.AddToCollection(node2.OutputNodes, node1);
48 | this.AddToCollection(node1.InputNodes, node2);
49 | }
50 |
51 | return true;
52 | }
53 |
54 | public bool RemoveEdge(GraphNode node1, GraphNode node2, bool directed = false)
55 | {
56 | if (!this.Nodes.Contains(node1) || !this.Nodes.Contains(node2))
57 | {
58 | return false;
59 | }
60 |
61 | this.RemoveFromCollection(node1.OutputNodes, node2);
62 | this.RemoveFromCollection(node2.InputNodes, node1);
63 |
64 | if (!directed)
65 | {
66 | this.RemoveFromCollection(node2.OutputNodes, node1);
67 | this.RemoveFromCollection(node1.InputNodes, node2);
68 | }
69 |
70 | return true;
71 | }
72 |
73 | public bool RemoveNode(GraphNode node)
74 | {
75 | if (!this.Nodes.Contains(node))
76 | {
77 | return false;
78 | }
79 |
80 | foreach (var edge in node.InputNodes)
81 | {
82 | this.RemoveFromCollection(edge.OutputNodes, node);
83 | }
84 |
85 | foreach (var edge in node.OutputNodes)
86 | {
87 | this.RemoveFromCollection(edge.InputNodes, node);
88 | }
89 |
90 | this.Nodes.Remove(node);
91 | return true;
92 | }
93 |
94 | public void ResetVisited()
95 | {
96 | foreach (var node in this.Nodes)
97 | {
98 | node.Visited = false;
99 | }
100 | }
101 |
102 | public bool AreConnected(GraphNode node1, GraphNode node2)
103 | {
104 | if (!this.Nodes.Contains(node1) || !this.Nodes.Contains(node2))
105 | {
106 | return false;
107 | }
108 |
109 | this.ResetVisited();
110 |
111 | var nodesToVisit = new Queue>();
112 | nodesToVisit.Enqueue(node1);
113 |
114 | while (nodesToVisit.Count > 0)
115 | {
116 | var currentNode = nodesToVisit.Dequeue();
117 | if (currentNode.Visited)
118 | {
119 | continue;
120 | }
121 |
122 | currentNode.Visited = true;
123 | if (currentNode.OutputNodes.Contains(node2))
124 | {
125 | return true;
126 | }
127 |
128 | foreach (var node in currentNode.OutputNodes)
129 | {
130 | nodesToVisit.Enqueue(node);
131 | }
132 | }
133 |
134 | return false;
135 | }
136 |
137 | public List> GetLexicographicOrder()
138 | {
139 | var result = new List>();
140 |
141 | while (!this.IsEmpty)
142 | {
143 | var freeNodes = this.GetNodesWithoutInput();
144 |
145 | if (freeNodes.Count == 0)
146 | {
147 | throw new InvalidOperationException();
148 | }
149 |
150 | result.AddRange(freeNodes);
151 |
152 | foreach (var node in freeNodes)
153 | {
154 | this.RemoveNode(node);
155 | }
156 | }
157 |
158 | return result;
159 | }
160 |
161 | private List> GetNodesWithoutInput()
162 | {
163 | return this.Nodes.Where(x => x.InputNodes.Count() == 0).ToList();
164 | }
165 |
166 | private void AddToCollection(HashSet> nodes, GraphNode node)
167 | {
168 | if (!nodes.Contains(node))
169 | {
170 | nodes.Add(node);
171 | }
172 | }
173 |
174 | private void RemoveFromCollection(HashSet> nodes, GraphNode node)
175 | {
176 | if (nodes.Contains(node))
177 | {
178 | nodes.Remove(node);
179 | }
180 | }
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Graph/GraphNode.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.DataStructures.Graph
4 | {
5 | ///
6 | /// Graph node
7 | ///
8 | /// Content type
9 | public class GraphNode
10 | {
11 | public T Content { get; set; }
12 | public HashSet> OutputNodes { get; }
13 | public HashSet> InputNodes { get; }
14 | public bool Visited { get; set; }
15 |
16 | public GraphNode(T value)
17 | {
18 | this.Content = value;
19 | this.OutputNodes = new HashSet>();
20 | this.InputNodes = new HashSet>();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/HashTable/DoubleHashTable.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using Algorithms.Helpers;
4 |
5 | namespace Algorithms.DataStructures.HashTable
6 | {
7 | ///
8 | /// Implementation of hash tabl with doule hashing
9 | ///
10 | public class DoubleHashTable : IEnumerable, IHashTable
11 | {
12 | private int HashPrime { get; set; }
13 | private int Size { get; set; }
14 | private int Count { get; set; }
15 | private HashTableItem[] Storage { get; set; }
16 |
17 | public DoubleHashTable()
18 | : this(10)
19 | {
20 | }
21 |
22 | public DoubleHashTable(int size)
23 | {
24 | this.Size = PrimeList.GetNextPrime(size);
25 | this.HashPrime = PrimeList.GetNextPrime(this.Size);
26 | this.Storage = new HashTableItem[this.Size];
27 | this.Count = 0;
28 | }
29 |
30 | public bool Add(int value)
31 | {
32 | if (this.Count >= this.Size)
33 | {
34 | this.Rebuild();
35 | }
36 |
37 | var baseIndex = this.GetHash(value);
38 | var index = baseIndex;
39 | var step = 0;
40 | while (this.Storage[index] != null &&
41 | (!this.Storage[index].IsDeleted || !this.Storage[index].IsEmpty))
42 | {
43 | index = this.GetNextProbingIndex(baseIndex, step, value);
44 | if (step < this.Size)
45 | {
46 | step++;
47 | }
48 | else
49 | {
50 | return false;
51 | }
52 | }
53 |
54 | if (this.Storage[index] == null)
55 | {
56 | this.Storage[index] = new HashTableItem();
57 | }
58 |
59 | this.Storage[index].Content = value;
60 | this.Storage[index].IsDeleted = false;
61 | this.Storage[index].IsEmpty = false;
62 | this.Count++;
63 | return true;
64 | }
65 |
66 | public bool Contains(int value)
67 | {
68 | var baseIndex = this.GetHash(value);
69 | var index = baseIndex;
70 | var step = 0;
71 | while (true)
72 | {
73 | if (this.Storage[index] == null
74 | || this.Storage[index].IsDeleted == true
75 | || this.Storage[index].IsEmpty == true)
76 | {
77 | return false;
78 | }
79 |
80 | if (this.Storage[index].Content == value)
81 | {
82 | return true;
83 | }
84 |
85 | if (step < this.Size)
86 | {
87 | step++;
88 | }
89 | else
90 | {
91 | return false;
92 | }
93 |
94 | index = this.GetNextProbingIndex(baseIndex, step, value);
95 | }
96 | }
97 |
98 | public bool Remove(int value)
99 | {
100 | var baseIndex = this.GetHash(value);
101 | var index = baseIndex;
102 | var step = 0;
103 | while (true)
104 | {
105 | if (this.Storage[index] == null
106 | || this.Storage[index].IsEmpty == true)
107 | {
108 | return false;
109 | }
110 |
111 | if (this.Storage[index].Content == value)
112 | {
113 | this.Storage[index].IsDeleted = true;
114 | this.Storage[index].IsEmpty = true;
115 | this.Count--;
116 | return true;
117 | }
118 |
119 | if (step < this.Size)
120 | {
121 | step++;
122 | }
123 | else
124 | {
125 | return false;
126 | }
127 |
128 | index = this.GetNextProbingIndex(baseIndex, step, value);
129 | }
130 | }
131 |
132 | public void Clear()
133 | {
134 | foreach (var item in this.Storage)
135 | {
136 | if (item != null)
137 | {
138 | item.IsEmpty = true;
139 | item.IsDeleted = false;
140 | }
141 | }
142 | }
143 |
144 | private void Rebuild()
145 | {
146 | this.Size = PrimeList.GetNextPrime(this.Size);
147 | this.HashPrime = PrimeList.GetNextPrime(this.Size);
148 | var newStorageItems = new List();
149 | foreach (var item in this)
150 | {
151 | newStorageItems.Add(item);
152 | }
153 |
154 | this.Count = 0;
155 | this.Storage = new HashTableItem[this.Size];
156 | foreach (var item in newStorageItems)
157 | {
158 | this.Add(item);
159 | }
160 | }
161 |
162 | private int GetHash(int value)
163 | {
164 | return value % this.Size;
165 | }
166 |
167 | private int GetNextProbingIndex(int index, int step, int value)
168 | {
169 | var hash = this.HashPrime - value % this.HashPrime;
170 | return (index + step * hash) % this.Size;
171 | }
172 |
173 | public IEnumerator GetEnumerator()
174 | {
175 | foreach (var item in this.Storage)
176 | {
177 | if (item != null && !item.IsDeleted && !item.IsEmpty)
178 | {
179 | yield return item.Content;
180 | }
181 | }
182 | }
183 |
184 | IEnumerator IEnumerable.GetEnumerator()
185 | {
186 | return this.GetEnumerator();
187 | }
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/HashTable/HashTableItem.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.HashTable
4 | {
5 | internal class HashTableItem where T:IComparable
6 | {
7 | public T Content { get; set; }
8 | public bool IsEmpty { get; set; }
9 | public bool IsDeleted { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/HashTable/HashTableWithLinkedList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 |
4 | namespace Algorithms.DataStructures.HashTable
5 | {
6 | ///
7 | /// Implements hash table with using linked list
8 | ///
9 | public class HashTableWithLinkedList: IEnumerable, IHashTable
10 | {
11 | private int Size { get; set; }
12 | private int Count { get; set; }
13 | private LinkedList[] Storage { get; set; }
14 |
15 | public HashTableWithLinkedList()
16 | : this(16)
17 | {
18 | }
19 |
20 | public HashTableWithLinkedList(int size)
21 | {
22 | this.Size = size;
23 | this.Storage = new LinkedList[this.Size];
24 | this.Count = 0;
25 | }
26 |
27 | public bool Add(int value)
28 | {
29 | if (this.Count >= this.Size)
30 | {
31 | this.Rebuild();
32 | }
33 |
34 | var index = this.GetHash(value);
35 | if (this.Storage[index] == null)
36 | {
37 | this.Storage[index] = new LinkedList();
38 | }
39 |
40 | this.Storage[index].AddLast(value);
41 | this.Count++;
42 | return true;
43 | }
44 |
45 | public bool Contains(int value)
46 | {
47 | var index = this.GetHash(value);
48 | if (this.Storage[index] == null)
49 | {
50 | return false;
51 | }
52 |
53 | return this.Storage[index].Contains(value);
54 | }
55 |
56 | public bool Remove(int value)
57 | {
58 | var index = this.GetHash(value);
59 | if (this.Storage[index] == null)
60 | {
61 | return false;
62 | }
63 |
64 | this.Count--;
65 | return this.Storage[index].Remove(value);
66 | }
67 |
68 | public void Clear()
69 | {
70 | foreach (var list in this.Storage)
71 | {
72 | if (list != null && list.Count > 0)
73 | {
74 | list.Clear();
75 | }
76 | }
77 | }
78 |
79 | private void Rebuild()
80 | {
81 | this.Size = this.Size * 2;
82 | var newStorageItems = new List();
83 | foreach(var item in this)
84 | {
85 | newStorageItems.Add(item);
86 | }
87 |
88 | this.Count = 0;
89 | this.Storage = new LinkedList[this.Size];
90 | foreach (var item in newStorageItems)
91 | {
92 | this.Add(item);
93 | }
94 | }
95 |
96 | private int GetHash(int value)
97 | {
98 | return value % this.Size;
99 | }
100 |
101 | public IEnumerator GetEnumerator()
102 | {
103 | foreach (var list in this.Storage)
104 | {
105 | if (list != null)
106 | {
107 | foreach(var item in list)
108 | {
109 | yield return item;
110 | }
111 | }
112 | }
113 | }
114 |
115 | IEnumerator IEnumerable.GetEnumerator()
116 | {
117 | return this.GetEnumerator();
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/HashTable/IHashTable.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.DataStructures.HashTable
4 | {
5 | ///
6 | /// Average: O(1)
7 | /// Worst: O(n)
8 | ///
9 | public interface IHashTable : IEnumerable
10 | {
11 | bool Add(int value);
12 |
13 | bool Contains(int value);
14 |
15 | bool Remove(int value);
16 |
17 | void Clear();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/HashTable/LinearHashTable.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using Algorithms.Helpers;
4 |
5 | namespace Algorithms.DataStructures.HashTable
6 | {
7 | ///
8 | /// Implementation of hash tabl with linear probing
9 | ///
10 | public class LinearHashTable : IEnumerable, IHashTable
11 | {
12 | private int Size { get; set; }
13 | private int Count { get; set; }
14 | private HashTableItem[] Storage { get; set; }
15 |
16 | public LinearHashTable()
17 | : this(10)
18 | {
19 | }
20 |
21 | public LinearHashTable(int size)
22 | {
23 | this.Size = PrimeList.GetNextPrime(size);
24 | this.Storage = new HashTableItem[this.Size];
25 | this.Count = 0;
26 | }
27 |
28 | public bool Add(int value)
29 | {
30 | if (this.Count >= this.Size)
31 | {
32 | this.Rebuild();
33 | }
34 |
35 | var index = this.GetHash(value);
36 | while (this.Storage[index] != null &&
37 | (!this.Storage[index].IsDeleted || !this.Storage[index].IsEmpty))
38 | {
39 | index = this.GetNextProbingIndex(index);
40 | }
41 |
42 | if (this.Storage[index] == null)
43 | {
44 | this.Storage[index] = new HashTableItem();
45 | }
46 |
47 | this.Storage[index].Content = value;
48 | this.Storage[index].IsDeleted = false;
49 | this.Storage[index].IsEmpty = false;
50 | this.Count++;
51 | return true;
52 | }
53 |
54 | public bool Contains(int value)
55 | {
56 | var index = this.GetHash(value);
57 | while (true)
58 | {
59 | if (this.Storage[index] == null
60 | || this.Storage[index].IsDeleted == true
61 | || this.Storage[index].IsEmpty == true)
62 | {
63 | return false;
64 | }
65 |
66 | if (this.Storage[index].Content == value)
67 | {
68 | return true;
69 | }
70 |
71 | index = this.GetNextProbingIndex(index);
72 | }
73 | }
74 |
75 | public bool Remove(int value)
76 | {
77 | var index = this.GetHash(value);
78 | while (true)
79 | {
80 | if (this.Storage[index] == null
81 | || this.Storage[index].IsEmpty == true)
82 | {
83 | return false;
84 | }
85 |
86 | if (this.Storage[index].Content == value)
87 | {
88 | this.Storage[index].IsDeleted = true;
89 | this.Count--;
90 | return true;
91 | }
92 |
93 | index = this.GetNextProbingIndex(index);
94 | }
95 | }
96 |
97 | public void Clear()
98 | {
99 | foreach (var item in this.Storage)
100 | {
101 | if (item != null)
102 | {
103 | item.IsEmpty = true;
104 | item.IsDeleted = false;
105 | }
106 | }
107 | }
108 |
109 | private void Rebuild()
110 | {
111 | this.Size = PrimeList.GetNextPrime(this.Size);
112 | var newStorageItems = new List();
113 | foreach (var item in this)
114 | {
115 | newStorageItems.Add(item);
116 | }
117 |
118 | this.Count = 0;
119 | this.Storage = new HashTableItem[this.Size];
120 | foreach (var item in newStorageItems)
121 | {
122 | this.Add(item);
123 | }
124 | }
125 |
126 | private int GetHash(int value)
127 | {
128 | return value % this.Size;
129 | }
130 |
131 | private int GetNextProbingIndex(int index)
132 | {
133 | return (index + 1) % this.Size;
134 | }
135 |
136 | public IEnumerator GetEnumerator()
137 | {
138 | foreach (var item in this.Storage)
139 | {
140 | if (item != null && !item.IsDeleted && !item.IsEmpty)
141 | {
142 | yield return item.Content;
143 | }
144 | }
145 | }
146 |
147 | IEnumerator IEnumerable.GetEnumerator()
148 | {
149 | return this.GetEnumerator();
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/HashTable/QuadraticHashTable.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using Algorithms.Helpers;
4 |
5 | namespace Algorithms.DataStructures.HashTable
6 | {
7 | ///
8 | /// Implementation of hash tabl with qiadric probing
9 | ///
10 | public class QuadraticHashTable : IEnumerable, IHashTable
11 | {
12 | private int Size { get; set; }
13 | private int Count { get; set; }
14 | private HashTableItem[] Storage { get; set; }
15 |
16 | public QuadraticHashTable()
17 | : this(10)
18 | {
19 | }
20 |
21 | public QuadraticHashTable(int size)
22 | {
23 | this.Size = PrimeList.GetNextPrime(size);
24 | this.Storage = new HashTableItem[this.Size];
25 | this.Count = 0;
26 | }
27 |
28 | public bool Add(int value)
29 | {
30 | if (this.Count >= this.Size)
31 | {
32 | this.Rebuild();
33 | }
34 |
35 | var baseIndex = this.GetHash(value);
36 | var index = baseIndex;
37 | var step = 0;
38 | while (this.Storage[index] != null &&
39 | (!this.Storage[index].IsDeleted || !this.Storage[index].IsEmpty))
40 | {
41 | index = this.GetNextProbingIndex(baseIndex, step);
42 | if (step < this.Size)
43 | {
44 | step++;
45 | }
46 | else
47 | {
48 | return false;
49 | }
50 | }
51 |
52 | if (this.Storage[index] == null)
53 | {
54 | this.Storage[index] = new HashTableItem();
55 | }
56 |
57 | this.Storage[index].Content = value;
58 | this.Storage[index].IsDeleted = false;
59 | this.Storage[index].IsEmpty = false;
60 | this.Count++;
61 | return true;
62 | }
63 |
64 | public bool Contains(int value)
65 | {
66 | var baseIndex = this.GetHash(value);
67 | var index = baseIndex;
68 | var step = 0;
69 | while (true)
70 | {
71 | if (this.Storage[index] == null
72 | || this.Storage[index].IsDeleted == true
73 | || this.Storage[index].IsEmpty == true)
74 | {
75 | return false;
76 | }
77 |
78 | if (this.Storage[index].Content == value)
79 | {
80 | return true;
81 | }
82 |
83 | if (step < this.Size)
84 | {
85 | step++;
86 | }
87 | else
88 | {
89 | return false;
90 | }
91 |
92 | index = this.GetNextProbingIndex(baseIndex, step);
93 | }
94 | }
95 |
96 | public bool Remove(int value)
97 | {
98 | var baseIndex = this.GetHash(value);
99 | var index = baseIndex;
100 | var step = 0;
101 | while (true)
102 | {
103 | if (this.Storage[index] == null
104 | || this.Storage[index].IsEmpty == true)
105 | {
106 | return false;
107 | }
108 |
109 | if (this.Storage[index].Content == value)
110 | {
111 | this.Storage[index].IsDeleted = true;
112 | this.Storage[index].IsEmpty = true;
113 | this.Count--;
114 | return true;
115 | }
116 |
117 | if (step < this.Size)
118 | {
119 | step++;
120 | }
121 | else
122 | {
123 | return false;
124 | }
125 |
126 | index = this.GetNextProbingIndex(baseIndex, step);
127 | }
128 | }
129 |
130 | public void Clear()
131 | {
132 | foreach (var item in this.Storage)
133 | {
134 | if (item != null)
135 | {
136 | item.IsEmpty = true;
137 | item.IsDeleted = false;
138 | }
139 | }
140 | }
141 |
142 | private void Rebuild()
143 | {
144 | this.Size = PrimeList.GetNextPrime(this.Size);
145 | var newStorageItems = new List();
146 | foreach (var item in this)
147 | {
148 | newStorageItems.Add(item);
149 | }
150 |
151 | this.Count = 0;
152 | this.Storage = new HashTableItem[this.Size];
153 | foreach (var item in newStorageItems)
154 | {
155 | this.Add(item);
156 | }
157 | }
158 |
159 | private int GetHash(int value)
160 | {
161 | return value % this.Size;
162 | }
163 |
164 | private int GetNextProbingIndex(int index, int step)
165 | {
166 | return (index + step * step) % this.Size;
167 | }
168 |
169 | public IEnumerator GetEnumerator()
170 | {
171 | foreach (var item in this.Storage)
172 | {
173 | if (item != null && !item.IsDeleted && !item.IsEmpty)
174 | {
175 | yield return item.Content;
176 | }
177 | }
178 | }
179 |
180 | IEnumerator IEnumerable.GetEnumerator()
181 | {
182 | return this.GetEnumerator();
183 | }
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Heap/Heap.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.DataStructures.Heap
4 | {
5 | ///
6 | /// Heap is the abstract data type which allows to store partially sorted data
7 | /// On the practice - this is array where
8 | /// For min heap: a[i] < a[2i + 1] and a[i] < a[2i + 2]
9 | /// For max heap: a[i] > a[2i + 1] and a[i] > a[2i + 2]
10 | ///
11 | /// Insert: O(lg n)
12 | /// Remove top: O(lg n)
13 | ///
14 | public class Heap
15 | {
16 | List heap;
17 | private bool isMinHeap;
18 |
19 | public Heap(bool minHeap)
20 | {
21 | this.heap = new List();
22 | this.isMinHeap = minHeap;
23 | }
24 |
25 | public int Count()
26 | {
27 | return this.heap.Count;
28 | }
29 |
30 | public int Peek()
31 | {
32 | if (this.heap.Count == 0)
33 | {
34 | return 0;
35 | }
36 |
37 | return this.heap[0];
38 | }
39 |
40 | public void Add(int item)
41 | {
42 | this.heap.Add(item);
43 | this.Up(this.heap.Count - 1);
44 | }
45 |
46 | public int ExtractTop()
47 | {
48 | if (this.heap.Count == 0)
49 | {
50 | return 0;
51 | }
52 |
53 | var min = this.heap[0];
54 | this.Switch(0, this.heap.Count - 1);
55 | this.heap.RemoveAt(this.heap.Count - 1);
56 | this.Down(0);
57 |
58 | return min;
59 | }
60 |
61 | public bool Validate()
62 | {
63 | if (this.heap.Count == 0)
64 | {
65 | return true;
66 | }
67 |
68 | for (var i = 0; i < this.heap.Count / 2; i++)
69 | {
70 | var child1Index = 2 * i + 1;
71 | var child2Index = 2 * i + 2;
72 |
73 | if (child1Index < this.heap.Count)
74 | {
75 | if (this.isMinHeap && this.heap[i] > this.heap[child1Index]
76 | || !this.isMinHeap && this.heap[i] < this.heap[child1Index])
77 | {
78 | return false;
79 | }
80 | }
81 |
82 | if (child2Index < this.heap.Count)
83 | {
84 | if (this.isMinHeap && this.heap[i] > this.heap[child2Index]
85 | || !this.isMinHeap && this.heap[i] < this.heap[child2Index])
86 | {
87 | return false;
88 | }
89 | }
90 | }
91 |
92 | return true;
93 | }
94 |
95 | private void Up(int index)
96 | {
97 | if (index == 0 || index >= this.heap.Count)
98 | {
99 | return;
100 | }
101 |
102 | int parent = (index - 1) / 2;
103 | if (this.isMinHeap && this.heap[parent] > this.heap[index]
104 | || !this.isMinHeap && this.heap[parent] < this.heap[index])
105 | {
106 | this.Switch(index, parent);
107 | this.Up(parent);
108 | }
109 | }
110 |
111 | private void Down(int index)
112 | {
113 | if (2 * index + 1 >= this.heap.Count)
114 | {
115 | return;
116 | }
117 |
118 | var childIndex1 = 2 * index + 1;
119 | var childIndex2 = 2 * index + 2;
120 | var minIndex = index;
121 |
122 | if (childIndex1 < this.heap.Count &&
123 | (this.isMinHeap && this.heap[childIndex1] < this.heap[minIndex]
124 | || !this.isMinHeap && this.heap[childIndex1] > this.heap[minIndex]))
125 | {
126 | minIndex = childIndex1;
127 | }
128 |
129 | if (childIndex2 < this.heap.Count &&
130 | (this.isMinHeap && this.heap[childIndex2] < this.heap[minIndex]
131 | || !this.isMinHeap && this.heap[childIndex2] > this.heap[minIndex]))
132 | {
133 | minIndex = childIndex2;
134 | }
135 |
136 | if (minIndex != index)
137 | {
138 | this.Switch(index, minIndex);
139 | this.Down(minIndex);
140 | }
141 | }
142 |
143 | private void Switch(int index1, int index2)
144 | {
145 | if (index1 < 0 || index1 >= this.heap.Count
146 | || index2 < 0 || index2 >= this.heap.Count)
147 | {
148 | return;
149 | }
150 |
151 | var temp = this.heap[index1];
152 | this.heap[index1] = this.heap[index2];
153 | this.heap[index2] = temp;
154 | }
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/LinkedList/LinkedList.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.DataStructures.LinkedList
2 | {
3 | public class LinkedList
4 | {
5 | public LinkedListNode Head { internal set; get; }
6 |
7 | public LinkedList()
8 | {
9 | }
10 |
11 | public bool IsEmpty
12 | {
13 | get
14 | {
15 | return this.Head == null;
16 | }
17 | }
18 |
19 | public int Length
20 | {
21 | get
22 | {
23 | var current = this.Head;
24 | var length = 0;
25 | while (current != null)
26 | {
27 | length++;
28 | current = current.Next;
29 | }
30 |
31 | return length;
32 | }
33 | }
34 |
35 | public LinkedList(T[] values) : this()
36 | {
37 | if (values == null || values.Length == 0)
38 | {
39 | return;
40 | }
41 |
42 | this.Head = new LinkedListNode(values[0]);
43 | var current = this.Head;
44 | for (var i = 1; i < values.Length; i++)
45 | {
46 | var nextNode = new LinkedListNode(values[i]);
47 | current.Next = nextNode;
48 | current = nextNode;
49 | }
50 | }
51 |
52 | public void AddToBegin(T value)
53 | {
54 | if (this.IsEmpty)
55 | {
56 | this.Head = new LinkedListNode(value);
57 | return;
58 | }
59 |
60 | var newNode = new LinkedListNode(value);
61 | newNode.Next = this.Head;
62 | this.Head = newNode;
63 | }
64 |
65 | public void AddToEnd(T value)
66 | {
67 | if (this.IsEmpty)
68 | {
69 | this.Head = new LinkedListNode(value);
70 | return;
71 | }
72 |
73 | var tail = this.Head;
74 | while(tail.Next != null)
75 | {
76 | tail = tail.Next;
77 | }
78 |
79 | tail.Next = new LinkedListNode(value);
80 | }
81 |
82 | public bool IsSameListAs(LinkedList other)
83 | {
84 | if (other == null)
85 | {
86 | return false;
87 | }
88 |
89 | var thisCurrent = this.Head;
90 | var anotherCurrent = other.Head;
91 |
92 | if (!this.IsEmpty && other.IsEmpty
93 | || this.IsEmpty && !other.IsEmpty)
94 | {
95 | return false;
96 | }
97 |
98 | while (thisCurrent != null && anotherCurrent != null)
99 | {
100 | if (!thisCurrent.Content.Equals(anotherCurrent.Content))
101 | {
102 | return false;
103 | }
104 |
105 | thisCurrent = thisCurrent.Next;
106 | anotherCurrent = anotherCurrent.Next;
107 | }
108 |
109 | return thisCurrent == null && anotherCurrent == null;
110 | }
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/LinkedList/LinkedListNode.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.DataStructures.LinkedList
2 | {
3 | public class LinkedListNode
4 | {
5 | public T Content { get; set; }
6 | public LinkedListNode Next { get; set; }
7 |
8 | public LinkedListNode() { }
9 |
10 | public LinkedListNode(T value) : this()
11 | {
12 | this.Content = value;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/AVLTree.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | ///
6 | /// Self-balansing binary search tree.
7 | /// The heights of the 2 child subtrees of any node differ by at most one.
8 | /// If at any time they differ by more than 1 - rebalancing is done to restore this property.
9 | /// Add: O(log n)
10 | /// Search: O(log n)
11 | /// Remove: O(log n)
12 | ///
13 | /// BalanceFactor has values in {-1, 0, 1} for each node in the tree
14 | /// If node has BF = -1 then it called "left-heavy"
15 | /// If node has BF = 1 then it called "right-heavy"
16 | /// If node has BF = 0 then it called "balanced"
17 | ///
18 | /// Type of data
19 | ///
20 | /// For lookup-intensive applications, faster than
21 | /// because they are more stricly balanced.
22 | /// Both are height-balanced, not weight-balanced.
23 | /// So sibling nodes can have hugely differing numbers of descendants
24 | ///
25 | public class AVLTree : BinarySearchTree> where T : IComparable
26 | {
27 | ///
28 | /// Insert content with balancing
29 | ///
30 | /// Content to insert
31 | /// Does element was added
32 | public override bool Insert(T content)
33 | {
34 | if (this.Root == null)
35 | {
36 | this.Root = new AVLTreeNode(content);
37 | return true;
38 | }
39 |
40 | if (this.FindIn(this.Root, content) != null)
41 | {
42 | return false;
43 | }
44 |
45 | var insertedNode = new AVLTreeNode(content);
46 | base.InsertNodeTo(this.Root, insertedNode);
47 | this.RebalanceIn(insertedNode);
48 | return true;
49 | }
50 |
51 | public override void MergeWith(AVLTree treeToMerge)
52 | {
53 | throw new NotSupportedException("Merge AVL trees currently doesn't supported");
54 | }
55 |
56 | public override AVLTree SplitByKey(T key)
57 | {
58 | throw new NotSupportedException("Splitting AVL trees currently doesn't supported");
59 | }
60 |
61 | ///
62 | /// Manual rotation doesn't allowed in AVL tree
63 | ///
64 | public override void RotateLeft()
65 | {
66 | throw new NotSupportedException("Manual rotating AVL trees currently doesn't supported");
67 | }
68 |
69 | ///
70 | /// Manual rotation doesn't allowed in AVL tree
71 | ///
72 | public override void RotateRight()
73 | {
74 | throw new NotSupportedException("Manual rotating AVL trees currently doesn't supported");
75 | }
76 |
77 | ///
78 | /// Verifying AVL tree node
79 | ///
80 | /// Tree node
81 | /// Tree min node
82 | /// Tree max node
83 | /// True if AVL tree node is valid
84 | protected override bool VerifyIn(BinarySearchTreeNode node, BinarySearchTreeNode min = null, BinarySearchTreeNode max = null)
85 | {
86 | var avlNode = node as AVLTreeNode;
87 |
88 | return avlNode.CalculatedHeight == avlNode.Height
89 | && Math.Abs(avlNode.BalanceFactor) < 2
90 | && base.VerifyIn(node, min, max);
91 | }
92 |
93 | protected override void Remove(BinarySearchTreeNode node)
94 | {
95 | if (node.IsTerminate)
96 | {
97 | var parentNode = node.Parent as AVLTreeNode;
98 | this.RemoveLeaf(node);
99 | this.RebalanceIn(parentNode as AVLTreeNode);
100 | }
101 | else
102 | {
103 | var leftHeight = node.Left?.Height ?? 0;
104 | var rightHeight = node.Right?.Height ?? 0;
105 | var nodeToReplace = leftHeight > rightHeight
106 | ? this.GetPredecessor(node.Content)
107 | : this.GetSuccessor(node.Content);
108 |
109 | node.Content = nodeToReplace.Content;
110 | this.Remove(nodeToReplace);
111 | }
112 | }
113 |
114 | ///
115 | /// Rebalancing tree
116 | ///
117 | /// Node to start rebalance
118 | private void RebalanceIn(AVLTreeNode node)
119 | {
120 | var currentNode = node;
121 | while (currentNode != null)
122 | {
123 | this.UpdateHeight(currentNode);
124 |
125 | var leftChild = currentNode.Left as AVLTreeNode;
126 | var rightChild = currentNode.Right as AVLTreeNode;
127 |
128 | if (currentNode.BalanceFactor == 2)
129 | {
130 | if (rightChild.BalanceFactor < 0)
131 | {
132 | currentNode.Right.Height--;
133 | currentNode.Right = this.RotateRight(currentNode.Right);
134 | currentNode.Right.Height++;
135 | }
136 |
137 | currentNode.Height -= 2;
138 | this.RotateLeft(currentNode);
139 | }
140 |
141 | if (currentNode.BalanceFactor == -2)
142 | {
143 | if (leftChild.BalanceFactor > 0)
144 | {
145 | currentNode.Left.Height--;
146 | currentNode.Left = this.RotateLeft(currentNode.Left);
147 | currentNode.Left.Height++;
148 | }
149 |
150 | currentNode.Height -= 2;
151 | this.RotateRight(currentNode);
152 | }
153 |
154 | currentNode = currentNode.Parent as AVLTreeNode;
155 | }
156 | }
157 |
158 | private void UpdateHeight(AVLTreeNode node)
159 | {
160 | if (node.IsTerminate)
161 | {
162 | node.Height = 0;
163 | return;
164 | }
165 |
166 | var leftChild = node.Left as AVLTreeNode;
167 | var rightChild = node.Right as AVLTreeNode;
168 |
169 | node.Height = 1 + Math.Max(
170 | leftChild?.Height ?? 0,
171 | rightChild?.Height ?? 0);
172 | }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/AVLTreeNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | ///
6 | /// AVL tree node.
7 | /// Contains left node which content less than this.Content
8 | /// Contains right node which content >= this.Content
9 | ///
10 | /// Type of content
11 | public class AVLTreeNode : BinarySearchTreeNode where T : IComparable
12 | {
13 | public AVLTreeNode(T content)
14 | : base(content)
15 | {
16 | }
17 |
18 | public int BalanceFactor
19 | {
20 | get { return ((this.Right as AVLTreeNode)?.Height ?? -1) - ((this.Left as AVLTreeNode)?.Height ?? -1); }
21 | }
22 |
23 | private int height = 0;
24 | public override int Height
25 | {
26 | get
27 | {
28 | return this.height;
29 | }
30 | set
31 | {
32 | this.height = value;
33 | }
34 | }
35 |
36 | public override bool HasLeft
37 | {
38 | get
39 | {
40 | return this.Left is AVLTreeNode;
41 | }
42 | }
43 |
44 | public override bool HasRight
45 | {
46 | get
47 | {
48 | return this.Right is AVLTreeNode;
49 | }
50 | }
51 |
52 | internal int CalculatedHeight
53 | {
54 | get { return base.Height; }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/BinarySearchTreeNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | ///
6 | /// Binary search tree node.
7 | /// Contains left node which content less than this.Content
8 | /// Contains right node which content >= this.Content
9 | ///
10 | /// Type of content
11 | public class BinarySearchTreeNode : ITreeNode> where T : IComparable
12 | {
13 | public T Content { get; set; }
14 | public BinarySearchTreeNode Parent { get; set; }
15 | public BinarySearchTreeNode Left { get; set; }
16 | public BinarySearchTreeNode Right { get; set; }
17 |
18 | public BinarySearchTreeNode(T content)
19 | {
20 | this.Content = content;
21 | }
22 |
23 | ///
24 | /// Has left child
25 | ///
26 | public virtual bool HasLeft
27 | {
28 | get { return this.Left != null; }
29 | }
30 |
31 | ///
32 | /// Has right child
33 | ///
34 | public virtual bool HasRight
35 | {
36 | get { return this.Right != null; }
37 | }
38 |
39 | ///
40 | /// Is this node - left child of its parent
41 | ///
42 | public bool IsLeftChild
43 | {
44 | get { return this.Parent != null && this.Parent.Left == this; }
45 | }
46 |
47 | ///
48 | /// Is this node - right child of its parent
49 | ///
50 | public bool IsRightChild
51 | {
52 | get { return this.Parent != null && this.Parent.Right == this; }
53 | }
54 |
55 | ///
56 | /// Is this node terminate (leaf)
57 | ///
58 | public bool IsTerminate
59 | {
60 | get { return !this.HasRight && !this.HasLeft; }
61 | }
62 |
63 | ///
64 | /// Is this node has parent
65 | ///
66 | public virtual bool HasParent
67 | {
68 | get { return this.Parent != null; }
69 | }
70 |
71 | ///
72 | /// Count of node's subtree (+ current node)
73 | ///
74 | public int Count
75 | {
76 | get { return 1 + (this.Left?.Count ?? 0) + (this.Right?.Count ?? 0); }
77 | }
78 |
79 | ///
80 | /// Height of the node (0 for leaf)
81 | ///
82 | public virtual int Height
83 | {
84 | get { return this.GetHeight(this); }
85 | set { }
86 | }
87 |
88 | ///
89 | /// Degree of outgoing nodes
90 | ///
91 | public int Degree
92 | {
93 | get { return (this.HasLeft ? 1 : 0) + (this.HasRight ? 1 : 0); }
94 | }
95 |
96 | public int Depth
97 | {
98 | get
99 | {
100 | if (this.Parent == null)
101 | {
102 | return 0;
103 | }
104 |
105 | return 1 + this.Parent.Depth;
106 | }
107 | }
108 |
109 | public int Level
110 | {
111 | get { return this.Depth + 1; }
112 | }
113 |
114 | public BinarySearchTreeNode Sibling
115 | {
116 | get
117 | {
118 | return this.IsRightChild
119 | ? this.Parent.Left
120 | : this.Parent?.Right;
121 | }
122 | }
123 |
124 | public BinarySearchTreeNode Uncle
125 | {
126 | get { return this.Parent?.Sibling; }
127 | }
128 |
129 | public BinarySearchTreeNode Grandparent
130 | {
131 | get { return this.Parent?.Parent; }
132 | }
133 |
134 | private int GetHeight(BinarySearchTreeNode node)
135 | {
136 | if (node.IsTerminate)
137 | {
138 | return 0;
139 | }
140 |
141 | var leftHeight = node.Left?.Height ?? 0;
142 | var rightHeight = node.Right?.Height ?? 0;
143 |
144 | return 1 + Math.Max(leftHeight, rightHeight);
145 | }
146 |
147 | public int CompareTo(ITreeNode> other)
148 | {
149 | return this.Content != null && other != null
150 | ? this.Content.CompareTo(other.Content)
151 | : -1;
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/ITree.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | ///
6 | /// Tree - abstract data type that simulates a hierarchical tree structure with a root value
7 | /// and subtrees of children with a parent node, represented as a set of linked nodes.
8 | ///
9 | /// Can be defined recursively as a collection of the nodes (starting as a root node)
10 | /// where each node is a data structure consisting of a value together with a list of references to the nodes ("children")
11 | /// with the constraint that no reference is duplicated and none points to the root.
12 | ///
13 | /// Altenativaly: connected grapth without cylcles, edges are not oriented and without weight.
14 | ///
15 | /// Restrictions:
16 | /// 1. Root node cannot reference to itself - root couldn't has a parent
17 | /// 2. No Cycles - node can have only 1 parent
18 | /// 3. Connected parts - only 1 root.
19 | ///
20 | /// Definitions:
21 | /// Root - top node of a tree
22 | /// Child - A node directly connected to another when moving away from the root
23 | /// Parent - converse notation of the Child
24 | /// Siblings - group of nodes with the same parent
25 | /// Descendant - node reachable by repeated proceeding from parent to child
26 | /// Ascendant - node reachable by repeated proceeding from child to parent
27 | /// Leaf (external node) - node without children
28 | /// Branch (internal node) - node with at least one child
29 | /// Edge - connection between nodes
30 | /// Path - sequence of nodes and edges connecting node with descendant
31 | /// Height of node = number of edges on the longest path between node and a leaf
32 | /// Height of tree = height of its root node
33 | /// Forest - set of n >= 0 disjoing trees
34 | ///
35 | /// Definitions for balancing:
36 | /// Balance Factor of node = Height(node.Right) - Height(node.Left)
37 | ///
38 | ///
39 | /// Common usage:
40 | /// Representing hierarchical data
41 | /// Storing data in a way that makes it efficiently searchable
42 | /// Representing sorted lists of data
43 | /// As a workflow for compositing digital images for visual effects
44 | /// Routing algorithms
45 | ///
46 | public interface ITree where T : IComparable
47 | where NodeType : ITreeNode
48 | where TreeType : ITree
49 | {
50 | NodeType Root { get; set; }
51 |
52 | bool Insert(T content);
53 | NodeType Find(T content);
54 | bool Remove(T content);
55 | void Traverse(TraverseDirection direction, Action action, bool iterativeImplementation = false);
56 | bool Verify();
57 | T GetMin();
58 | T GetMax();
59 | NodeType GetPredecessor(T key);
60 | NodeType GetSuccessor(T key);
61 | T GetKElementInOrder(int index);
62 | TreeType SplitByKey(T key);
63 | void MergeWith(TreeType treeToMerge);
64 | void RotateLeft();
65 | void RotateRight();
66 | NodeType GetCommonRoot(T nodeContent1, T nodeContent2);
67 | int DistanceBetween(T nodeContent1, T nodeContent2);
68 | }
69 |
70 | public enum TraverseDirection
71 | {
72 | // Depth first:
73 | Infix,
74 | Prefix,
75 | Postfix,
76 | // Breadth first:
77 | Breadth
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/ITreeNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | ///
6 | /// Tree node.
7 | ///
8 | /// Definitions:
9 | /// Height = number of edges on the longest path between node and a leaf
10 | /// Degree = number of subtrees of the node
11 | /// Depth = number of edges from the root to the node
12 | /// Level = 1 + (number of connections between node and the root) = 1 + Depth
13 | ///
14 | /// Type of content
15 | public interface ITreeNode : IComparable>
16 | where T : IComparable
17 | where NodeType : ITreeNode
18 | {
19 | T Content { get; set; }
20 | NodeType Parent { get; set; }
21 |
22 | bool HasParent { get; }
23 | bool IsTerminate { get; }
24 | int Count { get; }
25 | int Height { get; }
26 | int Degree { get; }
27 | int Depth { get; }
28 | int Level { get; }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/RedBlackTree.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | ///
6 | /// Self-balansing binary search tree.
7 | /// Root is always black
8 | /// All leaves (NIL) are black
9 | /// Both children of red node are black
10 | /// Every path from a given node to any of its descendant NIL nodes contains the same number of black nodes.
11 | ///
12 | /// It leads to the critical property:
13 | /// The path from the root to the farthest leaf is no more than twice as long as
14 | /// the path form the root to the nearest leaf.
15 | /// Result of that - rought height-balanced.
16 | /// It leads that worst case of Inserting/Searching/Removing to be more efficient unlike
17 | ///
18 | /// Definitions:
19 | /// Black depth of node = number of black nodes from the root to a node
20 | /// Black height of RB tree = uniform number of black nodes in all paths from root to leaves
21 | /// Add: O(log n)
22 | /// Search: O(log n)
23 | /// Remove: O(log n)
24 | ///
25 | /// Type of data
26 | ///
27 | /// Is height-balanced, not weight-balanced.
28 | /// So sibling nodes can have hugely differing numbers of descendants
29 | ///
30 | public class RedBlackTree : BinarySearchTree> where T : IComparable
31 | {
32 | ///
33 | /// Insert content with balancing
34 | ///
35 | /// Content to insert
36 | /// Does element was added
37 | public override bool Insert(T content)
38 | {
39 | if (this.Root == null)
40 | {
41 | this.Root = new RedBlackTreeNode(content, NodeColor.Black);
42 | return true;
43 | }
44 |
45 | if (this.FindIn(this.Root, content) != null)
46 | {
47 | return false;
48 | }
49 |
50 | var insertedNode = new RedBlackTreeNode(content, NodeColor.Red);
51 | base.InsertNodeTo(this.Root, insertedNode);
52 | this.UpdateColorOnInsert(insertedNode);
53 |
54 | return true;
55 | }
56 |
57 | public override void MergeWith(RedBlackTree treeToMerge)
58 | {
59 | throw new NotSupportedException("Merge RB trees currently doesn't supported");
60 | }
61 |
62 | public override RedBlackTree SplitByKey(T key)
63 | {
64 | throw new NotSupportedException("Splitting RB trees currently doesn't supported");
65 | }
66 |
67 | ///
68 | /// Manual rotation doesn't allowed in RB tree
69 | ///
70 | public override void RotateLeft()
71 | {
72 | throw new NotSupportedException("Manual rotating RB trees currently doesn't supported");
73 | }
74 |
75 | ///
76 | /// Manual rotation doesn't allowed in RB tree
77 | ///
78 | public override void RotateRight()
79 | {
80 | throw new NotSupportedException("Manual rotating RB trees currently doesn't supported");
81 | }
82 |
83 | ///
84 | /// Verifying RB tree node
85 | ///
86 | /// Tree node
87 | /// Tree min node
88 | /// Tree max node
89 | /// True if RB tree node is valid
90 | protected override bool VerifyIn(BinarySearchTreeNode node, BinarySearchTreeNode min = null, BinarySearchTreeNode max = null)
91 | {
92 | var redBlackNode = node as RedBlackTreeNode;
93 | var left = node.Left as RedBlackTreeNode;
94 | var right = node.Right as RedBlackTreeNode;
95 | var root = this.Root as RedBlackTreeNode;
96 |
97 | var isColorMatching = redBlackNode.IsRed
98 | ? ((!node.HasLeft || left.IsBlack) && (!node.HasRight || right.IsBlack))
99 | : true;
100 |
101 | return root.IsBlack
102 | && isColorMatching
103 | && (left?.BlackHeight ?? 1) == (right?.BlackHeight ?? 1)
104 | && base.VerifyIn(node, min, max);
105 | }
106 |
107 | protected override void Remove(BinarySearchTreeNode node)
108 | {
109 | if (node.HasRight && node.HasLeft)
110 | {
111 | var leftHeight = node.Left?.Height ?? 0;
112 | var rightHeight = node.Right?.Height ?? 0;
113 | var nodeToReplace = leftHeight > rightHeight
114 | ? this.GetPredecessor(node.Content)
115 | : this.GetSuccessor(node.Content);
116 |
117 | node.Content = nodeToReplace.Content;
118 | node = nodeToReplace;
119 | }
120 |
121 | // has 1 or 0 child
122 | var redBlackNode = node as RedBlackTreeNode;
123 |
124 | // if red and has no more than 1 child - it hasn't child
125 | if (redBlackNode.IsRed)
126 | {
127 | this.RemoveLeaf(node);
128 | return;
129 | }
130 |
131 | // node is black
132 | var child = (node.HasLeft
133 | ? node.Left
134 | : node.Right) as RedBlackTreeNode;
135 |
136 | // if black node has only 1 red child - copy content and remove child
137 | // (red child cannot contain any nodes)
138 | if (child != null && child.IsRed)
139 | {
140 | node.Content = child.Content;
141 | this.RemoveLeaf(child);
142 | return;
143 | }
144 |
145 | // node is black and no childs (black node cannot has just 1 black child)
146 | this.UpdateColorOnRemove(redBlackNode);
147 | this.RemoveLeaf(node);
148 | }
149 |
150 | private void UpdateColorOnInsert(RedBlackTreeNode node)
151 | {
152 | if (node == this.Root)
153 | {
154 | node.Color = NodeColor.Black;
155 | return;
156 | }
157 |
158 | node.Color = NodeColor.Red;
159 |
160 | var parent = node.Parent as RedBlackTreeNode;
161 | // if parent is black then nothing to do - all properties are still valid
162 | if (parent.IsBlack)
163 | {
164 | return;
165 | }
166 |
167 | // else we have parent as red so node has grandparent and uncle (uncle can be NIL)
168 | var uncle = node.Uncle as RedBlackTreeNode;
169 | var grandParent = node.Grandparent as RedBlackTreeNode;
170 | if (uncle != null && uncle.IsRed)
171 | {
172 | // if parent and uncle boths reds then recoloring them to black
173 | // and recoloring grandparent to red
174 | parent.Color = NodeColor.Black;
175 | uncle.Color = NodeColor.Black;
176 | this.UpdateColorOnInsert(grandParent);
177 | }
178 | else
179 | {
180 | // parent is red and uncle is black (real or NIL)
181 | // rotating of node "between" parent and uncle in ordering
182 | if (node.IsRightChild && node.Parent.IsLeftChild)
183 | {
184 | parent = this.RotateLeft(node.Parent) as RedBlackTreeNode;
185 | node = parent.Left as RedBlackTreeNode;
186 | }
187 | else if (node.IsLeftChild && node.Parent.IsRightChild)
188 | {
189 | parent = this.RotateRight(node.Parent) as RedBlackTreeNode;
190 | node = parent.Right as RedBlackTreeNode;
191 | }
192 |
193 | // parent is red and uncle is black (real or NIL) and node is greater or lesser boths
194 | // then rotating tree in the grandparent
195 | grandParent.Color = NodeColor.Red;
196 | parent.Color = NodeColor.Black;
197 | if (node.IsLeftChild && node.Parent.IsLeftChild)
198 | {
199 | this.RotateRight(node.Grandparent);
200 | }
201 | else
202 | {
203 | this.RotateLeft(node.Grandparent);
204 | }
205 | }
206 | }
207 |
208 | private void UpdateColorOnRemove(RedBlackTreeNode node)
209 | {
210 | if (!node.HasParent)
211 | {
212 | return;
213 | }
214 |
215 | // node is black
216 | var parent = node.Parent as RedBlackTreeNode;
217 | var sibling = node.Sibling as RedBlackTreeNode;
218 |
219 | if (sibling != null && sibling.IsRed)
220 | {
221 | sibling.Color = NodeColor.Black;
222 | parent.Color = NodeColor.Red;
223 |
224 | if (sibling.IsRightChild)
225 | {
226 | this.RotateLeft(parent);
227 | sibling = parent.Right as RedBlackTreeNode;
228 | }
229 | else
230 | {
231 | this.RotateRight(parent);
232 | sibling = parent.Left as RedBlackTreeNode;
233 | }
234 | }
235 |
236 | // after that sibling is black
237 |
238 | // if node, parent and sibling is black and terminate - recolor sibling to red and update color of parent
239 | if (parent.IsBlack && sibling.IsBlack && sibling.IsTerminate)
240 | {
241 | sibling.Color = NodeColor.Red;
242 | UpdateColorOnRemove(parent);
243 | return;
244 | }
245 |
246 | // if parent is red, sibling is black nd terminate - just recolor and that's all
247 | if (parent.IsRed && sibling.IsBlack && sibling.IsTerminate)
248 | {
249 | parent.Color = NodeColor.Black;
250 | sibling.Color = NodeColor.Red;
251 | return;
252 | }
253 |
254 | var leftChildOfSibling = sibling.Left as RedBlackTreeNode;
255 | var rightChildOfSibling = sibling.Right as RedBlackTreeNode;
256 | // cases when sibling has one red child "between"
257 | if (node.IsLeftChild
258 | && rightChildOfSibling == null
259 | && leftChildOfSibling != null
260 | && leftChildOfSibling.IsRed)
261 | {
262 | sibling.Color = NodeColor.Red;
263 | leftChildOfSibling.Color = NodeColor.Black;
264 | this.RotateRight(sibling);
265 | sibling = sibling.Parent as RedBlackTreeNode;
266 | }
267 |
268 | if (node.IsRightChild
269 | && leftChildOfSibling == null
270 | && rightChildOfSibling != null
271 | && rightChildOfSibling.IsRed)
272 | {
273 | sibling.Color = NodeColor.Red;
274 | rightChildOfSibling.Color = NodeColor.Black;
275 | this.RotateLeft(sibling);
276 | sibling = sibling.Parent as RedBlackTreeNode;
277 | }
278 |
279 | rightChildOfSibling = sibling.Right as RedBlackTreeNode;
280 | leftChildOfSibling = sibling.Left as RedBlackTreeNode;
281 | if (node.IsLeftChild
282 | && rightChildOfSibling != null
283 | && rightChildOfSibling.IsRed)
284 | {
285 | sibling.Color = parent.Color;
286 | parent.Color = NodeColor.Black;
287 | rightChildOfSibling.Color = NodeColor.Black;
288 | this.RotateLeft(parent);
289 | }
290 | else if (node.IsRightChild
291 | && leftChildOfSibling != null
292 | && leftChildOfSibling.IsRed)
293 | {
294 | sibling.Color = parent.Color;
295 | parent.Color = NodeColor.Black;
296 | leftChildOfSibling.Color = NodeColor.Black;
297 | this.RotateRight(parent);
298 | }
299 | }
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/Algorithms/DataStructures/Tree/RedBlackTreeNode.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.DataStructures.Tree
4 | {
5 | public enum NodeColor
6 | {
7 | Red,
8 | Black
9 | }
10 |
11 | ///
12 | /// Red black tree node.
13 | /// Contains left node which content less than this.Content
14 | /// Contains right node which content >= this.Content
15 | ///
16 | /// Type of content
17 | public class RedBlackTreeNode : BinarySearchTreeNode where T : IComparable
18 | {
19 | public RedBlackTreeNode(T content, NodeColor color)
20 | : base(content)
21 | {
22 | this.Color = color;
23 | }
24 |
25 | public NodeColor Color { get; set; }
26 |
27 | public bool IsRed
28 | {
29 | get { return this.Color == NodeColor.Red; }
30 | }
31 |
32 | public bool IsBlack
33 | {
34 | get { return this.Color == NodeColor.Black; }
35 | }
36 |
37 | public int BlackHeight
38 | {
39 | get
40 | {
41 | var thisNodeBlackAdditionalHeight = this.IsBlack ? 1 : 0;
42 | if (this.IsTerminate)
43 | {
44 | return 1 + thisNodeBlackAdditionalHeight;
45 | }
46 |
47 | if (this.HasLeft)
48 | {
49 | return (this.Left as RedBlackTreeNode).BlackHeight + thisNodeBlackAdditionalHeight;
50 | }
51 | else
52 | {
53 | return (this.Right as RedBlackTreeNode).BlackHeight + thisNodeBlackAdditionalHeight;
54 | }
55 | }
56 | }
57 |
58 | public override bool HasLeft
59 | {
60 | get
61 | {
62 | return this.Left is RedBlackTreeNode;
63 | }
64 | }
65 |
66 | public override bool HasRight
67 | {
68 | get
69 | {
70 | return this.Right is RedBlackTreeNode;
71 | }
72 | }
73 |
74 | public override bool HasParent
75 | {
76 | get
77 | {
78 | return this.Parent is RedBlackTreeNode;
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Algorithms/Helpers/PrimeList.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Algorithms.Helpers
4 | {
5 | public static class PrimeList
6 | {
7 | public static int GetNextPrime(int currentPrime)
8 | {
9 | var found = false;
10 | var nextPrime = currentPrime;
11 | while (!found)
12 | {
13 | nextPrime++;
14 | found = isPrime(nextPrime);
15 | }
16 |
17 | return nextPrime;
18 | }
19 |
20 | private static bool isPrime(int number)
21 | {
22 | if (number < 2)
23 | {
24 | return false;
25 | }
26 |
27 | if (number == 2)
28 | {
29 | return true;
30 | }
31 |
32 | var isPrime = true;
33 | for (int i = 2; i < Math.Max(Math.Sqrt(number), 3); i++)
34 | {
35 | if (number % i == 0)
36 | {
37 | isPrime = false;
38 | break;
39 | }
40 | }
41 |
42 | return isPrime;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Algorithms/Helpers/SortHelper.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Helpers
2 | {
3 | static class SortHelper
4 | {
5 | public static void swap(T[] array, int i, int j)
6 | {
7 | if (i == j || i < 0 || j < 0 || i >= array.Length || j >= array.Length)
8 | {
9 | return;
10 | }
11 |
12 | T temp = array[i];
13 | array[i] = array[j];
14 | array[j] = temp;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Algorithms/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Algorithms")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Algorithms")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("80fa8f11-8329-4c23-891c-bd4f9fadaa91")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/ISorter.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.SortAlgorithms
2 | {
3 | ///
4 | /// O upper limit accurate assessment is unknown less or equals
5 | /// o upper limit not an accurate assessment less
6 | /// Theta upper, bottom limit equals
7 | /// Omega big bottom limit accurate assessment is unknown greater or equals
8 | /// Omega small bottom limit not an accurate assessment greater
9 | ///
10 | /// Stabtility - maintain the relative order of records with equal keys (values)
11 | /// Adaptability - whether or not the presortedness of the input affects the running time
12 | /// In-place - transforms input without additional data structures, only additional flat variables. Input usually overwrittern by output.
13 | ///
14 | /// Binary search tree:
15 | /// 1. Depth D or D-1
16 | /// 2. Value in vertex greater or equals than its leafs
17 | /// Implementation in array:
18 | /// A[i] >= A[2i + 1]
19 | /// A[i] >= A[2i + 2], 0 <= i <= n/2
20 | ///
21 | /// Type of array's elements
22 | public interface ISorter
23 | {
24 | void sort(T[] array);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/NonComparison/BucketSorter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.SortAlgorithms
4 | {
5 | ///
6 | /// Place items in the backet
7 | /// Best: Omega(n + k)
8 | /// Average: Theta(n + k)
9 | /// Worst: O(n^2)
10 | /// Additional memory: n + k
11 | /// where 0 < a[i] < k
12 | ///
13 | public class BucketSorter : ISorter
14 | {
15 | public void sort(int[] array)
16 | {
17 | if (array.Length < 2)
18 | {
19 | return;
20 | }
21 |
22 | var maxValue = array[0];
23 | var minValue = array[0];
24 |
25 | for (var i = 1; i < array.Length; i++) // find min and max to understand how much backets we need
26 | {
27 | if (array[i] > maxValue)
28 | {
29 | maxValue = array[i];
30 | }
31 |
32 | if (array[i] < minValue)
33 | {
34 | minValue = array[i];
35 | }
36 | }
37 |
38 | IList[] buckets = new List[maxValue - minValue + 1]; // creating buckets
39 | for (var i = 0; i < buckets.Length; i++)
40 | {
41 | buckets[i] = new List();
42 | }
43 |
44 | for (var i = 0; i < array.Length; i++) // put items to the buckets
45 | {
46 | buckets[array[i] - minValue].Add(array[i]);
47 | }
48 |
49 | int position = 0;
50 | for (var i = 0; i < buckets.Length; i++) // place items back to array
51 | {
52 | if (buckets[i].Count > 0)
53 | {
54 | for (var j = 0; j < buckets[i].Count; j++)
55 | {
56 | array[position] = buckets[i][j];
57 | position++;
58 | }
59 | }
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/NonComparison/CountingSorter.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.SortAlgorithms
2 | {
3 | ///
4 | /// Count how much items we have for each number
5 | /// Best: n + k
6 | /// Average: n + k
7 | /// Worst: n + k
8 | /// Additional memory: n + k
9 | /// where 0 < a[i] < k
10 | ///
11 | ///
12 | /// Unstable
13 | ///
14 | public class CountingSorter : ISorter
15 | {
16 | public void sort(int[] array)
17 | {
18 | if (array.Length < 2)
19 | {
20 | return;
21 | }
22 |
23 | var maxValue = array[0];
24 | var minValue = array[0];
25 |
26 | for (var i = 1; i < array.Length; i++) // find min and max to understand how much array length
27 | {
28 | if (array[i] > maxValue)
29 | {
30 | maxValue = array[i];
31 | }
32 |
33 | if (array[i] < minValue)
34 | {
35 | minValue = array[i];
36 | }
37 | }
38 |
39 | int[] counter = new int[maxValue - minValue + 1];
40 | for (var i = 0; i < counter.Length; i++)
41 | {
42 | counter[i] = 0;
43 | }
44 |
45 | for (var i = 0; i < array.Length; i++) // put items to the counter
46 | {
47 | counter[array[i] - minValue]++;
48 | }
49 |
50 | int position = 0;
51 | for (var i = 0; i < counter.Length; i++) // place items back to array
52 | {
53 | while (counter[i] > 0)
54 | {
55 | array[position] = i + minValue;
56 | position++;
57 | counter[i]--;
58 | }
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/NonComparison/CountingStableSorter.cs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.SortAlgorithms
2 | {
3 | ///
4 | /// Count how much items we have for each number
5 | /// Best: n + k
6 | /// Average: n + k
7 | /// Worst: n + k
8 | /// Additional memory: n + k
9 | /// where 0 < a[i] < k
10 | ///
11 | ///
12 | /// Stable
13 | ///
14 | public class CountingStableSorter : ISorter
15 | {
16 | public void sort(int[] array)
17 | {
18 | if (array.Length < 2)
19 | {
20 | return;
21 | }
22 |
23 | var maxValue = array[0];
24 | var minValue = array[0];
25 |
26 | for (var i = 1; i < array.Length; i++) // find min and max to understand how much array length
27 | {
28 | if (array[i] > maxValue)
29 | {
30 | maxValue = array[i];
31 | }
32 |
33 | if (array[i] < minValue)
34 | {
35 | minValue = array[i];
36 | }
37 | }
38 |
39 | int[] counter = new int[maxValue - minValue + 1];
40 | for (var i = 0; i < counter.Length; i++)
41 | {
42 | counter[i] = 0;
43 | }
44 |
45 | for (var i = 0; i < array.Length; i++) // put items to the counter
46 | {
47 | counter[array[i] - minValue]++;
48 | }
49 |
50 | for (var i = 1; i < counter.Length; i++)
51 | {
52 | counter[i] += counter[i - 1];
53 | }
54 |
55 | var resultArray = new int[array.Length];
56 | for (var i = array.Length - 1; i >= 0; i--) // place items back to array
57 | {
58 | counter[array[i] - minValue]--;
59 | resultArray[counter[array[i] - minValue]] = array[i];
60 | }
61 |
62 | for (var i = 0; i < array.Length; i++) // put items to the counter
63 | {
64 | array[i] = resultArray[i];
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/NonComparison/LSDRadixSorter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Algorithms.SortAlgorithms
5 | {
6 | ///
7 | /// LSD - least significant digit
8 | /// Best: O(wn)
9 | /// Average: O(wn)
10 | /// Worst: O(wn)
11 | /// Additional memory: w + n
12 | /// where w - word size
13 | ///
14 | ///
15 | /// Applicable for numbers: 1, 2, 3, 10, 15
16 | /// Supports sorting negative numbers
17 | ///
18 | public class LSDRadixSorter : ISorter
19 | {
20 | public void sort(int[] array)
21 | {
22 | List negativeNumbers = new List();
23 | List positiveNumbers = new List();
24 |
25 | for (var i = 0; i < array.Length; i++)
26 | {
27 | if (array[i] >= 0)
28 | {
29 | positiveNumbers.Add(array[i]);
30 | }
31 | else
32 | {
33 | negativeNumbers.Add(-array[i]);
34 | }
35 | }
36 |
37 | this.internalSort(positiveNumbers);
38 | this.internalSort(negativeNumbers);
39 |
40 | var position = 0;
41 | for (var i = negativeNumbers.Count - 1; i >= 0; i--)
42 | {
43 | array[position] = -negativeNumbers[i];
44 | position++;
45 | }
46 |
47 | for (var i = 0; i < positiveNumbers.Count; i++)
48 | {
49 | array[position] = positiveNumbers[i];
50 | position++;
51 | }
52 | }
53 |
54 | private void internalSort(List array)
55 | {
56 | bool isFinished = false;
57 | int digitPosition = 0;
58 |
59 | Queue[] buckets = new Queue[10];
60 | for (int i = 0; i < buckets.Length; i++)
61 | {
62 | buckets[i] = new Queue();
63 | }
64 |
65 | while (!isFinished)
66 | {
67 | isFinished = true;
68 |
69 | foreach (int value in array)
70 | {
71 | int bucketNumber = (value / (int)Math.Pow(10, digitPosition)) % 10;
72 | if (bucketNumber > 0)
73 | {
74 | isFinished = false;
75 | }
76 |
77 | buckets[bucketNumber].Enqueue(value);
78 | }
79 |
80 | int i = 0;
81 | foreach (var bucket in buckets)
82 | {
83 | while (bucket.Count > 0)
84 | {
85 | array[i] = bucket.Dequeue();
86 | i++;
87 | }
88 | }
89 |
90 | digitPosition++;
91 | }
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/NonComparison/MSDRadixSorter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Algorithms.SortAlgorithms
4 | {
5 | ///
6 | /// MSD - most significant digit
7 | /// Best: O(wn)
8 | /// Average: O(wn)
9 | /// Worst: O(wn)
10 | /// Additional memory: w + n
11 | /// where w - word size
12 | ///
13 | ///
14 | /// Applicable for string: b, ba, c, d, e, f, g, h, i, j
15 | /// - Recursive
16 | /// - If w is small and alphabet is big - many space is wasting
17 | ///
18 | public class MSDRadixSorter : ISorter
19 | {
20 | public void sort(string[] array)
21 | {
22 | this.internalSort(array, 0);
23 | }
24 |
25 | private void internalSort(string[] array, int charPosition)
26 | {
27 | if (array.Length <= 1)
28 | {
29 | return;
30 | }
31 |
32 | List[] buckets = new List[128];
33 | for (var i = 0; i < buckets.Length; i++)
34 | {
35 | buckets[i] = new List();
36 | }
37 |
38 | foreach (string value in array)
39 | {
40 | int bucketNumber = value.Length > charPosition
41 | ? value[charPosition]
42 | : 0;
43 |
44 | buckets[bucketNumber].Add(value);
45 | }
46 |
47 | charPosition++;
48 | int position = 0;
49 | foreach (var bucket in buckets)
50 | {
51 | if (bucket.Count > 0)
52 | {
53 | var sortedBucket = bucket.ToArray();
54 | this.internalSort(sortedBucket, charPosition);
55 |
56 | foreach (var item in sortedBucket)
57 | {
58 | array[position] = item;
59 | position++;
60 | }
61 | }
62 | }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Algorithms/SortAlgorithms/Stable/BubbleSorter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Algorithms.Helpers;
3 |
4 | namespace Algorithms.SortAlgorithms
5 | {
6 | ///
7 | /// Best: O(n)
8 | /// Average: O(n^2)
9 | /// Worst: O(n^2)
10 | /// Additional memory: 1
11 | ///
12 | ///
13 | /// Stable
14 | ///
15 | /// Type of array's elements
16 | public class BubbleSorter : ISorter