├── .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 | [] 7 | type ReverseWordsTests () = 8 | 9 | [] 10 | [] 11 | [] 12 | member this.reverseWords (input:string, expected:string) = 13 | let actual = ReverseWords.reverseWords(input) 14 | Assert.AreEqual(expected, actual) 15 | 16 | -------------------------------------------------------------------------------- /Algorithms.Tests/Strings/SplitTests.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Tests.Strings 2 | 3 | open Microsoft.VisualStudio.TestTools.UnitTesting 4 | open Algorithms.Strings 5 | 6 | [] 7 | type SplitTests () = 8 | 9 | [] 10 | member this.Split () = 11 | let expected = ["apple"; "banana"; "cherry"; "orange"] 12 | let actual = Split.Split("apple#banana#cherry#orange", '#') 13 | Assert.AreEqual(expected, actual) 14 | 15 | -------------------------------------------------------------------------------- /Algorithms.Tests/Strings/SwapCaseTests.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Tests.Strings 2 | 3 | open Microsoft.VisualStudio.TestTools.UnitTesting 4 | open Algorithms.Strings 5 | 6 | [] 7 | type SwapCaseTests () = 8 | 9 | [] 10 | [] 11 | member this.swapCase (input:string, expected:string) = 12 | let actual = SwapCase.swapCase(input) 13 | Assert.AreEqual(expected, actual) 14 | 15 | -------------------------------------------------------------------------------- /Algorithms.Tests/Strings/UpperTests.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Tests.Strings 2 | 3 | open Microsoft.VisualStudio.TestTools.UnitTesting 4 | open Algorithms.Strings 5 | 6 | [] 7 | type UpperTests () = 8 | 9 | [] 10 | [] 11 | [] 12 | [] 13 | [] 14 | member this.upper (input:string, expected:string) = 15 | let actual = Upper.upper(input) 16 | Assert.AreEqual(expected, actual) 17 | 18 | -------------------------------------------------------------------------------- /Algorithms.Tests/Strings/WordOccurrenceTests.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Tests.Strings 2 | 3 | open Microsoft.VisualStudio.TestTools.UnitTesting 4 | open Algorithms.Strings 5 | 6 | [] 7 | type WordOccurrenceTests () = 8 | 9 | [] 10 | member this.wordOccurrence () = 11 | let mutable expected : Map = Map.empty 12 | expected <- expected.Add("Two",1) 13 | expected <- expected.Add("spaces",1) 14 | let actual = WordOccurrence.wordOccurrence("Two spaces") 15 | Assert.AreEqual(expected, actual) 16 | 17 | -------------------------------------------------------------------------------- /Algorithms.Tests/Strings/ZFunctionTests.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Tests.Strings 2 | 3 | open Microsoft.VisualStudio.TestTools.UnitTesting 4 | open Algorithms.Strings 5 | 6 | [] 7 | type ZFunctionTests () = 8 | 9 | [] 10 | [] 11 | [] 12 | [] 13 | member this.findPattern (pattern:string, inputString:string, expected:int) = 14 | let actual = ZFunction.findPattern(pattern, inputString) 15 | Assert.AreEqual(expected, actual) 16 | 17 | [] 18 | member this.zFunction () = 19 | let expected = [0; 0; 0; 1; 0; 1; 0; 4; 0; 0; 1] 20 | let actual = ZFunction.zFunction("abracadabra") 21 | Assert.AreEqual(expected, actual) 22 | 23 | -------------------------------------------------------------------------------- /Algorithms/Algorithms.fsproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Library 4 | net6.0 5 | latest 6 | true 7 | 8 | 9 | TRACE 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Algorithms/DataStructures/AVLTree.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.DataStructures 2 | 3 | module AVLTree = 4 | 5 | type AVLNode = { 6 | Value: int 7 | Height: int 8 | LeftChild: Option 9 | RightChild: Option 10 | } 11 | 12 | module AVLNode = 13 | let create (value: int) : AVLNode = 14 | { 15 | Value = value 16 | Height = 0 17 | LeftChild = None 18 | RightChild = None 19 | } 20 | 21 | let height (maybeNode: Option) : int = 22 | maybeNode 23 | |> Option.map (fun node -> node.Height) 24 | |> Option.defaultValue -1 25 | 26 | let balanceFactor (node: AVLNode) : int = 27 | height node.RightChild - height node.LeftChild 28 | 29 | type AVLNode 30 | with 31 | member this.UpdateLeftChild (leftChild: Option) : AVLNode = 32 | { 33 | this with 34 | LeftChild = leftChild 35 | Height = 1 + max (AVLNode.height leftChild) (AVLNode.height this.RightChild) 36 | } 37 | member this.UpdateRightChild (rightChild: Option) : AVLNode = 38 | { 39 | this with 40 | RightChild = rightChild 41 | Height = 1 + max (AVLNode.height this.LeftChild) (AVLNode.height rightChild) 42 | } 43 | 44 | module AVLTree = 45 | let rotateRight (node: AVLNode) : AVLNode = 46 | // Left child becomes the new root 47 | let leftChild = node.LeftChild |> Option.get 48 | let oldNode = node.UpdateLeftChild (leftChild.RightChild) 49 | leftChild.UpdateRightChild (Some oldNode) 50 | 51 | let rotateLeft (node: AVLNode) : AVLNode = 52 | // Right child becomes the new root 53 | let rightChild = node.RightChild |> Option.get 54 | let oldNode = node.UpdateRightChild (rightChild.LeftChild) 55 | rightChild.UpdateLeftChild (Some oldNode) 56 | 57 | 58 | type AVLTree = { 59 | Root: Option 60 | } 61 | 62 | let empty = { Root = None } 63 | 64 | let private rebalance (node: AVLNode) : AVLNode = 65 | if AVLNode.balanceFactor node > 1 then 66 | // Root node is right heavy, current balance factor is 2 67 | // check the balance factor of the right child 68 | if node.RightChild |> Option.get |> AVLNode.balanceFactor < 0 then 69 | // Right child is left heavy 70 | // rotate right around right child and rotate left around root 71 | 72 | // Illustration: possible heights are shown in brackets, 73 | // and the balance factor of the node is shown in parentheses 74 | 75 | // Initial state: 76 | // 77 | // b (+2) [h+3] 78 | // / \ 79 | // [h] a f (-1) [h+2] 80 | // /\ 81 | // [h+1] (0|-1|+1) d g [h] 82 | // /\ 83 | // [h|h-1] c e [h|h-1] 84 | 85 | // rotate right around f (right child) 86 | // 87 | // b (+2) [h+3] 88 | // / \ 89 | // [h] a d (+1|+2) [h+2] 90 | // /\ 91 | // [h|h-1] c f (0|-1) [h+1] 92 | // /\ 93 | // [h|h-1] e g [h] 94 | 95 | // rotate left around b (root) 96 | // d (0) [h+2] 97 | // __________/\__________ 98 | // / \ 99 | // [h+1] (0|-1) b f (0|-1) [h+1] 100 | // / \ /\ 101 | // [h] a c [h|h-1] [h|h-1] e g [h] 102 | 103 | 104 | let node =node.UpdateRightChild (Some (AVLTree.rotateRight (node.RightChild |> Option.get))) 105 | AVLTree.rotateLeft node 106 | else 107 | // Right child is balanced or left heavy, 108 | // rotate left around root 109 | 110 | // Illustration if right child is balanced 111 | 112 | // Initial state: 113 | // b (+2) [h+3] 114 | // / \ 115 | // [h] a d (0) [h+2] 116 | // /\ 117 | // [h+1] c e [h+1] 118 | 119 | // rotate left around b (root) 120 | // d (-1) [h+3] 121 | // / \ 122 | // [h+2] (+1) b e [h+1] 123 | // / \ 124 | // [h] a c [h+1] 125 | 126 | // Illustration if right child is right heavy 127 | 128 | // Initial state: 129 | // b (+2) [h+3] 130 | // / \ 131 | // [h] a d (+1) [h+2] 132 | // /\ 133 | // [h] c e [h+1] 134 | 135 | // rotate left around b (root) 136 | // d (0) [h+2] 137 | // / \ 138 | // [h+1] (0) b e [h+1] 139 | // / \ 140 | // [h] a c [h] 141 | 142 | AVLTree.rotateLeft node 143 | elif AVLNode.balanceFactor node < -1 then 144 | // Root node is left heavy, current balance factor is -2 145 | // check the balance factor of the left child 146 | if node.LeftChild |> Option.get |> AVLNode.balanceFactor > 0 then 147 | // Left child is right heavy 148 | // rotate left around left child and rotate right around root 149 | 150 | // Initial state: 151 | // f (-2) [h+3] 152 | // / \ 153 | // [h+2] (+1) b g [h] 154 | // /\ 155 | // [h] a d (0|-1|+1) [h+1] 156 | // /\ 157 | // [h|h-1] c e [h|h-1] 158 | 159 | // rotate left around b (left child) 160 | // f (-2) [h+3] 161 | // / \ 162 | // [h+2] (-2) d g [h] 163 | // / \ 164 | // [h+1] b e [h|h-1] 165 | // /\ 166 | // [h] a c [h|h-1] 167 | 168 | // rotate right around f (root) 169 | // d (0) [h+2] 170 | // __________/\__________ 171 | // / \ 172 | // [h+1] (0|-1) b f (0|-1) [h+1] 173 | // / \ /\ 174 | // [h] a c [h|h-1] [h|h-1] e g [h] 175 | 176 | let node = node.UpdateLeftChild (Some (AVLTree.rotateLeft (node.LeftChild |> Option.get))) 177 | AVLTree.rotateRight node 178 | else 179 | // Left child is balanced or left heavy 180 | // rotate right around root 181 | 182 | // Illustration if left child is balanced 183 | 184 | // Initial state: 185 | // d (-2) [h+3] 186 | // / \ 187 | // [h+2] (0) b e [h] 188 | // / \ 189 | // [h+1] a c [h+1] 190 | 191 | // rotate right around d (root) 192 | // b (+1) [h+3] 193 | // / \ 194 | // [h+1] a d (-1) [h+2] 195 | // / \ 196 | // [h+1]c e [h] 197 | 198 | // Illustration if left child is left heavy 199 | 200 | // Initial state: 201 | // d (-2) [h+3] 202 | // / \ 203 | // [h+2] (-1) b e [h] 204 | // / \ 205 | // [h+1] a c [h] 206 | 207 | // rotate right around d (root) 208 | // b (0) [h+2] 209 | // / \ 210 | // [h+1] a d (0) [h+1] 211 | // / \ 212 | // [h] c e [h] 213 | 214 | AVLTree.rotateRight node 215 | else 216 | // Balance of root is within acceptable range 217 | node 218 | 219 | 220 | let insert (value: int) (tree: AVLTree) : AVLTree = 221 | let rec insertImpl (maybeNode: Option) : AVLNode = 222 | match maybeNode with 223 | | None -> 224 | AVLNode.create value 225 | | Some node -> 226 | if value < node.Value then 227 | node.UpdateLeftChild (Some (insertImpl node.LeftChild)) 228 | |> rebalance 229 | elif value = node.Value then 230 | node 231 | else 232 | node.UpdateRightChild (Some (insertImpl node.RightChild)) 233 | |> rebalance 234 | 235 | 236 | insertImpl tree.Root 237 | |> fun root -> { Root = Some root } 238 | 239 | let delete (value: int) (tree: AVLTree) : AVLTree = 240 | let rec deleteMinValueNode (node: AVLNode) : Option * (* MinValue *) int = 241 | match node.LeftChild with 242 | | None -> 243 | // delete current node and return the value that was replaced 244 | node.RightChild, node.Value 245 | | Some leftChild -> 246 | let leftChild, minValue = deleteMinValueNode leftChild 247 | let node = 248 | node.UpdateLeftChild leftChild 249 | |> rebalance 250 | Some node, minValue 251 | 252 | let rec deleteImpl (maybeNode: Option) : Option = 253 | match maybeNode with 254 | | None -> None 255 | | Some node -> 256 | if value < node.Value then 257 | node.UpdateLeftChild (deleteImpl node.LeftChild) 258 | |> rebalance 259 | |> Some 260 | elif value = node.Value then 261 | match node.LeftChild, node.RightChild with 262 | | None, None -> None 263 | | None, Some rightChild -> Some rightChild 264 | | Some leftChild, None -> Some leftChild 265 | | Some _leftChild, Some rightChild -> 266 | let rightNode, currentValue = deleteMinValueNode rightChild 267 | let node = { node with Value = currentValue } 268 | 269 | node.UpdateRightChild rightNode 270 | |> rebalance 271 | |> Some 272 | else 273 | node.UpdateRightChild (deleteImpl node.RightChild) 274 | |> rebalance 275 | |> Some 276 | 277 | 278 | deleteImpl tree.Root 279 | |> fun root -> { Root = root } 280 | 281 | 282 | -------------------------------------------------------------------------------- /Algorithms/DataStructures/Treap.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.DataStructures 2 | 3 | module Treap = 4 | type TreapNode = { 5 | Value: int 6 | Priority: int64 7 | Size: int 8 | LeftChild: Option 9 | RightChild: Option 10 | } 11 | 12 | module TreapNode = 13 | let create (value: int) : TreapNode = 14 | { 15 | Value = value 16 | Priority = System.Random().NextInt64() 17 | Size = 1 18 | LeftChild = None 19 | RightChild = None 20 | } 21 | 22 | let getSize (maybeNode: Option) : int = 23 | maybeNode 24 | |> Option.map (fun node -> node.Size) 25 | |> Option.defaultValue 0 26 | 27 | type TreapNode 28 | with 29 | member this.UpdateLeftChild (leftChild: Option) : TreapNode = 30 | { 31 | this with 32 | LeftChild = leftChild 33 | Size = 1 + TreapNode.getSize leftChild + TreapNode.getSize this.RightChild 34 | } 35 | member this.UpdateRightChild (rightChild: Option) : TreapNode = 36 | { 37 | this with 38 | RightChild = rightChild 39 | Size = 1 + TreapNode.getSize this.LeftChild + TreapNode.getSize rightChild 40 | } 41 | 42 | [] 43 | type Treap = { 44 | Root: Option 45 | } 46 | 47 | let empty : Treap = { Root = None } 48 | 49 | /// Splits treap into two parts based on value 50 | /// Returns (left, right) tuple where: 51 | /// - left contains all nodes with values < split value 52 | /// - right contains all nodes with values >= split value 53 | let rec split (root: Option) (value: int) : Option * Option = 54 | match root with 55 | | None -> 56 | None, None 57 | | Some root -> 58 | if root.Value < value then 59 | // root node belongs to the left 60 | // split the right child of root and update the right child of root 61 | let updatedRightOfRoot, right = split root.RightChild value 62 | root.UpdateRightChild updatedRightOfRoot |> Some, right 63 | else 64 | // root node belongs to the right 65 | // split the left child of root and update the left child of root 66 | let left, updatedLeftOfRoot = split root.LeftChild value 67 | left, root.UpdateLeftChild updatedLeftOfRoot |> Some 68 | 69 | /// Merges two treaps maintaining BST and heap properties 70 | /// Assumes all values in left treap are less than all values in right treap 71 | let rec merge (left: Option) (right: Option) : Option = 72 | match left, right with 73 | | None, right -> right 74 | | left, None -> left 75 | | Some left, Some right -> 76 | if left.Priority < right.Priority then 77 | // left node is the root of the merged treap, merge its right child with right treap 78 | let updatedLeftsRightChild = merge left.RightChild (Some right) 79 | left.UpdateRightChild updatedLeftsRightChild |> Some 80 | else 81 | // right node is the root of the merged treap, merge its left child with left treap 82 | let updatedRightsLeftChild = merge (Some left) right.LeftChild 83 | right.UpdateLeftChild updatedRightsLeftChild |> Some 84 | 85 | // Inserts a new value into the treap, noop if value already exists 86 | let insert (value: int) (treap: Treap) : Treap = 87 | let node = TreapNode.create value 88 | let left, right = split treap.Root value 89 | let _, right = split right (value + 1) 90 | merge (merge left (Some node)) right 91 | |> fun root -> { Root = root } 92 | 93 | let erase (value: int) (treap: Treap) : Treap = 94 | let left, right = split treap.Root value 95 | let _, right = split right (value + 1) 96 | merge left right 97 | |> fun root -> { Root = root } 98 | 99 | /// Gets the kth smallest element in the treap (0-indexed) 100 | /// Returns None if k is out of bounds 101 | let getKthElement (treap: Treap) (k: uint) : Option = 102 | if TreapNode.getSize treap.Root |> uint <= k then 103 | None 104 | else 105 | let rec getKthElementImpl (root: TreapNode) (k: int) : int = 106 | assert (k < root.Size) 107 | if root.Size = 1 then 108 | root.Value 109 | else 110 | if k < TreapNode.getSize root.LeftChild then 111 | getKthElementImpl (root.LeftChild |> Option.get) k 112 | elif k = TreapNode.getSize root.LeftChild then 113 | root.Value 114 | else 115 | getKthElementImpl (root.RightChild |> Option.get) (k - TreapNode.getSize root.LeftChild - 1) 116 | getKthElementImpl (treap.Root |> Option.get) (int k) |> Some 117 | 118 | /// Gets the index of a value in the treap (0 indexed position in sorted order) 119 | /// Returns None if value is not found 120 | let getIndex (treap: Treap) (value: int) : Option = 121 | let left, right = split treap.Root value 122 | let node, _right = split right (value + 1) 123 | node 124 | |> Option.map (fun _ -> TreapNode.getSize left) -------------------------------------------------------------------------------- /Algorithms/DataStructures/Trie.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.DataStructures 2 | 3 | module Trie = 4 | 5 | type Trie = { 6 | IsWord : bool 7 | Children : Map 8 | } 9 | 10 | let empty : Trie = { IsWord = false; Children = Map.empty } 11 | 12 | let insert (word: string) (trie: Trie) : Trie = 13 | let rec insertImpl (chars: char list) (trie: Trie) : Trie = 14 | match chars with 15 | | [] -> 16 | { trie with IsWord = true } 17 | | c :: rest -> 18 | match trie.Children.TryFind c with 19 | | Some child -> 20 | let child = insertImpl rest child 21 | { trie with Children = trie.Children.Add(c, child) } 22 | | None -> 23 | let child = insertImpl rest empty 24 | { trie with Children = trie.Children.Add(c, child) } 25 | 26 | insertImpl (word |> Seq.toList) trie 27 | 28 | let search (word: string) (trie: Trie) : bool = 29 | let rec searchImpl (chars: char list) (trie: Trie) : bool = 30 | match chars with 31 | | [] -> trie.IsWord 32 | | c :: rest -> 33 | match trie.Children.TryFind c with 34 | | Some child -> searchImpl rest child 35 | | None -> false 36 | searchImpl (word |> Seq.toList) trie 37 | 38 | -------------------------------------------------------------------------------- /Algorithms/Math/Abs.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module Abs = 4 | let absVal num = if num < 0 then -num else num 5 | -------------------------------------------------------------------------------- /Algorithms/Math/AbsMax.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module AbsMax = 4 | let absMax (x: int list) = 5 | let mutable j = x.[0] 6 | 7 | for i in x do 8 | if abs i > abs j then j <- i 9 | 10 | j 11 | -------------------------------------------------------------------------------- /Algorithms/Math/AbsMin.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module AbsMin = 4 | let absMin (x: int list) = 5 | let mutable j = x.[0] 6 | 7 | for i in x do 8 | if abs i < abs j then j <- i 9 | 10 | j 11 | -------------------------------------------------------------------------------- /Algorithms/Math/Average.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module Average = 4 | let inline average (xs: ^a list) = 5 | match xs with 6 | | [] -> None 7 | | _ -> 8 | let sum, count = List.fold (fun (sum, count) current -> (sum + current, count + 1)) 9 | (LanguagePrimitives.GenericZero, 0) 10 | xs 11 | LanguagePrimitives.DivideByInt sum count |> Some 12 | -------------------------------------------------------------------------------- /Algorithms/Math/Factorial.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module Factorial = 4 | /// Calculates factorial. Time complexity: O(n) 5 | let byFoldFunction n = 6 | if n < 0 then 7 | failwith "No factorial for negative numbers" 8 | else 9 | { 1 .. n } |> Seq.fold (fun acc n -> acc * n) 1 10 | 11 | /// Calculates factorial. Time complexity: O(n) 12 | let byReduceFunction n = 13 | match n with 14 | | n when n < 0 -> failwith "No factorial for negative numbers" 15 | | 0 -> 1 16 | | n -> { 1 .. n } |> Seq.reduce (*) 17 | 18 | /// Calculates factorial. Time complexity: O(n) 19 | let rec byRecursion n = 20 | match sign n with 21 | | -1 -> failwith "No factorial for negative numbers" 22 | | 0 -> 1 23 | | _ -> n * byRecursion (n - 1) 24 | 25 | /// Calculates factorial. Time complexity: O(n) 26 | let byTailRecursion n = 27 | let rec inner n prod = 28 | match n with 29 | | 0 -> prod 30 | | _ -> inner (n - 1) (prod * n) 31 | 32 | match n with 33 | | n when n < 0 -> failwith "No factorial for negative numbers" 34 | | _ -> inner n 1 35 | 36 | /// Calculates factorial. Time complexity: O(n) 37 | let inline byTailRecursionGeneric n = 38 | let gen0 = LanguagePrimitives.GenericZero 39 | let gen1 = LanguagePrimitives.GenericOne 40 | 41 | let rec inner n prod = 42 | match n with 43 | | n when n = gen0 -> prod 44 | | _ -> inner (n - gen1) (prod * n) 45 | 46 | match n with 47 | | n when n < gen0 -> failwith "No factorial for negative numbers" 48 | | _ -> inner n gen1 49 | -------------------------------------------------------------------------------- /Algorithms/Math/Fibonacci.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module Fibonacci = 4 | let rec PrintSerie (one: int) (two: int) = 5 | let fibo = one + two 6 | System.Console.WriteLine fibo 7 | PrintSerie two fibo 8 | 9 | let rec NthFibonacci (n: int): int = 10 | match n with 11 | | 0 -> 0 12 | | 1 -> 1 13 | | n -> NthFibonacci (n-1) + NthFibonacci (n-2) 14 | -------------------------------------------------------------------------------- /Algorithms/Math/Greatest_Common_Divisor.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module GreatestCommonDivisor = 4 | let rec gcd (m: int) (n: int): int = 5 | match m,n with 6 | | 0,n -> n 7 | | m,n -> gcd (n % m) m 8 | -------------------------------------------------------------------------------- /Algorithms/Math/Perfect_Numbers.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module PerfectNumbers = 4 | /// Check if a number is perfect. Time complexity: O(√n) 5 | let isPerfect n = 6 | match n with 7 | | n when n <= 0 -> false 8 | | n -> 9 | { 1 .. n - 1 } 10 | |> Seq.takeWhile (fun i -> i * i <= n) 11 | |> Seq.filter ((%) n >> (=) 0) 12 | |> Seq.fold (fun acc i -> acc + i + n / i) 0 13 | |> (=) (2 * n) 14 | -------------------------------------------------------------------------------- /Algorithms/Math/Power.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module Power = 4 | /// Calculates x^n. Time complexity: O(√n). 5 | let byFoldFunction x n = 6 | { 1 .. n } |> Seq.fold (fun acc _ -> acc * x) 1 7 | 8 | /// Calculates x^n. x and n can be negative. 9 | /// Time complexity O(n). 10 | let rec byRecursion x n = 11 | match x, sign n with 12 | | 0, -1 -> 13 | System.DivideByZeroException "Attempted to divide by zero." 14 | |> raise 15 | | -1, _ -> if n % 2 = 0 then 1 else -1 16 | | 1, _ -> 1 17 | | _, 0 -> 1 18 | | 0, _ -> 0 19 | | _, -1 -> 0 20 | | _, _ -> x * byRecursion x (n - 1) 21 | -------------------------------------------------------------------------------- /Algorithms/Math/Prime.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Math 2 | 3 | module Prime = 4 | /// Check if a number is prime. Time complexity: O(√n) 5 | let isPrime n = 6 | if n <= 1 then 7 | false 8 | elif n = 2 then 9 | true 10 | elif n % 2 = 0 then 11 | false 12 | else 13 | seq { 14 | let mutable i = 3 15 | 16 | while i * i <= n do 17 | yield i 18 | i <- i + 2 19 | } 20 | |> Seq.forall ((%) n >> (<>) 0) 21 | -------------------------------------------------------------------------------- /Algorithms/Search/BinarySearch.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Search 2 | 3 | module BinarySearch = 4 | /// Search the target item in a sorted array. 5 | /// Returns -1 when the target is not found. 6 | /// Time complexity: O(log(sortedData.Length))) 7 | let findIndex target sortedData = 8 | let rec search l r = 9 | let count = r - l 10 | let mid = (l + r) / 2 11 | let midItem = Array.item mid sortedData 12 | 13 | match count <= 1, compare midItem target with 14 | | _, 0 -> mid 15 | | true, _ -> -1 16 | | false, -1 -> search mid r 17 | | false, 1 -> search l mid 18 | | _ -> exn () |> raise 19 | 20 | search 0 (Array.length sortedData + 1) 21 | -------------------------------------------------------------------------------- /Algorithms/Sort/Bubble_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module BubbleSort = 4 | let rec Sort list: 'T [] = 5 | let mutable updated = false 6 | let mutable list = list |> Array.copy 7 | for index in 0 .. list.Length - 1 do 8 | if index < list.Length - 1 then 9 | let current = list.[index] 10 | let next = list.[index + 1] 11 | if next < current then 12 | list.[index] <- next 13 | list.[index + 1] <- current 14 | updated <- true 15 | if updated then list <- Sort list 16 | list 17 | -------------------------------------------------------------------------------- /Algorithms/Sort/Comb_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module CombSort = 4 | let Sort list: 'T [] = 5 | let mutable list = list |> Array.copy 6 | let mutable gap = double list.Length 7 | let mutable swaps = true 8 | while gap > 1.0 || swaps do 9 | gap <- gap / 1.247330950103979 10 | if gap < 1.0 then gap <- 1.0 11 | let mutable i = 0 12 | swaps <- false 13 | while i + int gap < list.Length do 14 | let igap = i + int gap 15 | if list.[i] > list.[igap] then 16 | let swap = list.[i] 17 | list.[i] <- list.[igap] 18 | list.[igap] <- swap 19 | swaps <- true 20 | i <- i + 1 21 | list 22 | -------------------------------------------------------------------------------- /Algorithms/Sort/Cycle_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module CycleSort = 4 | let Sort list: 'T [] = 5 | let mutable list = list |> Array.copy 6 | let mutable writes = 0 7 | for index in 0 .. list.Length - 1 do 8 | let mutable value = list.[index] 9 | let mutable pos = index 10 | for i in index + 1 .. list.Length - 1 do 11 | if list.[i] < value then pos <- pos + 1 12 | if pos <> index then 13 | while value = list.[pos] do 14 | pos <- pos + 1 15 | let mutable tmp = list.[pos] 16 | list.[pos] <- value 17 | value <- tmp 18 | writes <- writes + 1 19 | while pos <> index do 20 | pos <- index 21 | for i in index + 1 .. list.Length - 1 do 22 | if list.[i] < value then pos <- pos + 1 23 | while value = list.[pos] do 24 | pos <- pos + 1 25 | tmp <- list.[pos] 26 | list.[pos] <- value 27 | value <- tmp 28 | writes <- writes + 1 29 | list 30 | -------------------------------------------------------------------------------- /Algorithms/Sort/Gnome_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module GnomeSort = 4 | let Sort list: 'T [] = 5 | let mutable list = list |> Array.copy 6 | let mutable first = 1 7 | let mutable second = 2 8 | while first < list.Length do 9 | if list.[first - 1] <= list.[first] then 10 | first <- second 11 | second <- second + 1 12 | else 13 | let tmp = list.[first - 1] 14 | list.[first - 1] <- list.[first] 15 | list.[first] <- tmp 16 | first <- first - 1 17 | if first = 0 then 18 | first <- 1 19 | second <- 2 20 | list 21 | -------------------------------------------------------------------------------- /Algorithms/Sort/Heap_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module HeapSort = 4 | let inline swap (a: 'T []) i j = 5 | let temp = a.[i] 6 | a.[i] <- a.[j] 7 | a.[j] <- temp 8 | 9 | let inline sift cmp (a: 'T []) start count = 10 | let rec loop root child = 11 | if root * 2 + 1 < count then 12 | let p = 13 | child < count 14 | - 1 15 | && cmp a.[child] a.[child + 1] < 0 16 | 17 | let child = if p then child + 1 else child 18 | if cmp a.[root] a.[child] < 0 then 19 | swap a root child 20 | loop child (child * 2 + 1) 21 | 22 | loop start (start * 2 + 1) 23 | 24 | let inline heapsort cmp (a: 'T []) = 25 | let n = a.Length 26 | for start = n / 2 - 1 downto 0 do 27 | sift cmp a start n 28 | for term = n - 1 downto 1 do 29 | swap a term 0 30 | sift cmp a 0 term 31 | -------------------------------------------------------------------------------- /Algorithms/Sort/Insertion_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module InsertionSort = 4 | let Sort list: 'T [] = 5 | let mutable list = list |> Array.copy 6 | for index in 1 .. list.Length - 1 do 7 | let item = list.[index] 8 | let mutable j = index 9 | while j > 0 && list.[j - 1] > item do 10 | list.[j] <- list.[j - 1] 11 | j <- j - 1 12 | list.[j] <- item 13 | list 14 | -------------------------------------------------------------------------------- /Algorithms/Sort/Merge_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module MergeSort = 4 | let split list = 5 | let rec aux l acc1 acc2 = 6 | match l with 7 | | [] -> (acc1, acc2) 8 | | [ x ] -> (x :: acc1, acc2) 9 | | x :: y :: tail -> aux tail (x :: acc1) (y :: acc2) 10 | 11 | aux list [] [] 12 | 13 | let rec merge l1 l2 = 14 | match (l1, l2) with 15 | | (x, []) -> x 16 | | ([], y) -> y 17 | | (x :: tx, y :: ty) -> if x <= y then x :: merge tx l2 else y :: merge l1 ty 18 | 19 | let rec sort list = 20 | match list with 21 | | [] -> [] 22 | | [ x ] -> [ x ] 23 | | _ -> 24 | let (l1, l2) = split list 25 | merge (sort l1) (sort l2) 26 | -------------------------------------------------------------------------------- /Algorithms/Sort/Pancake_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module PancakeSort = 4 | let show data = 5 | data |> Array.iter (printf "%d ") 6 | printfn "" 7 | 8 | let split (data: int []) pos = data.[0..pos], data.[(pos + 1)..] 9 | 10 | let flip items pos = 11 | let lower, upper = split items pos 12 | Array.append (Array.rev lower) upper 13 | 14 | let sort items = 15 | let rec loop data limit = 16 | if limit <= 0 then 17 | data 18 | else 19 | let lower, upper = split data limit 20 | 21 | let indexOfMax = 22 | lower |> Array.findIndex ((=) (Array.max lower)) 23 | 24 | let partialSort = 25 | Array.append (flip lower indexOfMax |> Array.rev) upper 26 | 27 | loop partialSort (limit - 1) 28 | 29 | loop items ((Array.length items) - 1) 30 | -------------------------------------------------------------------------------- /Algorithms/Sort/Quick_Sort.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Sort 2 | 3 | module QuickSort = 4 | let Sort lst = 5 | let rec aux l cont = 6 | match l with 7 | | [] -> cont [] 8 | | pivot :: rest -> 9 | let left, right = 10 | rest |> List.partition (fun i -> i < pivot) 11 | 12 | aux left (fun acc_left -> aux right (fun acc_right -> cont (acc_left @ pivot :: acc_right))) 13 | 14 | aux lst (id) 15 | -------------------------------------------------------------------------------- /Algorithms/Strings/Capitalize.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module Capitalize = 4 | /// 5 | /// This function will capitalize the first letter of a sentence or a word 6 | /// 7 | /// 8 | /// 9 | /// capitalize("hello world") 10 | /// 'Hello world' 11 | /// 12 | /// capitalize("123 hello world") 13 | /// '123 hello world' 14 | /// 15 | /// capitalize(" hello world") 16 | /// ' hello world' 17 | /// 18 | /// capitalize("a") 19 | /// 'A' 20 | /// 21 | /// capitalize("") 22 | /// '' 23 | /// 24 | /// 25 | /// String to capitalize. 26 | /// Capitalized string 27 | let capitalize (sentence: string) = 28 | match sentence with 29 | | "" -> "" 30 | | s when s.[0] >= 'a' && s.[0] <= 'z' -> 31 | sentence 32 | .Remove(0, 1) 33 | .Insert(0, (string) ((char) ((int) s.[0] - 32))) 34 | | _ -> sentence 35 | -------------------------------------------------------------------------------- /Algorithms/Strings/CheckAnagrams.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | /// wiki: https://en.wikipedia.org/wiki/Anagram 4 | module CheckAnagrams = 5 | /// 6 | /// Two strings are anagrams if they are made of the same letters 7 | /// arranged differently (ignoring the case). 8 | /// 9 | /// 10 | /// 11 | /// check_anagrams('Silent', 'Listen') 12 | /// True 13 | /// 14 | /// check_anagrams('This is a string', 'Is this a string') 15 | /// True 16 | /// 17 | /// check_anagrams('This is a string', 'Is this a string') 18 | /// True 19 | /// 20 | /// check_anagrams('There', 'Their') 21 | /// False 22 | /// 23 | /// 24 | /// First string 25 | /// Second string 26 | /// Boolean 27 | let isAnagram (string1: string, string2: string): bool = 28 | let a = 29 | string1.ToLower().ToCharArray() 30 | |> Array.filter (fun chars -> chars <> ' ') 31 | |> Array.sort 32 | |> System.String.Concat 33 | 34 | let b = 35 | string2.ToLower().ToCharArray() 36 | |> Array.filter (fun chars -> chars <> ' ') 37 | |> Array.sort 38 | |> System.String.Concat 39 | 40 | a = b 41 | -------------------------------------------------------------------------------- /Algorithms/Strings/CheckPangram.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | /// wiki: https://en.wikipedia.org/wiki/Pangram 4 | module CheckPangram = 5 | type System.Char with 6 | member this.IsUpper(): bool = 7 | match this with 8 | | c when c >= 'A' && c <= 'Z' -> true 9 | | _ -> false 10 | 11 | member this.IsLower(): bool = 12 | match this with 13 | | c when c >= 'a' && c <= 'z' -> true 14 | | _ -> false 15 | 16 | member this.Lower(): char = 17 | match this with 18 | | c when c >= 'A' && c <= 'Z' -> (char) ((int) this + 32) 19 | | _ -> this 20 | 21 | member this.Upper(): char = 22 | match this with 23 | | c when c >= 'a' && c <= 'z' -> (char) ((int) this - 32) 24 | | _ -> this 25 | 26 | let checkPangram (inputString: string): bool = 27 | let mutable frequency = Set.empty 28 | let inputStr = inputString.Replace(" ", "") // Replacing all the whitespace in our sentence 29 | 30 | for alpha in inputStr do 31 | if 'a' <= alpha.Lower() && alpha.Lower() <= 'z' then 32 | frequency <- frequency.Add(alpha.Lower()) 33 | 34 | match frequency.Count with 35 | | 26 -> true 36 | | _ -> if inputStr = "" then true else false 37 | 38 | let checkPangramFaster (inputString: string): bool = 39 | let mutable flag = [| for i in 1 .. 26 -> false |] 40 | 41 | for char in inputString do 42 | if char.IsLower() then 43 | flag.SetValue(true, (int) char - (int) 'a') 44 | 45 | flag |> Array.forall (id) 46 | -------------------------------------------------------------------------------- /Algorithms/Strings/HasPrefix.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module HasPrefix = 4 | /// 5 | /// Reports string has specified prefix or not. 6 | /// 7 | let HasPrefix (s: string, prefix: string): bool = 8 | s.Length >= prefix.Length && s.Substring(0, prefix.Length) = prefix 9 | 10 | -------------------------------------------------------------------------------- /Algorithms/Strings/HasSuffix.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module HasSuffix = 4 | /// 5 | /// Reports string has specified suffix or not. 6 | /// 7 | let HasSuffix (s: string, suffix: string) = 8 | s.Length >= suffix.Length && s.Substring(s.Length-suffix.Length) = suffix 9 | -------------------------------------------------------------------------------- /Algorithms/Strings/IsPalindrome.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module IsPalindrome = 4 | /// 5 | /// Determine whether the string is palindrome 6 | /// 7 | /// 8 | /// Boolean 9 | let isPalindrome (str: string): bool = 10 | let str = 11 | str.ToLower() 12 | |> Seq.filter (System.Char.IsLetterOrDigit) 13 | |> Seq.toList 14 | 15 | str = (str |> List.rev) 16 | -------------------------------------------------------------------------------- /Algorithms/Strings/JaroWinkler.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | open Microsoft.FSharp.Collections 4 | 5 | module JaroWinkler = 6 | /// 7 | /// Jaro–Winkler distance is a string metric measuring an edit distance between two 8 | /// sequences. 9 | /// Output value is between 0.0 and 1.0. 10 | /// 11 | /// 12 | /// 13 | /// 14 | let jaroWinkler (str1: string, str2: string): float = 15 | let getMatchedCharacters (_str1: string, _str2: string): string = 16 | let mutable istr1 = _str1 17 | let mutable istr2 = _str2 18 | let mutable matched = [] 19 | 20 | let limit = 21 | int (floor (double (min _str1.Length str2.Length) / 2.0)) 22 | 23 | istr1 24 | |> Seq.iteri 25 | (fun i l -> 26 | let left = int(max 0 (i - limit)) 27 | 28 | let right = int(min (i + limit + 1) istr2.Length) 29 | 30 | if (istr2.[left..right - 1]).Contains(l) then 31 | matched <- List.append matched [ (string) l ] 32 | let myIndex = (istr2.IndexOf(l)) 33 | istr2 <- $"{istr2.[0..istr2.IndexOf(l) - 1]} {istr2.[istr2.IndexOf(l) + 1..]}") 34 | 35 | matched |> List.fold (+) "" 36 | 37 | // matching characters 38 | let matching1 = getMatchedCharacters (str1, str2) 39 | let matching2 = getMatchedCharacters (str2, str1) 40 | let matchCount = matching1.Length 41 | let mutable jaro = 0.0 42 | 43 | // Transposition 44 | let transpositions = 45 | floor ( 46 | double ( 47 | (double) 48 | [ for c1, c2 in List.zip [ matching1 ] [ matching2 ] do if c1 <> c2 then (c1, c2) ] 49 | .Length 50 | ) 51 | ) 52 | 53 | if matchCount = 0 then 54 | jaro <- 0.0 55 | else 56 | jaro <- 57 | 1.0 / 3.0 58 | * ((double) matchCount / (double) str1.Length 59 | + (double) matchCount / (double) str2.Length 60 | + ((double) matchCount - transpositions) 61 | / (double) matchCount) 62 | 63 | // Common prefix up to 4 characters 64 | let mutable prefixLen = 0 65 | 66 | let mutable c1C2BoolList : bool list = [] 67 | 68 | if str1.Length = str2.Length then 69 | for c1, c2 in Array.zip (str1.[..4].ToCharArray()) (str2.[..4].ToCharArray()) do 70 | if c1 = c2 then 71 | c1C2BoolList <- List.append c1C2BoolList [true] 72 | else 73 | c1C2BoolList <- List.append c1C2BoolList [false] 74 | if (c1C2BoolList |> List.exists(fun x -> (not x))) then 75 | prefixLen <- prefixLen + (c1C2BoolList |> List.findIndex(fun x -> (not x))) 76 | jaro + 0.1 * (double) prefixLen * (1.0 - jaro) -------------------------------------------------------------------------------- /Algorithms/Strings/KnuthMorrisPratt.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module KnuthMorrisPratt = 4 | let getFailureArray (pattern: string) : list = 5 | let mutable failure = [ 0 ] 6 | let mutable i = 0 7 | let mutable j = 1 8 | 9 | while j < pattern.Length do 10 | if pattern.[i] = pattern.[j] then 11 | i <- i + 1 12 | j <- j + 1 13 | failure <- failure @ [ i ] 14 | 15 | elif i > 0 then 16 | i <- failure.[i - 1] 17 | else 18 | j <- j + 1 19 | failure <- failure @ [ i ] 20 | 21 | failure 22 | 23 | /// 24 | /// The Knuth-Morris-Pratt Algorithm for finding a pattern within a piece of text 25 | /// with complexity O(n + m) 26 | /// 27 | /// 28 | /// 29 | /// 30 | let kmp (pattern: string, text: string) : bool = 31 | // 1) Construct the failure array 32 | let failure = getFailureArray pattern 33 | 34 | let mutable result = false 35 | 36 | // 2) Step through text searching for pattern 37 | let mutable i, j = 0, 0 // Index into text, pattern 38 | 39 | while i < text.Length do 40 | if pattern.[j] = text.[i] then 41 | if j = pattern.Length - 1 && (not result) then 42 | i <- text.Length 43 | result <- true 44 | 45 | j <- j + 1 46 | i <- i + 1 47 | 48 | // If this is a prefix in our pattern 49 | // just go back far enough to continue 50 | elif j > 0 && (not result) then 51 | j <- failure.[j - 1] 52 | 53 | else 54 | i <- i + 1 55 | 56 | result -------------------------------------------------------------------------------- /Algorithms/Strings/LevenshteinDistance.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module LevenshteinDistance = 4 | /// 5 | /// Implementation of the levenshtein distance in F#. 6 | /// 7 | /// The first word to measure the difference. 8 | /// The second word to measure the difference. 9 | /// 10 | let rec levenshteinDistance (firstWord: string, secondWord: string): int = 11 | // The longer word should come first 12 | 13 | match secondWord.Length with 14 | | s when s > firstWord.Length -> levenshteinDistance (secondWord, firstWord) 15 | | 0 -> firstWord.Length 16 | | _ -> 17 | let mutable previousRow = [ 0 .. secondWord.Length ] 18 | 19 | firstWord 20 | |> Seq.iteri 21 | (fun i c1 -> 22 | let mutable currentRow = [ i + 1 ] 23 | 24 | secondWord 25 | |> Seq.iteri 26 | (fun j c2 -> 27 | let insertions = previousRow.[j + 1] + 1 28 | let deletions = currentRow.[j] + 1 29 | 30 | let substitutions = 31 | previousRow.[j] + (if c1 <> c2 then 1 else 0) 32 | 33 | // Get the minimum to append to the current row 34 | currentRow <- 35 | currentRow 36 | |> List.append [ (min insertions (min deletions substitutions)) ]) 37 | 38 | previousRow <- currentRow |> List.rev) 39 | 40 | previousRow |> List.rev |> List.item 0 41 | -------------------------------------------------------------------------------- /Algorithms/Strings/Lower.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module Lower = 4 | /// 5 | /// Will convert the entire string to lowercase letters 6 | /// 7 | /// 8 | /// 9 | /// lower("wow") 10 | /// 'wow' 11 | /// 12 | /// lower("HellZo") 13 | /// hellzo' 14 | /// 15 | /// lower("WHAT") 16 | /// 'what' 17 | /// 18 | /// lower("wh[]32") 19 | /// 'wh[]32' 20 | /// 21 | /// lower("whAT") 22 | /// 'what' 23 | /// 24 | /// 25 | /// 26 | /// 27 | let lower (input: string): string = 28 | input.Split() 29 | |> Array.map 30 | (fun word -> 31 | word.ToCharArray() 32 | |> Array.map 33 | (fun character -> 34 | if character >= 'A' && character <= 'Z' then 35 | char (int character + 32) 36 | else 37 | character) 38 | |> (fun characters -> System.String.Concat(characters))) 39 | |> String.concat " " 40 | -------------------------------------------------------------------------------- /Algorithms/Strings/Manacher.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module Manacher = 4 | type List<'a> with 5 | member this.LengthInDouble = (double) this.Length 6 | 7 | let palindromicString (inputString: string): string = 8 | 9 | let mutable maxLength = 0 10 | 11 | // If input_string is "aba" than new_input_string become "a|b|a" 12 | let mutable newInputString = "" 13 | let mutable outputString = "" 14 | 15 | // Append each character + "|" in new_string for range(0, length-1) 16 | for i in inputString.[..(inputString.Length - 1)] do 17 | newInputString <- newInputString + string (i) + "|" 18 | 19 | printfn "%A" newInputString 20 | // Append last character 21 | newInputString <- 22 | newInputString 23 | + string inputString.[inputString.Length - 1] 24 | 25 | // We will store the starting and ending of previous furthest ending palindromic 26 | // substring 27 | let mutable l, r = 0, 0 28 | 29 | // length.[i] shows the length of palindromic substring with center i 30 | let length = 31 | [ for i in 0 .. newInputString.Length -> 1 ] 32 | |> Array.ofList 33 | 34 | 35 | 36 | let mutable start = 0 37 | 38 | // For each character in new_string find corresponding palindromic string 39 | for i in 0 .. newInputString.Length do 40 | // k = 1 if i > r else min(length[l + r - i] // 2, r - i + 1) 41 | let mutable k = 42 | if i > r then 43 | 1 44 | else 45 | min ((int) (floor ([ l + r - 1 ].LengthInDouble / 2.0))) (r - i + 1) 46 | 47 | while i - k >= 0 48 | && i + k < newInputString.Length 49 | && newInputString.[k + i] = newInputString.[i - k] do 50 | k <- k + 1 51 | 52 | length.[i] <- 2 * k - 1 53 | 54 | // Does this string end after the previously explored end (that is r) ? 55 | // if yes the update the new r to the last index of this 56 | if i + k - 1 > r then 57 | l <- i - k + 1 // noqa: E741 58 | r <- i + k - 1 59 | 60 | // update max_length and start position 61 | if maxLength < length.[i] then 62 | maxLength <- length.[i] 63 | start <- i 64 | 65 | // create that string 66 | let s = 67 | newInputString.[int (floor (((double) start - (double) maxLength / 2.0)))..(int) (floor ((double) start + (double) maxLength / 2.0 + 1.0))] 68 | 69 | for i in s do 70 | if i <> '|' then 71 | outputString <- outputString + (string) i 72 | 73 | 74 | outputString 75 | -------------------------------------------------------------------------------- /Algorithms/Strings/MinCostStringConversion.fs: -------------------------------------------------------------------------------- 1 | /// Algorithm for calculating the most cost-efficient sequence for converting one string 2 | /// into another. 3 | /// The only allowed operations are 4 | /// --- Cost to copy a character is copy_cost 5 | /// --- Cost to replace a character is replace_cost 6 | /// --- Cost to delete a character is delete_cost 7 | /// --- Cost to insert a character is insert_cost 8 | /// 9 | namespace Algorithms.Strings 10 | 11 | module MinCostStringConversion = 12 | 13 | [] 14 | type Operation = 15 | | Copy of char 16 | | Replace of Source: char * Target: char 17 | | Delete of char 18 | | Insert of char 19 | 20 | let computeTransformTables 21 | ( 22 | source: string, 23 | destination: string, 24 | copyCost: int, 25 | replaceCost: int, 26 | deleteCost: int, 27 | insertCost: int 28 | ): array> * array> = 29 | 30 | let costs = 31 | Array.init (source.Length + 1) (fun _ -> Array.init (destination.Length + 1) (fun _ -> 0)) 32 | 33 | let ops = 34 | Array.init (source.Length + 1) (fun _ -> Array.init (destination.Length + 1) (fun _ -> Operation.Copy 'a')) 35 | 36 | for i = 1 to source.Length do 37 | costs.[i].[0] <- i * deleteCost 38 | ops.[i].[0] <- Operation.Delete source.[i - 1] 39 | 40 | for i = 1 to destination.Length do 41 | costs.[0].[i] <- i * insertCost 42 | ops.[0].[i] <- Operation.Insert destination.[i - 1] 43 | 44 | for i in 1 .. source.Length do 45 | for j in 1 .. destination.Length do 46 | if source.[i - 1] = destination.[j - 1] then 47 | costs.[i].[j] <- costs.[i - 1].[j - 1] + copyCost 48 | ops.[i].[j] <- Operation.Copy (source.[i - 1]) 49 | else 50 | costs.[i].[j] <- costs.[i - 1].[j - 1] + replaceCost 51 | ops.[i].[j] <- Operation.Replace (source.[i - 1], destination.[j - 1]) 52 | 53 | if costs.[i - 1].[j] + deleteCost < costs.[i].[j] then 54 | costs.[i].[j] <- costs.[i - 1].[j] + deleteCost 55 | ops.[i].[j] <- Operation.Delete (source.[i - 1]) 56 | 57 | if costs.[i].[j - 1] + insertCost < costs.[i].[j] then 58 | costs.[i].[j] <- costs.[i].[j - 1] + insertCost 59 | ops.[i].[j] <- Operation.Insert destination.[j - 1] 60 | 61 | costs, ops 62 | 63 | let rec assembleTransformation (ops: array>, i: int, j: int): array = 64 | printfn $"i={i},j={j},%A{ops}" 65 | if i = 0 && j = 0 then 66 | Array.empty 67 | else 68 | match ops.[i].[j] with 69 | | Operation.Replace _ 70 | | Operation.Copy _ -> 71 | let seq = assembleTransformation (ops, i - 1, j - 1) 72 | Array.append seq [| ops[i][j] |] 73 | | Operation.Delete _ -> 74 | let seq = assembleTransformation (ops, i - 1, j) 75 | Array.append seq [| ops[i][j] |] 76 | | Operation.Insert _ -> 77 | let seq = assembleTransformation (ops, i , j - 1) 78 | Array.append seq [| ops[i][j] |] 79 | 80 | -------------------------------------------------------------------------------- /Algorithms/Strings/NaiveStringSearch.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | /// 4 | /// https://en.wikipedia.org/wiki/String-searching_algorithm#Na%C3%AFve_string_search 5 | /// 6 | /// This algorithm tries to find the pattern from every position of 7 | /// the mainString if pattern is found from position i it add it to 8 | /// the answer and does the same for position i+1 9 | /// 10 | /// 11 | /// 12 | /// Complexity : O(n*m) 13 | /// n=length of main string 14 | /// m=length of pattern string 15 | /// 16 | module NaiveStringSearch = 17 | /// 18 | /// 19 | /// 20 | /// 21 | /// naive_pattern_search("ABAAABCDBBABCDDEBCABC", "ABC") 22 | /// [4, 10, 18] 23 | /// 24 | /// naive_pattern_search("ABC", "ABAAABCDBBABCDDEBCABC") 25 | /// [] 26 | /// 27 | /// naive_pattern_search("", "ABC") 28 | /// [] 29 | /// 30 | /// naive_pattern_search("TEST", "TEST") 31 | /// [0] 32 | /// 33 | /// naive_pattern_search("ABCDEGFTEST", "TEST") 34 | /// [7] 35 | /// 36 | /// 37 | /// 38 | /// 39 | /// List of positions 40 | let naivePatternSearch (s: string, pattern: string): int list = 41 | s.ToCharArray() 42 | |> Seq.mapi 43 | (fun i x -> 44 | let myv = pattern.[0] 45 | 46 | if x = pattern.[0] then 47 | (i, s.[i..(i + (pattern.Length - 1))]) 48 | else 49 | (i, "")) 50 | |> Seq.where (fun (i, x) -> pattern = x) 51 | |> Seq.map (fun (i, x) -> i) 52 | |> List.ofSeq 53 | -------------------------------------------------------------------------------- /Algorithms/Strings/PrefixFunction.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | /// https://cp-algorithms.com/string/prefix-function.html 4 | /// 5 | /// Prefix function Knuth–Morris–Pratt algorithm 6 | /// 7 | /// Different algorithm than Knuth-Morris-Pratt pattern finding 8 | /// 9 | /// E.x. Finding longest prefix which is also suffix 10 | /// Time Complexity: O(n) - where n is the length of the string 11 | module PrefixFunction = 12 | 13 | /// 14 | /// For the given string this function computes value for each index(i), 15 | /// which represents the longest coincidence of prefix and suffix 16 | /// for given substring inputString[0...i]. 17 | /// For the value of the first element the algorithm always returns 0 18 | /// 19 | /// 20 | /// 21 | /// prefix_function "aabcdaabc" 22 | /// [0, 1, 0, 0, 0, 1, 2, 3, 4] 23 | /// 24 | /// prefix_function("asdasdad") 25 | /// [0, 0, 0, 1, 2, 3, 4, 0] 26 | /// 27 | /// 28 | /// 29 | /// A string of int 30 | let prefixFunction (inputString: string): list = 31 | 32 | // List for the result values 33 | let mutable prefixResult = 34 | [| for i in 0 .. (inputString.Length - 1) -> 0 |] 35 | 36 | for i = 1 to (inputString.Length - 1) do 37 | // Use last results for better performance - dynamic programming 38 | let mutable j = prefixResult.[i - 1] 39 | 40 | while j > 0 && inputString.[i] <> inputString.[j] do 41 | j <- prefixResult.[j - 1] 42 | 43 | if inputString.[i] = inputString.[j] then 44 | j <- j + 1 45 | 46 | prefixResult.SetValue(j, i) 47 | 48 | prefixResult |> List.ofArray 49 | 50 | /// 51 | /// Prefix-function use case 52 | /// Finding longest prefix which is suffix as well 53 | /// 54 | /// 55 | /// 56 | /// longest_prefix "aabcdaabc" 57 | /// 4 58 | /// longest_prefix "asdasdad" 59 | /// 4 60 | /// longest_prefix "abcab" 61 | /// 2 62 | /// 63 | /// 64 | /// 65 | /// Returns int 66 | let longestPrefix (inputString: string): int = 67 | // Just returning maximum value of the array gives us answer 68 | prefixFunction (inputString) 69 | |> System.Linq.Enumerable.Max 70 | -------------------------------------------------------------------------------- /Algorithms/Strings/RabinKarp.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module RabinKarp = 4 | /// Numbers of alphabet which we call base 5 | let alphabetSize = 256L 6 | 7 | /// Modulus to hash a string 8 | let modulus = 1000003L 9 | 10 | let nfmod (a: int64, b: int64) = 11 | let aD = double a 12 | let bD = double b 13 | int64 (aD - bD * floor (aD / bD)) 14 | 15 | /// 16 | /// The Rabin-Karp Algorithm for finding a pattern within a piece of text 17 | /// with complexity O(nm), most efficient when it is used with multiple patterns 18 | /// as it is able to check if any of a set of patterns match a section of text in o(1) 19 | /// given the precomputed hashes. 20 | /// 21 | /// 22 | /// This will be the simple version which only assumes one pattern is being searched 23 | /// for but it's not hard to modify 24 | /// 25 | /// 1) Calculate pattern hash 26 | /// 27 | /// 2) Step through the text one character at a time passing a window with the same 28 | /// length as the pattern 29 | /// calculating the hash of the text within the window compare it with the hash 30 | /// of the pattern. Only testing equality if the hashes match 31 | /// 32 | /// 33 | /// 34 | /// 35 | let rabinKarp (pattern: string, text: string): bool = 36 | 37 | let mutable result = false 38 | 39 | let patLen = pattern.Length 40 | let textLen = text.Length 41 | 42 | match patLen with 43 | | p when p > textLen -> false 44 | | _ -> 45 | let mutable patternHash = 0L 46 | let mutable textHash = 0L 47 | let mutable modulusPower = 1L 48 | 49 | 50 | // Calculating the hash of pattern and substring of text 51 | for i in 0 .. (patLen - 1) do 52 | patternHash <- (int64 (pattern.[i]) + patternHash * alphabetSize) % modulus 53 | textHash <- (int64 (text.[i]) + textHash * alphabetSize) % modulus 54 | 55 | if i <> (patLen - 1) then 56 | modulusPower <- (modulusPower * alphabetSize) % modulus 57 | 58 | 59 | for i in 0 .. (textLen - patLen + 1) do 60 | if textHash = patternHash 61 | && text.[i..i + (patLen - 1)] = pattern then 62 | result <- true 63 | 64 | if not result then 65 | if i <> (textLen - patLen) then 66 | let first = 67 | (textHash - int64 (text.[i]) * modulusPower) 68 | * alphabetSize 69 | 70 | let second = int64 (text.[i + patLen]) 71 | let third = (first + second) % modulus 72 | 73 | textHash <- 74 | ((((textHash - int64 (text.[i]) * modulusPower) 75 | * alphabetSize) 76 | + int64 (text.[i + patLen])) % modulus) 77 | + modulus 78 | 79 | result 80 | -------------------------------------------------------------------------------- /Algorithms/Strings/RemoveDuplicates.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module RemoveDuplicates = 4 | /// 5 | /// Remove duplicates from sentence 6 | /// 7 | let removeDuplicates (str: string) = 8 | str.Split() |> Array.distinct |> String.concat " " 9 | -------------------------------------------------------------------------------- /Algorithms/Strings/ReverseLetters.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module ReverseLetters = 4 | /// 5 | /// Reverses letters in a given string without adjusting the position of the words 6 | /// 7 | /// String to reverse. 8 | /// Reversed string 9 | let reverseLetters (input: string) = 10 | input.Split() 11 | |> Array.map 12 | (fun x -> 13 | x.ToCharArray() 14 | |> Array.rev 15 | |> (fun c -> System.String.Concat(c))) 16 | |> String.concat " " 17 | -------------------------------------------------------------------------------- /Algorithms/Strings/ReverseWords.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module ReverseWords = 4 | /// 5 | /// Reverses words in a given string 6 | /// 7 | /// String to reverse. 8 | /// Reversed string 9 | let reverseWords (input: string): string = 10 | input.Split() |> Seq.rev |> String.concat " " 11 | -------------------------------------------------------------------------------- /Algorithms/Strings/Split.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | type Split() = 4 | /// 5 | /// Will split the string up into all the values separated by the separator 6 | /// 7 | /// String to split into lists 8 | /// The separator on what you would like to separate your strings 9 | /// A string list 10 | static member Split(str: string, ?separator0: char): string list = 11 | let mutable newStringList: string list = [] 12 | let separator = defaultArg separator0 ' ' 13 | let mutable value = "" 14 | 15 | if str.Contains separator then 16 | for c in str do 17 | match (string) c with 18 | | c when c.Contains separator -> 19 | newStringList <- newStringList |> List.append <| [ value ] 20 | value <- "" 21 | | _ -> value <- value + (string) c 22 | 23 | if value <> "" then 24 | newStringList <- newStringList |> List.append <| [ value ] 25 | value <- "" 26 | else 27 | newStringList <- [ value ] 28 | 29 | newStringList 30 | -------------------------------------------------------------------------------- /Algorithms/Strings/SwapCase.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module SwapCase = 4 | type System.Char with 5 | member this.IsUpper(): bool = 6 | match this with 7 | | c when c >= 'A' && c <= 'Z' -> true 8 | | _ -> false 9 | 10 | member this.IsLower(): bool = 11 | match this with 12 | | c when c >= 'a' && c <= 'z' -> true 13 | | _ -> false 14 | 15 | member this.Lower(): char = 16 | match this with 17 | | c when c >= 'A' && c <= 'Z' -> (char) ((int) this + 32) 18 | | _ -> this 19 | 20 | member this.Upper(): char = 21 | match this with 22 | | c when c >= 'a' && c <= 'z' -> (char) ((int) this - 32) 23 | | _ -> this 24 | 25 | /// 26 | /// This function will convert all lowercase letters to uppercase letters and vice versa 27 | /// 28 | let swapCase (sentence: string): string = 29 | let mutable newString = "" 30 | for character in sentence do 31 | match character with 32 | | c when c.IsUpper() -> newString <- newString + (string) (character.Lower()) 33 | | c when c.IsLower() -> newString <- newString + (string) (character.Upper()) 34 | | _ -> newString <- newString + (string) character 35 | newString 36 | -------------------------------------------------------------------------------- /Algorithms/Strings/Upper.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | module Upper = 4 | /// 5 | /// Will convert the entire string to uppercase letters 6 | /// 7 | /// String to change to uppercase. 8 | /// Uppercased string 9 | let upper (input: string) = 10 | input.Split() 11 | |> Array.map 12 | (fun word -> 13 | word.ToCharArray() 14 | |> Array.map 15 | (fun character -> 16 | if character >= 'a' && character <= 'z' then 17 | char (int character - 32) 18 | else 19 | character) 20 | |> (fun characters -> System.String.Concat(characters))) 21 | |> String.concat " " 22 | -------------------------------------------------------------------------------- /Algorithms/Strings/WordOccurrence.fs: -------------------------------------------------------------------------------- 1 | namespace Algorithms.Strings 2 | 3 | open System.Collections.Generic 4 | 5 | module WordOccurrence = 6 | let wordOccurrence (sentence: string): Map = 7 | // Creating a dictionary containing count of each word 8 | let mutable occurrence: Map = Map.empty 9 | 10 | for word in sentence.Split() do 11 | match word with 12 | | "" -> ignore word 13 | | w when occurrence.ContainsKey(word) -> printfn "%A" (word) 14 | | _ -> occurrence <- occurrence.Add(word, 1) 15 | 16 | occurrence 17 | -------------------------------------------------------------------------------- /Algorithms/Strings/ZFunction.fs: -------------------------------------------------------------------------------- 1 | ///https://cp-algorithms.com/string/z-function.html 2 | /// 3 | ///Z-function or Z algorithm 4 | /// 5 | ///Efficient algorithm for pattern occurrence in a string 6 | /// 7 | ///Time Complexity: O(n) - where n is the length of the string 8 | namespace Algorithms.Strings 9 | 10 | module ZFunction = 11 | 12 | let goNext (i, zResult: array, s: string) = 13 | i + zResult.[i] < s.Length 14 | && s.[zResult.[i]] = s.[i + zResult.[i]] 15 | 16 | /// 17 | /// For the given string this function computes value for each index, 18 | /// which represents the maximal length substring starting from the index 19 | /// and is the same as the prefix of the same size 20 | /// 21 | /// 22 | /// 23 | let zFunction (inputString: string): list = 24 | let mutable zResult = 25 | [| for i in 1 .. inputString.Length -> 0 |] 26 | // Initialize interval's left pointer and right pointer 27 | let mutable leftPointer, rightPointer = 0, 0 28 | 29 | for i in 1 .. inputString.Length - 1 do 30 | // Case when current index is inside the interval 31 | if i <= rightPointer then 32 | let minEdge = 33 | min (rightPointer - i + 1) (zResult.[i - leftPointer]) 34 | 35 | zResult.SetValue(minEdge, i) 36 | 37 | while goNext (i, zResult, inputString) do 38 | zResult.[i] <- zResult.[i] + 1 39 | 40 | // if new index's result gives us more right interval, 41 | // we've to update left_pointer and right_pointer 42 | if i + zResult.[i] - 1 > rightPointer then 43 | leftPointer <- i 44 | rightPointer <- i + zResult.[i] - 1 45 | 46 | zResult |> List.ofArray 47 | 48 | 49 | let findPattern (pattern: string, inputString: string): int = 50 | let mutable answer = 0 51 | // Concatenate 'pattern' and 'input_str' and call z_function 52 | // with concatenated string 53 | let zResult = zFunction (pattern + inputString) 54 | 55 | for value in zResult do 56 | // If value is greater then length of the pattern string 57 | // that means this index is starting position of substring 58 | // which is equal to pattern string 59 | if value >= pattern.Length then 60 | answer <- answer + 1 61 | 62 | answer 63 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at siryaka@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, if your changes are subjective, controversial or people are likely to have 4 | polarized opinions on this matter, please first discuss the change you wish to make via issue with the owners of 5 | this repository. 6 | 7 | We welcome adding new algorithms and data structures that were mentioned in books or other reputable sources. 8 | We also welcome fixing bugs in code, clarifying documentation and adding new test cases to check existing code. 9 | 10 | Please note that we have a code of conduct, please follow it in all your interactions with the project. 11 | -------------------------------------------------------------------------------- /DIRECTORY.md: -------------------------------------------------------------------------------- 1 | # List of all files 2 | 3 | ## Algorithms.Tests 4 | * Datastructures 5 | * [Avltree](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/DataStructures/AVLTree.fs) 6 | * [Treap](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/DataStructures/Treap.fs) 7 | * [Trie](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/DataStructures/Trie.fs) 8 | * Math 9 | * [Absmaxtests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/AbsMaxTests.fs) 10 | * [Absmintests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/AbsMinTests.fs) 11 | * [Abstests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/AbsTests.fs) 12 | * [Averagetests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/AverageTests.fs) 13 | * [Factorialtests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/FactorialTests.fs) 14 | * [Perfectnumberstests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/PerfectNumbersTests.fs) 15 | * [Powertests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/PowerTests.fs) 16 | * [Primetests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Math/PrimeTests.fs) 17 | * [Program](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Program.fs) 18 | * Search 19 | * [Binarysearchtests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Search/BinarySearchTests.fs) 20 | * Strings 21 | * [Capitalizetests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/CapitalizeTests.fs) 22 | * [Checkanagramstests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/CheckAnagramsTests.fs) 23 | * [Checkpangramtests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/CheckPangramTests.fs) 24 | * [Ispalindrometests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/IsPalindromeTests.fs) 25 | * [Jarowinklertests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/JaroWinklerTests.fs) 26 | * [Knuthmorrispratttests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/KnuthMorrisPrattTests.fs) 27 | * [Levenshteindistancetests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/LevenshteinDistanceTests.fs) 28 | * [Lowertests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/LowerTests.fs) 29 | * [Manachertests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/ManacherTests.fs) 30 | * [Mincoststringconversiontests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/MinCostStringConversionTests.fs) 31 | * [Naivestringsearchtests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/NaiveStringSearchTests.fs) 32 | * [Prefixfunctiontests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/PrefixFunctionTests.fs) 33 | * [Rabinkarptests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/RabinKarpTests.fs) 34 | * [Removeduplicatestests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/RemoveDuplicatesTests.fs) 35 | * [Reverseletterstests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/ReverseLettersTests.fs) 36 | * [Reversewordstests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/ReverseWordsTests.fs) 37 | * [Splittests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/SplitTests.fs) 38 | * [Swapcasetests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/SwapCaseTests.fs) 39 | * [Uppertests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/UpperTests.fs) 40 | * [Wordoccurrencetests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/WordOccurrenceTests.fs) 41 | * [Zfunctiontests](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms.Tests/Strings/ZFunctionTests.fs) 42 | 43 | ## Algorithms 44 | * Datastructures 45 | * [Avltree](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/DataStructures/AVLTree.fs) 46 | * [Treap](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/DataStructures/Treap.fs) 47 | * [Trie](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/DataStructures/Trie.fs) 48 | * Math 49 | * [Abs](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Abs.fs) 50 | * [Absmax](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/AbsMax.fs) 51 | * [Absmin](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/AbsMin.fs) 52 | * [Average](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Average.fs) 53 | * [Factorial](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Factorial.fs) 54 | * [Fibonacci](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Fibonacci.fs) 55 | * [Greatest Common Divisor](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Greatest_Common_Divisor.fs) 56 | * [Perfect Numbers](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Perfect_Numbers.fs) 57 | * [Power](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Power.fs) 58 | * [Prime](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Prime.fs) 59 | * Search 60 | * [Binarysearch](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Search/BinarySearch.fs) 61 | * Sort 62 | * [Bubble Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Bubble_Sort.fs) 63 | * [Comb Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Comb_Sort.fs) 64 | * [Cycle Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Cycle_Sort.fs) 65 | * [Gnome Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Gnome_Sort.fs) 66 | * [Heap Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Heap_Sort.fs) 67 | * [Insertion Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Insertion_Sort.fs) 68 | * [Merge Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Merge_Sort.fs) 69 | * [Pancake Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Pancake_Sort.fs) 70 | * [Quick Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Quick_Sort.fs) 71 | * Strings 72 | * [Capitalize](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Capitalize.fs) 73 | * [Checkanagrams](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/CheckAnagrams.fs) 74 | * [Checkpangram](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/CheckPangram.fs) 75 | * [Hasprefix](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/HasPrefix.fs) 76 | * [Hassuffix](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/HasSuffix.fs) 77 | * [Ispalindrome](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/IsPalindrome.fs) 78 | * [Jarowinkler](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/JaroWinkler.fs) 79 | * [Knuthmorrispratt](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/KnuthMorrisPratt.fs) 80 | * [Levenshteindistance](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/LevenshteinDistance.fs) 81 | * [Lower](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Lower.fs) 82 | * [Manacher](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Manacher.fs) 83 | * [Mincoststringconversion](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/MinCostStringConversion.fs) 84 | * [Naivestringsearch](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/NaiveStringSearch.fs) 85 | * [Prefixfunction](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/PrefixFunction.fs) 86 | * [Rabinkarp](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/RabinKarp.fs) 87 | * [Removeduplicates](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/RemoveDuplicates.fs) 88 | * [Reverseletters](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/ReverseLetters.fs) 89 | * [Reversewords](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/ReverseWords.fs) 90 | * [Split](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Split.fs) 91 | * [Swapcase](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/SwapCase.fs) 92 | * [Upper](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Upper.fs) 93 | * [Wordoccurrence](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/WordOccurrence.fs) 94 | * [Zfunction](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/ZFunction.fs) 95 | -------------------------------------------------------------------------------- /F-Sharp.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30503.244 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Algorithms", "Algorithms\Algorithms.fsproj", "{05E4AEE0-4C8F-4315-9A1E-067266EEF87A}" 7 | EndProject 8 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Algorithms.Tests", "Algorithms.Tests\Algorithms.Tests.fsproj", "{1EAB477C-BC19-45B3-9C92-65B3D0E57BED}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {05E4AEE0-4C8F-4315-9A1E-067266EEF87A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {05E4AEE0-4C8F-4315-9A1E-067266EEF87A}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {05E4AEE0-4C8F-4315-9A1E-067266EEF87A}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {05E4AEE0-4C8F-4315-9A1E-067266EEF87A}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {1EAB477C-BC19-45B3-9C92-65B3D0E57BED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {1EAB477C-BC19-45B3-9C92-65B3D0E57BED}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {1EAB477C-BC19-45B3-9C92-65B3D0E57BED}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {1EAB477C-BC19-45B3-9C92-65B3D0E57BED}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {A93F8F74-2A01-4C5F-BACB-9E30FDD87C26} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 The Algorithms 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The Algorithms - F# 2 | [![Run tests on CI](https://github.com/TheAlgorithms/F-Sharp/actions/workflows/tests.yml/badge.svg)](https://github.com/TheAlgorithms/F-Sharp/actions/workflows/tests.yml) 3 |
4 | This repository contains algorithms and data structures implemented in F# for eductional purposes. 5 | 6 | ## Overview 7 | + [Algorithms](https://github.com/TheAlgorithms/F-Sharp/tree/main/Algorithms) 8 | + [Math](https://github.com/TheAlgorithms/F-Sharp/tree/main/Algorithms/Math) 9 | + [Abs](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Abs.fs) 10 | + [Abs Maximum](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/AbsMax.fs) 11 | + [Abs Minimum](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/AbsMin.fs) 12 | + [Average](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Average.fs) 13 | + [Factorial](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Factorial.fs) 14 | + [Fibonacci](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Fibonacci.fs) 15 | + [Greatest Common Divisor](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Greatest_Common_Divisor.fs) 16 | + [Perfect Numbers](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Perfect_Numbers.fs) 17 | + [Power](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Math/Power.fs) 18 | + [Search](https://github.com/TheAlgorithms/F-Sharp/tree/main/Algorithms/Search) 19 | + [Binary Search](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Search/BinarySearch.fs) 20 | + [Sort](https://github.com/TheAlgorithms/F-Sharp/tree/main/Algorithms/Sort) 21 | + [Bubble Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Bubble_Sort.fs) 22 | + [Comb Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Comb_Sort.fs) 23 | + [Cycle Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Cycle_Sort.fs) 24 | + [Gnome Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Gnome_Sort.fs) 25 | + [Heap Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Heap_Sort.fs) 26 | + [Insertion Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Insertion_Sort.fs) 27 | + [Merge Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Merge_Sort.fs) 28 | + [Pancake Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Pancake_Sort.fs) 29 | + [Quick Sort](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Sort/Quick_Sort.fs) 30 | + [Strings](https://github.com/TheAlgorithms/F-Sharp/tree/main/Algorithms/Strings) 31 | + [Capitalize](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Capitalize.fs) 32 | + [Check Anagrams](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/CheckAnagrams.fs) 33 | + [Check Pangram](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/CheckPangram.fs) 34 | + [Is Palindrome](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/IsPalindrome.fs) 35 | + [Jaro Winkler](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/JaroWinkler.fs) 36 | + [Knuth Morris Pratt](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/KnuthMorrisPratt.fs) 37 | + [Levenshtein Distance](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/LevenshteinDistance.fs) 38 | + [Lower](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Lower.fs) 39 | + [Manacher](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Manacher.fs) 40 | + [Min Cost String Conversion](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/MinCostStringConversion.fs) 41 | + [Navie String Search](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/NaiveStringSearch.fs) 42 | + [Prefix Function](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/PrefixFunction.fs) 43 | + [Rabin Karp](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/RabinKarp.fs) 44 | + [Remove Duplicates](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/RemoveDuplicates.fs) 45 | + [Reversel Letters](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/ReverseLetters.fs) 46 | + [Reverse Words](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/ReverseWords.fs) 47 | + [Split](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Split.fs) 48 | + [Swap Case](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/SwapCase.fs) 49 | + [Upper](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/Upper.fs) 50 | + [Word Occurrence](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/WordOccurrence.fs) 51 | + [Z Function](https://github.com/TheAlgorithms/F-Sharp/blob/main/Algorithms/Strings/ZFunction.fs) 52 | 53 | ## Contribution 54 | You can contribute with pleasure to this repository. Please orient on the directory structure and overall code style of this repository. 55 | If you want to ask a question or suggest something, please open an issue. 56 | --------------------------------------------------------------------------------