├── .editorconfig
├── .github
└── workflows
│ ├── directory_md.yml
│ └── tests.yml
├── .gitignore
├── Algorithms.Tests
├── Algorithms.Tests.fsproj
├── DataStructures
│ ├── AVLTree.fs
│ ├── Treap.fs
│ └── Trie.fs
├── Math
│ ├── AbsMaxTests.fs
│ ├── AbsMinTests.fs
│ ├── AbsTests.fs
│ ├── AverageTests.fs
│ ├── FactorialTests.fs
│ ├── PerfectNumbersTests.fs
│ ├── PowerTests.fs
│ └── PrimeTests.fs
├── Program.fs
├── Search
│ └── BinarySearchTests.fs
└── Strings
│ ├── CapitalizeTests.fs
│ ├── CheckAnagramsTests.fs
│ ├── CheckPangramTests.fs
│ ├── IsPalindromeTests.fs
│ ├── JaroWinklerTests.fs
│ ├── KnuthMorrisPrattTests.fs
│ ├── LevenshteinDistanceTests.fs
│ ├── LowerTests.fs
│ ├── ManacherTests.fs
│ ├── MinCostStringConversionTests.fs
│ ├── NaiveStringSearchTests.fs
│ ├── PrefixFunctionTests.fs
│ ├── RabinKarpTests.fs
│ ├── RemoveDuplicatesTests.fs
│ ├── ReverseLettersTests.fs
│ ├── ReverseWordsTests.fs
│ ├── SplitTests.fs
│ ├── SwapCaseTests.fs
│ ├── UpperTests.fs
│ ├── WordOccurrenceTests.fs
│ └── ZFunctionTests.fs
├── Algorithms
├── Algorithms.fsproj
├── DataStructures
│ ├── AVLTree.fs
│ ├── Treap.fs
│ └── Trie.fs
├── Math
│ ├── Abs.fs
│ ├── AbsMax.fs
│ ├── AbsMin.fs
│ ├── Average.fs
│ ├── Factorial.fs
│ ├── Fibonacci.fs
│ ├── Greatest_Common_Divisor.fs
│ ├── Perfect_Numbers.fs
│ ├── Power.fs
│ └── Prime.fs
├── Search
│ └── BinarySearch.fs
├── Sort
│ ├── Bubble_Sort.fs
│ ├── Comb_Sort.fs
│ ├── Cycle_Sort.fs
│ ├── Gnome_Sort.fs
│ ├── Heap_Sort.fs
│ ├── Insertion_Sort.fs
│ ├── Merge_Sort.fs
│ ├── Pancake_Sort.fs
│ └── Quick_Sort.fs
└── Strings
│ ├── Capitalize.fs
│ ├── CheckAnagrams.fs
│ ├── CheckPangram.fs
│ ├── HasPrefix.fs
│ ├── HasSuffix.fs
│ ├── IsPalindrome.fs
│ ├── JaroWinkler.fs
│ ├── KnuthMorrisPratt.fs
│ ├── LevenshteinDistance.fs
│ ├── Lower.fs
│ ├── Manacher.fs
│ ├── MinCostStringConversion.fs
│ ├── NaiveStringSearch.fs
│ ├── PrefixFunction.fs
│ ├── RabinKarp.fs
│ ├── RemoveDuplicates.fs
│ ├── ReverseLetters.fs
│ ├── ReverseWords.fs
│ ├── Split.fs
│ ├── SwapCase.fs
│ ├── Upper.fs
│ ├── WordOccurrence.fs
│ └── ZFunction.fs
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── DIRECTORY.md
├── F-Sharp.sln
├── LICENSE
└── README.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories
2 | root = true
3 |
4 | # F# files
5 | [*.fs]
6 |
7 | #### Core EditorConfig Options ####
8 |
9 | # Indentation and spacing
10 | indent_size = 4
11 | indent_style = space
12 | tab_width = 4
13 |
14 | # New line preferences
15 | end_of_line = crlf
16 | insert_final_newline = false
17 |
18 | #### .NET Coding Conventions ####
19 |
20 | # Organize usings
21 | dotnet_separate_import_directive_groups = true
22 | dotnet_sort_system_directives_first = true
23 |
--------------------------------------------------------------------------------
/.github/workflows/directory_md.yml:
--------------------------------------------------------------------------------
1 | name: directory_md
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | MainSequence:
6 | name: DIRECTORY.md
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v1 # v2 is broken for git diff
10 | - uses: actions/setup-python@v2
11 | - name: Setup Git Specs
12 | run: |
13 | git config --global user.name "$GITHUB_ACTOR"
14 | git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com"
15 | git remote set-url origin https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/$GITHUB_REPOSITORY
16 | - name: Update DIRECTORY.md
17 | shell: python
18 | run: |
19 | import os
20 | from typing import Iterator
21 | URL_BASE = "https://github.com/TheAlgorithms/F-Sharp/blob/main"
22 | g_output = []
23 | def good_filepaths(top_dir: str = ".") -> Iterator[str]:
24 | fs_exts = tuple(".fs".split())
25 | for dirpath, dirnames, filenames in os.walk(top_dir):
26 | dirnames[:] = [d for d in dirnames if d[0] not in "._"]
27 | for filename in filenames:
28 | if os.path.splitext(filename)[1].lower() in fs_exts:
29 | yield os.path.join(dirpath, filename).lstrip("./")
30 | def md_prefix(i):
31 | return f"{i * ' '}*" if i else "\n##"
32 | def print_path(old_path: str, new_path: str) -> str:
33 | global g_output
34 | old_parts = old_path.split(os.sep)
35 | for i, new_part in enumerate(new_path.split(os.sep)):
36 | if i + 1 > len(old_parts) or old_parts[i] != new_part:
37 | if new_part:
38 | g_output.append(f"{md_prefix(i)} {new_part.replace('_', ' ').title()}")
39 | return new_path
40 | def build_directory_md(top_dir: str = ".") -> str:
41 | global g_output
42 | old_path = ""
43 | for filepath in sorted(good_filepaths(), key=str.lower):
44 | filepath, filename = os.path.split(filepath)
45 | if filepath != old_path:
46 | old_path = print_path(old_path, filepath)
47 | indent = (filepath.count(os.sep) + 1) if filepath else 0
48 | url = "/".join((URL_BASE, filepath, filename)).replace(" ", "%20")
49 | filename = os.path.splitext(filename.replace("_", " ").title())[0]
50 | g_output.append(f"{md_prefix(indent)} [{filename}]({url})")
51 | return "# List of all files\n" + "\n".join(g_output)
52 | with open("DIRECTORY.md", "w") as out_file:
53 | out_file.write(build_directory_md(".") + "\n")
54 | - name: Commit DIRECTORY.md
55 | run: |
56 | git commit -m "updating DIRECTORY.md" DIRECTORY.md || true
57 | git diff DIRECTORY.md
58 | git push --force origin HEAD:$GITHUB_REF || true
59 |
--------------------------------------------------------------------------------
/.github/workflows/tests.yml:
--------------------------------------------------------------------------------
1 | name: Run tests on CI
2 |
3 | on: [workflow_dispatch, pull_request, push]
4 |
5 | jobs:
6 | run-tests:
7 | name: Run tests
8 | runs-on: ubuntu-22.04
9 | steps:
10 | - name: Checkout repo
11 | uses: actions/checkout@v3
12 | - name: Run tests
13 | run: dotnet test
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 | .idea/
--------------------------------------------------------------------------------
/Algorithms.Tests/Algorithms.Tests.fsproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | latest
5 | true
6 | false
7 | false
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | all
23 | runtime; build; native; contentfiles; analyzers; buildtransitive
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Algorithms.Tests/DataStructures/AVLTree.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.DataStructures
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.DataStructures.AVLTree
5 |
6 | []
7 | type AVLTreeTests() =
8 |
9 | let rec verifyBalance (maybeNode: Option) =
10 | match maybeNode with
11 | | None -> ()
12 | | Some node ->
13 | let bf = AVLNode.balanceFactor node
14 | Assert.IsTrue(bf >= -1 && bf <= 1, $"Balance factor {bf} is out of range")
15 | verifyBalance node.LeftChild
16 | verifyBalance node.RightChild
17 |
18 | let rec verifyHeights (maybeNode: Option) =
19 | match maybeNode with
20 | | None -> ()
21 | | Some node ->
22 | let leftHeight = AVLNode.height node.LeftChild
23 | let rightHeight = AVLNode.height node.RightChild
24 | Assert.AreEqual(node.Height, 1 + max leftHeight rightHeight)
25 |
26 | verifyHeights node.LeftChild
27 | verifyHeights node.RightChild
28 |
29 | let rec verifyBST (maybeNode: Option) : Option< (* Min *) int * (* Max*) int> =
30 | match maybeNode with
31 | | None -> None
32 | | Some node ->
33 | let maybeLeftMinMax = verifyBST node.LeftChild
34 | let maybeRightMinMax = verifyBST node.RightChild
35 | maybeLeftMinMax
36 | |> Option.iter (fun (_, leftMax) ->
37 | Assert.IsTrue(leftMax < node.Value, $"Left child {leftMax} is greater than parent {node.Value}")
38 | )
39 | maybeRightMinMax
40 | |> Option.iter (fun (rightMin, _) ->
41 | Assert.IsTrue(rightMin > node.Value, $"Right child {rightMin} is less than parent {node.Value}")
42 | )
43 | let minValue =
44 | maybeLeftMinMax
45 | |> Option.map fst
46 | |> Option.defaultValue node.Value
47 | let maxValue =
48 | maybeRightMinMax
49 | |> Option.map snd
50 | |> Option.defaultValue node.Value
51 | Some (minValue, maxValue)
52 |
53 | let verifyProperties (tree: AVLTree) =
54 | verifyBalance tree.Root
55 | verifyHeights tree.Root
56 | verifyBST tree.Root |> ignore
57 | tree
58 |
59 | []
60 | member _.``Empty tree has no root``() =
61 | let tree =
62 | empty
63 | |> verifyProperties
64 |
65 | Assert.IsTrue(tree.Root.IsNone)
66 |
67 | []
68 | member _.``Insert maintains AVL properties``() =
69 | let tree =
70 | empty
71 | |> verifyProperties
72 | |> insert 5
73 | |> verifyProperties
74 | |> insert 3
75 | |> verifyProperties
76 | |> insert 7
77 | |> verifyProperties
78 | |> insert 1
79 | |> verifyProperties
80 | |> insert 9
81 | |> verifyProperties
82 | |> insert 1
83 | |> verifyProperties
84 | ()
85 |
86 | []
87 | member _.``Right-heavy case triggers rotation``() =
88 | let tree =
89 | empty
90 | |> verifyProperties
91 | |> insert 1
92 | |> verifyProperties
93 | |> insert 2
94 | |> verifyProperties
95 | |> insert 3
96 | |> verifyProperties
97 |
98 | Assert.IsTrue(tree.Root.IsSome)
99 | let root = tree.Root.Value
100 | Assert.AreEqual(2, root.Value)
101 | Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
102 | Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
103 |
104 | []
105 | member _.``Left-heavy case triggers rotation``() =
106 | let tree =
107 | empty
108 | |> verifyProperties
109 | |> insert 3
110 | |> verifyProperties
111 | |> insert 2
112 | |> verifyProperties
113 | |> insert 1
114 | |> verifyProperties
115 |
116 | Assert.IsTrue(tree.Root.IsSome)
117 | let root = tree.Root.Value
118 | Assert.AreEqual(2, root.Value)
119 | Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
120 | Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
121 |
122 | []
123 | member _.``Double rotation for right-left case``() =
124 | let tree =
125 | empty
126 | |> verifyProperties
127 | |> insert 1
128 | |> verifyProperties
129 | |> insert 3
130 | |> verifyProperties
131 | |> insert 2
132 | |> verifyProperties
133 |
134 | Assert.IsTrue(tree.Root.IsSome)
135 | let root = tree.Root.Value
136 | Assert.AreEqual(2, root.Value)
137 | Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
138 | Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
139 |
140 | []
141 | member _.``Double rotation for left-right case``() =
142 | let tree =
143 | empty
144 | |> verifyProperties
145 | |> insert 3
146 | |> verifyProperties
147 | |> insert 1
148 | |> verifyProperties
149 | |> insert 2
150 | |> verifyProperties
151 |
152 | Assert.IsTrue(tree.Root.IsSome)
153 | let root = tree.Root.Value
154 | Assert.AreEqual(2, root.Value)
155 | Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
156 | Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
157 |
158 | []
159 | member _.``Duplicate insert is idempotent``() =
160 | let tree1 =
161 | empty
162 | |> verifyProperties
163 | |> insert 1
164 | |> verifyProperties
165 | |> insert 2
166 | |> verifyProperties
167 |
168 | let tree2 =
169 | insert 2 tree1
170 | |> verifyProperties
171 |
172 | Assert.AreEqual(tree1.Root |> Option.map (fun n -> n.Value),
173 | tree2.Root |> Option.map (fun n -> n.Value))
174 | []
175 | member _.``Delete maintains AVL properties``() =
176 | let tree =
177 | empty
178 | |> insert 5
179 | |> verifyProperties
180 | |> insert 3
181 | |> verifyProperties
182 | |> insert 7
183 | |> verifyProperties
184 | |> insert 1
185 | |> verifyProperties
186 | |> insert 9
187 | |> verifyProperties
188 | |> insert 4
189 | |> verifyProperties
190 | |> insert 6
191 | |> verifyProperties
192 | |> insert 8
193 | |> verifyProperties
194 | |> insert 2
195 | |> verifyProperties
196 | |> delete 5 // Delete root
197 | |> verifyProperties
198 | |> delete 1 // Delete leaf
199 | |> verifyProperties
200 | |> delete 7 // Delete node with one child
201 | |> verifyProperties
202 | |> delete 3 // Delete node with two children
203 | |> verifyProperties
204 |
205 | Assert.IsTrue(tree.Root.IsSome)
206 |
207 | []
208 | member _.``Delete from empty tree returns empty tree``() =
209 | let tree =
210 | empty
211 | |> delete 1
212 | |> verifyProperties
213 |
214 | Assert.IsTrue(tree.Root.IsNone)
215 |
216 | []
217 | member _.``Delete non-existent value maintains tree structure``() =
218 | let tree1 =
219 | empty
220 | |> insert 2
221 | |> verifyProperties
222 | |> insert 1
223 | |> verifyProperties
224 | |> insert 3
225 | |> verifyProperties
226 |
227 | let tree2 =
228 | tree1
229 | |> delete 4
230 | |> verifyProperties
231 |
232 | Assert.AreEqual(
233 | tree1.Root |> Option.map (fun n -> n.Value),
234 | tree2.Root |> Option.map (fun n -> n.Value)
235 | )
236 |
237 | []
238 | member _.``Complex deletion cases maintain balance``() =
239 | let tree =
240 | empty
241 | |> insert 50 // Create a more complex tree
242 | |> verifyProperties
243 | |> insert 25
244 | |> verifyProperties
245 | |> insert 75
246 | |> verifyProperties
247 | |> insert 10
248 | |> verifyProperties
249 | |> insert 35
250 | |> verifyProperties
251 | |> insert 60
252 | |> verifyProperties
253 | |> insert 90
254 | |> verifyProperties
255 | |> insert 5
256 | |> verifyProperties
257 | |> insert 15
258 | |> verifyProperties
259 | |> insert 30
260 | |> verifyProperties
261 | |> insert 40
262 | |> verifyProperties
263 | |> insert 55
264 | |> verifyProperties
265 | |> insert 65
266 | |> verifyProperties
267 | |> insert 80
268 | |> verifyProperties
269 | |> insert 95
270 | |> verifyProperties
271 |
272 | // Test various deletion patterns
273 | |> delete 50 // Delete root with two children
274 | |> verifyProperties
275 | |> delete 25 // Delete inner node with two children
276 | |> verifyProperties
277 | |> delete 5 // Delete leaf
278 | |> verifyProperties
279 | |> delete 95 // Delete leaf on opposite side
280 | |> verifyProperties
281 | |> delete 35 // Delete node with one child
282 | |> verifyProperties
283 | |> delete 75 // Delete node requiring rebalancing
284 | |> verifyProperties
285 |
286 | Assert.IsTrue(tree.Root.IsSome)
287 |
288 | []
289 | member _.``Sequential deletion maintains balance``() =
290 | let mutable tree = empty
291 |
292 | // Build tree with sequential inserts
293 | for i in 1..10 do
294 | tree <- insert i tree
295 | tree <- verifyProperties tree
296 |
297 | // Delete in reverse order
298 | for i in seq{10..(-1)..1} do
299 | tree <- delete i tree
300 | tree <- verifyProperties tree
301 |
302 | Assert.IsTrue(tree.Root.IsNone)
303 |
304 | []
305 | member _.``Random operations maintain AVL properties``() =
306 | let rng = System.Random(42)
307 | let mutable tree = empty
308 |
309 | // Random inserts
310 | for _ in 1..20 do
311 | let value = rng.Next(1, 100)
312 | tree <- insert value tree
313 | tree <- verifyProperties tree
314 |
315 | // Random deletes
316 | for _ in 1..10 do
317 | let value = rng.Next(1, 100)
318 | tree <- delete value tree
319 | tree <- verifyProperties tree
--------------------------------------------------------------------------------
/Algorithms.Tests/DataStructures/Treap.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.DataStructures
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.DataStructures.Treap
5 |
6 | []
7 | type TreapTests () =
8 |
9 | []
10 | member this.``Test basic operations``() =
11 | let treap =
12 | empty
13 | |> insert 5
14 | |> insert 3
15 | |> insert 7
16 |
17 | // Test getKthElement (0-based indexing)
18 | Assert.AreEqual(Some 3, getKthElement treap 0u)
19 | Assert.AreEqual(Some 5, getKthElement treap 1u)
20 | Assert.AreEqual(Some 7, getKthElement treap 2u)
21 | Assert.AreEqual(None, getKthElement treap 3u)
22 |
23 | // Test getIndex
24 | Assert.AreEqual(Some 0, getIndex treap 3)
25 | Assert.AreEqual(Some 1, getIndex treap 5)
26 | Assert.AreEqual(Some 2, getIndex treap 7)
27 | Assert.AreEqual(None, getIndex treap 4)
28 |
29 | []
30 | member this.``Test empty treap``() =
31 | let treap = empty
32 | Assert.AreEqual(None, getKthElement treap 0u)
33 | Assert.AreEqual(None, getIndex treap 5)
34 |
35 | []
36 | member this.``Test deletion``() =
37 | let mutable treap =
38 | empty
39 | |> insert 5
40 | |> insert 3
41 | |> insert 7
42 |
43 | // Delete middle element
44 | treap <- erase 5 treap
45 | Assert.AreEqual(Some 3, getKthElement treap 0u)
46 | Assert.AreEqual(Some 7, getKthElement treap 1u)
47 | Assert.AreEqual(None, getKthElement treap 2u)
48 |
49 | // Delete non-existent element
50 | treap <- erase 5 treap
51 | Assert.AreEqual(Some 3, getKthElement treap 0u)
52 | Assert.AreEqual(Some 7, getKthElement treap 1u)
53 |
54 | []
55 | member this.``Test duplicate insertion``() =
56 | let mutable treap = empty
57 | treap <- insert 3 treap
58 | treap <- insert 5 treap
59 | treap <- insert 1 treap
60 | treap <- insert 3 treap
61 |
62 | Assert.AreEqual(Some 1, getKthElement treap 0u)
63 | Assert.AreEqual(Some 3, getKthElement treap 1u)
64 | Assert.AreEqual(Some 5, getKthElement treap 2u)
65 | Assert.AreEqual(None, getKthElement treap 3u)
66 |
67 | treap <- erase 3 treap
68 | Assert.AreEqual(Some 1, getKthElement treap 0u)
69 | Assert.AreEqual(Some 5, getKthElement treap 1u)
70 | Assert.AreEqual(None, getKthElement treap 2u)
71 |
72 |
73 | []
74 | member this.``Test order preservation``() =
75 | let mutable treap = empty
76 |
77 | // Insert in non-sorted order
78 | treap <- insert 8 treap
79 | treap <- insert 3 treap
80 | treap <- insert 10 treap
81 | treap <- insert 1 treap
82 | treap <- insert 6 treap
83 | treap <- insert 4 treap
84 | treap <- insert 7 treap
85 | treap <- insert 14 treap
86 | treap <- insert 13 treap
87 |
88 | // Verify elements are retrievable in sorted order
89 | for i in 0u..8u do
90 | let expected =
91 | match i with
92 | | 0u -> 1 | 1u -> 3 | 2u -> 4 | 3u -> 6 | 4u -> 7
93 | | 5u -> 8 | 6u -> 10 | 7u -> 13 | 8u -> 14
94 | | _ -> failwith "Unexpected index"
95 | Assert.AreEqual(Some expected, getKthElement treap i)
96 |
--------------------------------------------------------------------------------
/Algorithms.Tests/DataStructures/Trie.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.DataStructures
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.DataStructures.Trie
5 |
6 | []
7 | type TrieTests () =
8 |
9 | []
10 | member this.``Test insertion and retrieval with strings``() =
11 | let mutable trie = empty
12 |
13 | trie <- insert "foo" trie
14 | Assert.IsTrue(search "foo" trie)
15 |
16 | trie <- insert "foobar" trie
17 | Assert.IsTrue(search "foobar" trie)
18 | Assert.IsTrue(search "foo" trie)
19 |
20 | trie <- insert "bar" trie
21 | Assert.IsTrue(search "bar" trie)
22 | Assert.IsFalse(search "baz" trie)
23 | Assert.IsFalse(search "foobarbaz" trie)
24 |
25 | []
26 | member this.``Test empty trie``() =
27 | let trie = empty
28 | Assert.IsFalse(search "foo" trie)
29 | Assert.IsFalse(search "" trie)
30 |
31 | []
32 | member this.``Test insert empty key``() =
33 | let trie =
34 | empty
35 | |> insert ""
36 |
37 | Assert.IsTrue(search "" trie)
38 | Assert.IsFalse(search "foo" trie)
39 |
40 | []
41 | member this.``Test overlapping keys``() =
42 | let trie =
43 | empty
44 | |> insert "car"
45 | |> insert "cart"
46 | |> insert "carter"
47 |
48 | Assert.IsTrue(search "car" trie)
49 | Assert.IsTrue(search "cart" trie)
50 | Assert.IsTrue(search "carter" trie)
51 | Assert.IsFalse(search "care" trie)
52 |
53 | []
54 | member this.``Test partial match``() =
55 | let trie =
56 | empty
57 | |> insert "apple"
58 |
59 | Assert.IsFalse(search "app" trie)
60 | Assert.IsFalse(search "appl" trie)
61 | Assert.IsTrue(search "apple" trie)
62 | Assert.IsFalse(search "applepie" trie)
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/AbsMaxTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type AbsMaxTests() =
8 |
9 | []
10 | member this.Test() =
11 | Assert.AreEqual(-3, AbsMax.absMax [ -1; 1; 2; -2; -3; 3 ])
12 | Assert.AreEqual(3, AbsMax.absMax [ 1; -1; 2; -2; 3; -3 ])
13 | Assert.AreEqual(-1, AbsMax.absMax [ 0; -1; 0 ])
14 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/AbsMinTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type AbsMinTests() =
8 |
9 | []
10 | member this.Test() =
11 | Assert.AreEqual(-1, AbsMin.absMin [ -1; 1; 2; -2; -3; 3 ])
12 | Assert.AreEqual(1, AbsMin.absMin [ 1; -1; 2; -2; 3; -3 ])
13 | Assert.AreEqual(0, AbsMin.absMin [ 0; -1; 0 ])
14 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/AbsTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type AbsTests() =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | member this.Test(input: int, expected: int) =
16 | let actual = Abs.absVal input
17 | Assert.AreEqual(expected, actual)
18 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/AverageTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type AverageTests() =
8 |
9 | []
10 | member this.Test() =
11 | Assert.AreEqual(None, Average.average List.empty)
12 | Assert.AreEqual(Some 2.0, Average.average [1.0; 2.0; 3.0])
13 | Assert.AreEqual(Some 1.0, Average.average [1.0])
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/FactorialTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type FactorialTests() =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 | member this.ValidInt(num: int, expected: int) =
19 | seq {
20 | Factorial.byFoldFunction
21 | Factorial.byReduceFunction
22 | Factorial.byRecursion
23 | Factorial.byTailRecursion
24 | Factorial.byTailRecursionGeneric
25 | }
26 | |> Seq.iter (fun func ->
27 | let actual = func num
28 | Assert.AreEqual(expected, actual))
29 |
30 | []
31 | []
32 | member this.InvalidInt(num: int) =
33 | seq {
34 | Factorial.byFoldFunction
35 | Factorial.byReduceFunction
36 | Factorial.byRecursion
37 | Factorial.byTailRecursion
38 | Factorial.byTailRecursionGeneric
39 | }
40 | |> Seq.iter (fun func ->
41 | let action =
42 | new System.Action(fun () -> func num |> ignore)
43 |
44 | Assert.ThrowsException(action) |> ignore)
45 |
46 | []
47 | member this.Generic() =
48 | Assert.AreEqual(479001600, Factorial.byTailRecursionGeneric 12)
49 | Assert.AreEqual(479001600u, Factorial.byTailRecursionGeneric 12u)
50 | Assert.AreEqual(479001600.f, Factorial.byTailRecursionGeneric 12.f)
51 | Assert.AreEqual(2432902008176640000L, Factorial.byTailRecursionGeneric 20L)
52 | Assert.AreEqual(2432902008176640000UL, Factorial.byTailRecursionGeneric 20UL)
53 | Assert.AreEqual(2432902008176640000., Factorial.byTailRecursionGeneric 20.)
54 | Assert.AreEqual(10888869450418352160768000000M, Factorial.byTailRecursionGeneric 27M)
55 |
56 | Assert.AreEqual(
57 | 30414093201713378043612608166064768844377641568960512000000000000I,
58 | Factorial.byTailRecursionGeneric 50I
59 | )
60 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/PerfectNumbersTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type PerfectNumbersTests() =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 | []
19 | []
20 | []
21 | []
22 | []
23 | []
24 | []
25 | member this.Test(n: int, expected: bool) =
26 | let actual = PerfectNumbers.isPerfect n
27 | Assert.AreEqual(expected, actual)
28 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/PowerTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type PowerTests() =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 | []
19 | []
20 | []
21 | member this.FoldFunction_Valid(num: int, pow: int, expected: int) =
22 | let actual = Power.byFoldFunction num pow
23 | Assert.AreEqual(expected, actual)
24 |
25 | []
26 | []
27 | []
28 | []
29 | []
30 | []
31 | []
32 | []
33 | []
34 | []
35 | []
36 | []
37 | []
38 | []
39 | []
40 | []
41 | []
42 | []
43 | []
44 | []
45 | []
46 | []
47 | []
48 | []
49 | []
50 | []
51 | []
52 | []
53 | []
54 | []
55 | member this.ByRecursion_Valid(num: int, pow: int, expected: int) =
56 | let actual = Power.byRecursion num pow
57 | Assert.AreEqual(expected, actual)
58 |
59 | []
60 | []
61 | []
62 | member this.ByRecursion_Invalid(num: int, pow: int) =
63 | let action =
64 | new System.Action(fun () -> Power.byRecursion num pow |> ignore)
65 |
66 | Assert.ThrowsException(action)
67 | |> ignore
68 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Math/PrimeTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Math
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Math
5 |
6 | []
7 | type PrimeTests() =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | []
18 | []
19 | []
20 | member this.IsPrime(input: int, expected: bool) =
21 | let actual = Prime.isPrime input
22 | Assert.AreEqual(expected, actual)
23 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Program.fs:
--------------------------------------------------------------------------------
1 | module Program = let [] main _ = 0
2 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Search/BinarySearchTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Search
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Search
5 |
6 | []
7 | type BinarySearchTests() =
8 | let data0 =
9 | [| -2147483468
10 | -10
11 | -2
12 | -1
13 | 0
14 | 1
15 | 2
16 | 10
17 | 20
18 | 20
19 | 2147483467 |]
20 |
21 | []
22 | []
23 | []
24 | []
25 | []
26 | []
27 | []
28 | []
29 | []
30 | []
31 | member this.Data0_Exists(num: int, expected: int) =
32 | let actual = BinarySearch.findIndex num data0
33 | Assert.AreEqual(expected, actual)
34 |
35 | []
36 | []
37 | member this.Data0_Duplicates(num: int) =
38 | let actual = BinarySearch.findIndex num data0
39 | Assert.IsTrue(actual = 8 || actual = 9)
40 |
41 | []
42 | []
43 | member this.Data0_None(num: int, expected: int) =
44 | let actual = BinarySearch.findIndex num data0
45 | Assert.AreEqual(expected, actual)
46 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/CapitalizeTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type CapitalizeTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | member this.Capitalize (sentence:string, expected:string) =
16 | let actual = Capitalize.capitalize sentence
17 | Assert.AreEqual(expected, actual)
18 |
19 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/CheckAnagramsTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type CheckAnagramsTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | member this.isAnagram (string1:string, string2:string, expected:bool) =
15 | let actual = CheckAnagrams.isAnagram (string1, string2)
16 | Assert.AreEqual(expected, actual)
17 |
18 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/CheckPangramTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type CheckPangramTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | member this.CheckPangram (sentence:string, expected:bool) =
17 | let actual = CheckPangram.checkPangram sentence
18 | Assert.AreEqual(expected, actual)
19 |
20 | []
21 | []
22 | []
23 | []
24 | []
25 | []
26 | member this.CheckPangramFaster (sentence:string, expected:bool) =
27 | let actual = CheckPangram.checkPangramFaster sentence
28 | Assert.AreEqual(expected, actual)
29 |
30 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/IsPalindromeTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type IsPalindromeTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | member this.isPalindrome (str:string, expected:bool) =
16 | let actual = IsPalindrome.isPalindrome str
17 | Assert.AreEqual(expected, actual)
18 |
19 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/JaroWinklerTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type JaroWinklerTests () =
8 | []
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | member this.jaroWinkler (str1:string, str2:string, expected:float) =
18 | let actual = JaroWinkler.jaroWinkler(str1, str2)
19 | Assert.AreEqual(expected, actual)
20 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/KnuthMorrisPrattTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type KnuthMorrisPrattTests () =
8 |
9 | []
10 | member this.getFailureArray () =
11 | let actual = KnuthMorrisPratt.getFailureArray("aabaabaaa")
12 | let expected = [0; 1; 0; 1; 2; 3; 4; 5; 2]
13 | Assert.AreEqual(expected, actual)
14 |
15 | []
16 | []
17 | []
18 | []
19 | []
20 | member this.kmp (pattern:string, text:string) =
21 | let actual = KnuthMorrisPratt.kmp(pattern, text)
22 | Assert.IsTrue(actual)
23 |
24 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/LevenshteinDistanceTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type LevenshteinDistanceTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | []
16 | []
17 | member this.levenshteinDistance (firstWord:string, secondWord:string, expected:int) =
18 | let actual = LevenshteinDistance.levenshteinDistance(firstWord, secondWord )
19 | Assert.AreEqual(expected, actual)
20 |
21 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/LowerTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type LowerTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | []
15 | member this.lower (input:string, expected:string) =
16 | let actual = Lower.lower(input)
17 | Assert.AreEqual(expected, actual)
18 |
19 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/ManacherTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type ManacherTests () =
8 |
9 | []
10 | []
11 | []
12 | member this.palindromicString (input:string, expected:string) =
13 | let actual = Manacher.palindromicString(input)
14 | Assert.AreEqual(expected, actual)
15 |
16 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/MinCostStringConversionTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 | open MinCostStringConversion
6 |
7 | []
8 | type MinCostStringConversionTests () =
9 |
10 | let validateAndApply (source: string ) (operations: Operation array) : string =
11 | operations
12 | |> Array.mapFold (fun sourcePosition op ->
13 | match op with
14 | | Operation.Copy s ->
15 | Assert.AreEqual(source.[sourcePosition], s)
16 | Some s, sourcePosition + 1
17 | | Operation.Replace (s, d) ->
18 | Assert.AreEqual(source.[sourcePosition], s)
19 | Some d, sourcePosition + 1
20 | | Operation.Delete s ->
21 | Assert.AreEqual(source.[sourcePosition], s)
22 | None, sourcePosition + 1
23 | | Operation.Insert c ->
24 | Some c, sourcePosition
25 | ) 0
26 | |> fst
27 | |> Array.choose id
28 | |> Array.map string
29 | |> String.concat ""
30 |
31 | let calculateCost (operations: Operation array, copyCost:int, replaceCost:int, deleteCost:int, insertCost:int) =
32 | operations
33 | |> Array.sumBy (function
34 | | Operation.Copy _ -> copyCost
35 | | Operation.Replace _ -> replaceCost
36 | | Operation.Delete _ -> deleteCost
37 | | Operation.Insert _ -> insertCost
38 | )
39 |
40 |
41 | []
42 | []
43 | []
44 | []
45 | []
46 | []
47 | []
48 | []
49 | member this.validateResult (source: string, destination: string, copyCost:int, replaceCost:int, deleteCost:int, insertCost:int) =
50 | let costs, ops = computeTransformTables (source, destination, copyCost, replaceCost, deleteCost, insertCost)
51 |
52 | for i = 0 to source.Length do
53 | for j = 0 to destination.Length do
54 | let sourceSubstring = source.Substring(0, i)
55 | let destinationSubstring = destination.Substring(0, j)
56 | let operations = assembleTransformation (ops, i, j)
57 | let actualDestinationSubstring = validateAndApply sourceSubstring operations
58 | let calculatedCost = calculateCost (operations, copyCost, replaceCost, deleteCost, insertCost)
59 | Assert.AreEqual (destinationSubstring, actualDestinationSubstring)
60 | Assert.AreEqual (costs.[i].[j], calculatedCost)
61 |
62 | static member inputForComputeTransformTables =
63 | seq {
64 | yield [|
65 | "abbbaba" :> obj
66 | "ababa" :> obj
67 | 1 :> obj
68 | 2 :> obj
69 | 3 :> obj
70 | 3 :> obj
71 | ([|
72 | [|0; 3; 6; 9; 12; 15|]
73 | [|3; 1; 4; 7; 10; 13|]
74 | [|6; 4; 2; 5; 8; 11|]
75 | [|9; 7; 5; 4; 6; 9|]
76 | [|12; 10; 8; 7; 5; 8|]
77 | [|15; 13; 11; 9; 8; 6|]
78 | [|18; 16; 14; 12; 10; 9|]
79 | [|21; 19; 17; 15; 13; 11|]
80 | |],
81 | [|
82 | [|Operation.Copy 'a'; Operation.Insert 'a'; Operation.Insert 'b'; Operation.Insert 'a'; Operation.Insert 'b'; Operation.Insert 'a'|]
83 | [|Operation.Delete 'a'; Operation.Copy 'a'; Operation.Insert 'b'; Operation.Copy 'a'; Operation.Insert 'b'; Operation.Copy 'a'|]
84 | [|Operation.Delete 'b'; Operation.Delete 'b'; Operation.Copy 'b'; Operation.Insert 'a'; Operation.Copy 'b'; Operation.Insert 'a'|]
85 | [|Operation.Delete 'b'; Operation.Delete 'b'; Operation.Copy 'b'; Operation.Replace ('b', 'a'); Operation.Copy 'b'; Operation.Insert 'a'|]
86 | [|Operation.Delete 'b'; Operation.Delete 'b'; Operation.Copy 'b'; Operation.Replace ('b', 'a'); Operation.Copy 'b'; Operation.Replace ('b', 'a')|]
87 | [|Operation.Delete 'a'; Operation.Copy 'a'; Operation.Delete 'a'; Operation.Copy 'a'; Operation.Delete 'a'; Operation.Copy 'a'|]
88 | [|Operation.Delete 'b'; Operation.Delete 'b'; Operation.Copy 'b'; Operation.Delete 'b'; Operation.Copy 'b'; Operation.Delete 'b'|]
89 | [|Operation.Delete 'a'; Operation.Copy 'a'; Operation.Delete 'a'; Operation.Copy 'a'; Operation.Delete 'a'; Operation.Copy 'a'|]
90 | |]) :> obj
91 | |]
92 | }
93 |
94 | []
95 | []
96 | member this.computeTransformTables (sourceString:string, destinationString:string, copyCost:int, replaceCost:int, deleteCost:int, insertCost:int, expected:int array array * Operation array array) =
97 | let actual = MinCostStringConversion.computeTransformTables(sourceString,destinationString,copyCost,replaceCost,deleteCost,insertCost)
98 | Assert.IsTrue((expected = actual))
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/NaiveStringSearchTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 |
7 |
8 | []
9 | type NaiveStringSearchTests () =
10 |
11 | []
12 | member this.naivePatternSearch () =
13 | let actual = NaiveStringSearch.naivePatternSearch("ABAAABCDBBABCDDEBCABC", "ABC")
14 | let expected = [4; 10; 18]
15 | Assert.AreEqual(expected, actual)
16 |
17 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/PrefixFunctionTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type PrefixFunctionTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | member this.longestPrefix (input:string, expected:int) =
14 | let actual = PrefixFunction.longestPrefix(input)
15 | Assert.AreEqual(expected, actual)
16 |
17 | []
18 | member this.prefixFunction () =
19 | let expected = [0; 1; 0; 0; 0; 1; 2; 3; 4]
20 | let actual = PrefixFunction.prefixFunction("aabcdaabc")
21 | Assert.AreEqual(expected, actual)
22 |
23 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/RabinKarpTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type RabinKarpTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | member this.rabinKarp (pattern:string, text:string) =
15 | let actual = RabinKarp.rabinKarp(pattern, text)
16 | Assert.IsTrue(actual)
17 |
18 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/RemoveDuplicatesTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type RemoveDuplicatesTests () =
8 |
9 | []
10 | []
11 | []
12 | member this.removeDuplicates (str:string, expected:string) =
13 | let actual = RemoveDuplicates.removeDuplicates(str)
14 | Assert.AreEqual(expected, actual)
15 |
16 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/ReverseLettersTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | []
7 | type ReverseLettersTests () =
8 |
9 | []
10 | []
11 | []
12 | []
13 | []
14 | member this.reverseLetters (input:string, expected:string) =
15 | let actual = ReverseLetters.reverseLetters(input)
16 | Assert.AreEqual(expected, actual)
17 |
18 |
--------------------------------------------------------------------------------
/Algorithms.Tests/Strings/ReverseWordsTests.fs:
--------------------------------------------------------------------------------
1 | namespace Algorithms.Tests.Strings
2 |
3 | open Microsoft.VisualStudio.TestTools.UnitTesting
4 | open Algorithms.Strings
5 |
6 | [