├── assets ├── TUM.png ├── bst.gif ├── dll.png ├── heap.gif ├── list.gif ├── sll.png ├── sqrt.png ├── ufds.gif ├── graphds.gif ├── graphs.gif ├── primes.png ├── sorting.gif ├── VisuAlgo.png ├── trees │ ├── bst.png │ ├── cbt.png │ ├── fbt.png │ ├── nbst.png │ ├── ncbt.png │ ├── nfbt.png │ ├── avl │ │ ├── bf.jpeg │ │ ├── left.jpeg │ │ ├── right.jpeg │ │ ├── left-right.jpeg │ │ └── right-left.jpeg │ ├── bst-dark.png │ ├── btorder.png │ ├── cbt-dark.png │ ├── fbt-dark.png │ ├── nbst-dark.png │ ├── ncbt-dark.png │ ├── nfbt-dark.png │ ├── btorder-dark.png │ ├── red-black │ │ ├── rb-case1.png │ │ ├── rb-case1-dark.png │ │ ├── rb-case2-after.png │ │ ├── rb-case3-after.png │ │ ├── rb-case4-after.png │ │ ├── rb-case2-before.png │ │ ├── rb-case3-before.png │ │ ├── rb-case3-rotate.png │ │ ├── rb-case4-before.png │ │ ├── rb-case2-after-dark.png │ │ ├── rb-case3-after-dark.png │ │ ├── rb-case4-after-dark.png │ │ ├── rb-case2-before-dark.png │ │ ├── rb-case3-before-dark.png │ │ ├── rb-case3-rotate-dark.png │ │ └── rb-case4-before-dark.png │ └── rotations │ │ ├── left-left.png │ │ ├── left-right.png │ │ ├── right-left.png │ │ ├── right-right.png │ │ ├── left-left-dark.png │ │ ├── left-right-dark.png │ │ ├── right-left-dark.png │ │ └── right-right-dark.png ├── heap_arr_dark.png ├── heap_arr_light.png ├── heap_tree_dark.png ├── heap_tree_light.png ├── logo │ ├── rust-logo.png │ └── csharp-logo.png ├── primes_compare.png └── logo-algos.svg ├── rust ├── .vscode │ └── settings.json ├── src │ ├── main.rs │ ├── primes │ │ ├── mod.rs │ │ ├── trial_division.rs │ │ ├── sieve_of_eratosthenes.rs │ │ └── dijkstra_primes.rs │ ├── sorting │ │ ├── mod.rs │ │ ├── bubble_sort.rs │ │ ├── heap_sort.rs │ │ ├── selection_sort.rs │ │ ├── quicksort.rs │ │ ├── shell_sort.rs │ │ ├── insertion_sort.rs │ │ └── merge_sort.rs │ ├── graphs │ │ ├── mod.rs │ │ ├── tarjan_state.rs │ │ ├── kruskal.rs │ │ ├── tarjan.rs │ │ ├── dfs.rs │ │ ├── bfs.rs │ │ ├── prim.rs │ │ ├── floyd_warshall.rs │ │ ├── dijkstra.rs │ │ ├── bellman_ford.rs │ │ ├── kosaraju.rs │ │ └── graph.rs │ └── data_structures │ │ ├── mod.rs │ │ ├── disjoint_set.rs │ │ ├── linked_list.rs │ │ ├── heap.rs │ │ ├── red_black_tree.rs │ │ ├── binary_search_tree.rs │ │ └── avl_tree.rs ├── Cargo.lock ├── target │ ├── CACHEDIR.TAG │ └── .rustc_info.json └── Cargo.toml ├── csharp ├── RadixSort │ ├── Program.cs │ └── RadixSort.csproj ├── Graphs │ ├── Graphs.csproj │ └── Graph.cs ├── AVLTree │ ├── AVLTree.csproj │ └── AVLTree.cs ├── BinaryHeap │ ├── BinaryHeap.csproj │ └── Heap.cs ├── LinkedList │ ├── LinkedList.csproj │ └── SinglyLinkedList.cs ├── UnionFind │ ├── UnionFind.csproj │ └── UnionFindSet.cs ├── BinarySearchTree │ ├── BinarySearchTree.csproj │ └── BinarySearchTree.cs ├── RedBlackTree │ ├── RedBlackTree.csproj │ └── RedBlackTree.cs ├── TrialDivision │ ├── TrialDivision.csproj │ └── Program.cs ├── DijkstraPrimes │ ├── DijkstraPrimes.csproj │ └── Program.cs ├── SieveOfEratosthenes │ ├── SieveOfEratosthenes.csproj │ └── Program.cs ├── MergeSort │ ├── MergeSort.csproj │ └── Program.cs ├── QuickSort │ ├── QuickSort.csproj │ └── Program.cs ├── ShellSort │ ├── ShellSort.csproj │ └── Program.cs ├── BubbleSort │ ├── BubbleSort.csproj │ └── Program.cs ├── InsertionSort │ ├── InsertionSort.csproj │ └── Program.cs ├── SelectionSort │ ├── SelectionSort.csproj │ └── Program.cs ├── Prim │ ├── Prim.csproj │ └── GraphExtensions.cs ├── Dijkstra │ ├── Dijkstra.csproj │ └── GraphExtensions.cs ├── Kosaraju │ ├── Kosaraju.csproj │ └── GraphExtensions.cs ├── DepthFirstSearch │ ├── DepthFirstSearch.csproj │ └── GraphExtensions.cs ├── BreadthFirstSearch │ ├── BreadthFirstSearch.csproj │ └── GraphExtensions.cs ├── BellmanFord │ ├── BellmanFord.csproj │ └── GraphExtensions.cs ├── Kruskal │ ├── Kruskal.csproj │ └── GraphExtensions.cs ├── HeapSort │ ├── HeapSort.csproj │ └── Program.cs └── Floyd–Warshall │ ├── Floyd–Warshall.csproj │ └── GraphExtensions.cs └── .gitignore /assets/TUM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/TUM.png -------------------------------------------------------------------------------- /assets/bst.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/bst.gif -------------------------------------------------------------------------------- /assets/dll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/dll.png -------------------------------------------------------------------------------- /assets/heap.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/heap.gif -------------------------------------------------------------------------------- /assets/list.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/list.gif -------------------------------------------------------------------------------- /assets/sll.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/sll.png -------------------------------------------------------------------------------- /assets/sqrt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/sqrt.png -------------------------------------------------------------------------------- /assets/ufds.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/ufds.gif -------------------------------------------------------------------------------- /rust/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.showUnlinkedFileNotification": false 3 | } -------------------------------------------------------------------------------- /assets/graphds.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/graphds.gif -------------------------------------------------------------------------------- /assets/graphs.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/graphs.gif -------------------------------------------------------------------------------- /assets/primes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/primes.png -------------------------------------------------------------------------------- /assets/sorting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/sorting.gif -------------------------------------------------------------------------------- /assets/VisuAlgo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/VisuAlgo.png -------------------------------------------------------------------------------- /assets/trees/bst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/bst.png -------------------------------------------------------------------------------- /assets/trees/cbt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/cbt.png -------------------------------------------------------------------------------- /assets/trees/fbt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/fbt.png -------------------------------------------------------------------------------- /assets/trees/nbst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/nbst.png -------------------------------------------------------------------------------- /assets/trees/ncbt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/ncbt.png -------------------------------------------------------------------------------- /assets/trees/nfbt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/nfbt.png -------------------------------------------------------------------------------- /assets/heap_arr_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/heap_arr_dark.png -------------------------------------------------------------------------------- /assets/heap_arr_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/heap_arr_light.png -------------------------------------------------------------------------------- /assets/heap_tree_dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/heap_tree_dark.png -------------------------------------------------------------------------------- /assets/heap_tree_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/heap_tree_light.png -------------------------------------------------------------------------------- /assets/logo/rust-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/logo/rust-logo.png -------------------------------------------------------------------------------- /assets/primes_compare.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/primes_compare.png -------------------------------------------------------------------------------- /assets/trees/avl/bf.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/avl/bf.jpeg -------------------------------------------------------------------------------- /assets/trees/avl/left.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/avl/left.jpeg -------------------------------------------------------------------------------- /assets/trees/bst-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/bst-dark.png -------------------------------------------------------------------------------- /assets/trees/btorder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/btorder.png -------------------------------------------------------------------------------- /assets/trees/cbt-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/cbt-dark.png -------------------------------------------------------------------------------- /assets/trees/fbt-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/fbt-dark.png -------------------------------------------------------------------------------- /assets/trees/nbst-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/nbst-dark.png -------------------------------------------------------------------------------- /assets/trees/ncbt-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/ncbt-dark.png -------------------------------------------------------------------------------- /assets/trees/nfbt-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/nfbt-dark.png -------------------------------------------------------------------------------- /assets/logo/csharp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/logo/csharp-logo.png -------------------------------------------------------------------------------- /assets/trees/avl/right.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/avl/right.jpeg -------------------------------------------------------------------------------- /rust/src/main.rs: -------------------------------------------------------------------------------- 1 | mod data_structures; 2 | mod graphs; 3 | mod primes; 4 | mod sorting; 5 | 6 | fn main() { 7 | } 8 | -------------------------------------------------------------------------------- /assets/trees/btorder-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/btorder-dark.png -------------------------------------------------------------------------------- /assets/trees/avl/left-right.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/avl/left-right.jpeg -------------------------------------------------------------------------------- /assets/trees/avl/right-left.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/avl/right-left.jpeg -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case1.png -------------------------------------------------------------------------------- /assets/trees/rotations/left-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/left-left.png -------------------------------------------------------------------------------- /rust/src/primes/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | mod dijkstra_primes; 3 | mod trial_division; 4 | mod sieve_of_eratosthenes; 5 | -------------------------------------------------------------------------------- /assets/trees/rotations/left-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/left-right.png -------------------------------------------------------------------------------- /assets/trees/rotations/right-left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/right-left.png -------------------------------------------------------------------------------- /assets/trees/rotations/right-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/right-right.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case1-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case1-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case2-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case2-after.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case3-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case3-after.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case4-after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case4-after.png -------------------------------------------------------------------------------- /assets/trees/rotations/left-left-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/left-left-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case2-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case2-before.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case3-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case3-before.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case3-rotate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case3-rotate.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case4-before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case4-before.png -------------------------------------------------------------------------------- /assets/trees/rotations/left-right-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/left-right-dark.png -------------------------------------------------------------------------------- /assets/trees/rotations/right-left-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/right-left-dark.png -------------------------------------------------------------------------------- /assets/trees/rotations/right-right-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/rotations/right-right-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case2-after-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case2-after-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case3-after-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case3-after-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case4-after-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case4-after-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case2-before-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case2-before-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case3-before-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case3-before-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case3-rotate-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case3-rotate-dark.png -------------------------------------------------------------------------------- /assets/trees/red-black/rb-case4-before-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnastasKosstow/algorithms/HEAD/assets/trees/red-black/rb-case4-before-dark.png -------------------------------------------------------------------------------- /rust/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "rust" 7 | version = "0.1.0" 8 | -------------------------------------------------------------------------------- /rust/src/sorting/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | mod bubble_sort; 3 | mod selection_sort; 4 | mod insertion_sort; 5 | mod shell_sort; 6 | mod heap_sort; 7 | mod merge_sort; 8 | mod quicksort; -------------------------------------------------------------------------------- /rust/target/CACHEDIR.TAG: -------------------------------------------------------------------------------- 1 | Signature: 8a477f597d28d172789f06886806bc55 2 | # This file is a cache directory tag created by cargo. 3 | # For information about cache directory tags see https://bford.info/cachedir/ 4 | -------------------------------------------------------------------------------- /csharp/RadixSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 7253, 3864, 573, 8511, 9619, 2608, 5455, 571, 1, 0 }; 2 | arr = Sort(arr); 3 | 4 | int[] Sort(int[] sourceArray) 5 | { 6 | throw new NotImplementedException(); 7 | } 8 | -------------------------------------------------------------------------------- /rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /csharp/Graphs/Graphs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/AVLTree/AVLTree.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/BinaryHeap/BinaryHeap.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/LinkedList/LinkedList.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/UnionFind/UnionFind.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/BinarySearchTree/BinarySearchTree.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/RedBlackTree/RedBlackTree.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /csharp/TrialDivision/TrialDivision.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /csharp/DijkstraPrimes/DijkstraPrimes.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /csharp/SieveOfEratosthenes/SieveOfEratosthenes.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /rust/src/graphs/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | mod bfs; 3 | mod dfs; 4 | mod dijkstra; 5 | mod bellman_ford; 6 | mod floyd_warshall; 7 | mod kosaraju; 8 | mod kruskal; 9 | mod prim; 10 | mod tarjan_state; 11 | mod tarjan; 12 | mod graph; 13 | 14 | pub use graph::{Graph, GraphType, Node, NodeIndex, Edge}; -------------------------------------------------------------------------------- /csharp/MergeSort/MergeSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/QuickSort/QuickSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/RadixSort/RadixSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/ShellSort/ShellSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/BubbleSort/BubbleSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/InsertionSort/InsertionSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/SelectionSort/SelectionSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /csharp/Prim/Prim.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp/Dijkstra/Dijkstra.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp/Kosaraju/Kosaraju.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp/DepthFirstSearch/DepthFirstSearch.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp/BreadthFirstSearch/BreadthFirstSearch.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /csharp/BellmanFord/BellmanFord.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /csharp/Kruskal/Kruskal.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /csharp/HeapSort/HeapSort.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /csharp/Floyd–Warshall/Floyd–Warshall.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | Floyd_Warshall 6 | enable 7 | enable 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /rust/src/data_structures/mod.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | mod avl_tree; 3 | mod red_black_tree; 4 | mod binary_search_tree; 5 | mod disjoint_set; 6 | mod linked_list; 7 | mod heap; 8 | 9 | pub use avl_tree::AvlTree; 10 | pub use avl_tree::TreeNode; 11 | pub use red_black_tree::RedBlackTree; 12 | pub use binary_search_tree::BinarySearchTree; 13 | pub use disjoint_set::DisjointSet; 14 | pub use linked_list::LinkedList; 15 | pub use heap::Heap; 16 | pub use heap::HeapType; -------------------------------------------------------------------------------- /csharp/TrialDivision/Program.cs: -------------------------------------------------------------------------------- 1 | const int PRIMES_UP_TO = 100; 2 | 3 | var primes = new List(); 4 | 5 | for (int number = 2; number <= PRIMES_UP_TO; number++) 6 | { 7 | bool isPrime = true; 8 | for (int primeIndex = 0; primeIndex < Math.Sqrt(primes.Count); primeIndex++) 9 | { 10 | if (primes.Any() && number % primes[primeIndex] == 0) 11 | { 12 | isPrime = false; 13 | break; 14 | } 15 | } 16 | 17 | if (isPrime) 18 | primes.Add(number); 19 | } 20 | -------------------------------------------------------------------------------- /csharp/SieveOfEratosthenes/Program.cs: -------------------------------------------------------------------------------- 1 | const int PRIMES_UP_TO = 100; 2 | 3 | var sieve = Enumerable.Repeat(true, PRIMES_UP_TO).ToArray(); 4 | sieve[0] = false; 5 | sieve[1] = false; 6 | 7 | for (int number = 0; number < Math.Sqrt(PRIMES_UP_TO); number++) 8 | { 9 | if (sieve[number] == true) 10 | { 11 | var multiple = number * number; 12 | while (multiple < PRIMES_UP_TO) 13 | { 14 | sieve[multiple] = false; 15 | multiple += number; 16 | } 17 | } 18 | } 19 | 20 | var primes = new List(); 21 | for (int index = 0; index < sieve.Length; index++) 22 | { 23 | if (sieve[index]) 24 | primes.Add(index); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /rust/src/graphs/tarjan_state.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{HashMap, HashSet}; 2 | 3 | use super::NodeIndex; 4 | 5 | pub struct State { 6 | pub nodes_discovery_time: HashMap, 7 | pub nodes_low_link_value: HashMap, 8 | pub parent_node: HashMap, 9 | pub visited: HashSet, 10 | pub discovery_time: i32, 11 | } 12 | 13 | impl State { 14 | pub fn new() -> Self { 15 | State { 16 | nodes_discovery_time: HashMap::new(), 17 | nodes_low_link_value: HashMap::new(), 18 | parent_node: HashMap::new(), 19 | visited: HashSet::new(), 20 | discovery_time: 0 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /rust/src/sorting/bubble_sort.rs: -------------------------------------------------------------------------------- 1 | pub fn bubble_sort(arr: &mut [T]) { 2 | if arr.is_empty() { 3 | return; 4 | } 5 | for index in (0..arr.len()).rev() { 6 | for sort_index in 0..index { 7 | if arr[sort_index] > arr[sort_index + 1] { 8 | arr.swap(sort_index, sort_index + 1) 9 | } 10 | } 11 | } 12 | } 13 | 14 | #[cfg(test)] 15 | mod tests { 16 | use super::*; 17 | 18 | #[test] 19 | fn empty() { 20 | let mut empty_vec: Vec = Vec::new(); 21 | bubble_sort(&mut empty_vec); 22 | 23 | assert!(empty_vec.is_empty()); 24 | } 25 | 26 | #[test] 27 | fn sort() { 28 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 29 | bubble_sort(&mut arr); 30 | 31 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /rust/target/.rustc_info.json: -------------------------------------------------------------------------------- 1 | {"rustc_fingerprint":3823893406534814463,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.75.0 (82e1608df 2023-12-21)\nbinary: rustc\ncommit-hash: 82e1608dfa6e0b5569232559e3d385fea5a93112\ncommit-date: 2023-12-21\nhost: x86_64-pc-windows-msvc\nrelease: 1.75.0\nLLVM version: 17.0.6\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\kosstow\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}} -------------------------------------------------------------------------------- /rust/src/sorting/heap_sort.rs: -------------------------------------------------------------------------------- 1 | use crate::data_structures::{Heap, HeapType}; 2 | 3 | pub fn heap_sort(arr: &mut [T]) { 4 | if arr.is_empty() { 5 | return; 6 | } 7 | 8 | let mut heap: Heap = Heap::::new(HeapType::Min); 9 | let length = arr.len(); 10 | 11 | for item in arr.iter() { 12 | heap.push(*item); 13 | } 14 | 15 | for index in 0..length { 16 | if let Some(item) = heap.pop() { 17 | arr[index] = item; 18 | } 19 | } 20 | } 21 | 22 | #[cfg(test)] 23 | mod tests { 24 | use super::*; 25 | 26 | #[test] 27 | fn empty() { 28 | let mut empty_vec: Vec = Vec::new(); 29 | heap_sort(&mut empty_vec); 30 | 31 | assert!(empty_vec.is_empty()); 32 | } 33 | 34 | #[test] 35 | fn sort() { 36 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 37 | heap_sort(&mut arr); 38 | 39 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /csharp/InsertionSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6 }; 2 | 3 | // Start the loop from the second element, since the first element is considered sorted in Insertion sort 4 | for (int index = 1; index < arr.Length; index++) 5 | { 6 | // The current item to be placed in the correct position 7 | int currentItem = arr[index]; 8 | 9 | // Find the position where the current item should be inserted 10 | // Start from the element before the current item and move backwards 11 | int insertionIndex = index - 1; 12 | 13 | // Move elements that are greater than the current item to one position ahead of their current position, 14 | // to make space for inserting the current item. 15 | while (insertionIndex >= 0 && arr[insertionIndex] > currentItem) 16 | { 17 | arr[insertionIndex + 1] = arr[insertionIndex]; 18 | insertionIndex--; 19 | } 20 | 21 | // Insert the current item in its correct position. 22 | arr[insertionIndex + 1] = currentItem; 23 | } 24 | -------------------------------------------------------------------------------- /csharp/SelectionSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6 }; 2 | 3 | // Iterate over the array. Each iteration finds the minimum element in the unsorted part 4 | for (int index = 0; index < arr.Length - 1; index++) 5 | { 6 | // Assume the first element in the unsorted part is the minimum 7 | var currentMinValue = arr[index]; 8 | var currentMinIndex = index; 9 | 10 | // Iterate over the unsorted part of the array 11 | for (int compareIndex = index + 1; compareIndex < arr.Length; compareIndex++) 12 | { 13 | // If a smaller element is found, update currentMinValue and currentMinIndex 14 | if (currentMinValue > arr[compareIndex]) 15 | { 16 | currentMinValue = arr[compareIndex]; 17 | currentMinIndex = compareIndex; 18 | } 19 | } 20 | // Swap the found minimum element with the first element in the unsorted part 21 | Swap(ref arr[index], ref arr[currentMinIndex]); 22 | } 23 | 24 | void Swap(ref int x1, ref int x2) => (x2, x1) = (x1, x2); 25 | -------------------------------------------------------------------------------- /rust/src/sorting/selection_sort.rs: -------------------------------------------------------------------------------- 1 | pub fn selection_sort(arr: &mut [T]) { 2 | if arr.is_empty() { 3 | return; 4 | } 5 | let mut index: usize = 0; 6 | while index < arr.len() { 7 | let mut min_index: usize = index; 8 | 9 | for compare_index in index+1..arr.len() { 10 | if arr[min_index] > arr[compare_index] { 11 | min_index = compare_index; 12 | } 13 | } 14 | 15 | arr.swap(index, min_index); 16 | index += 1; 17 | } 18 | } 19 | 20 | #[cfg(test)] 21 | mod tests { 22 | use super::*; 23 | 24 | #[test] 25 | fn empty() { 26 | let mut empty_vec: Vec = Vec::new(); 27 | selection_sort(&mut empty_vec); 28 | 29 | assert!(empty_vec.is_empty()); 30 | } 31 | 32 | #[test] 33 | fn sort() { 34 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 35 | selection_sort(&mut arr); 36 | 37 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /rust/src/primes/trial_division.rs: -------------------------------------------------------------------------------- 1 | pub fn trieal_division(up_to: usize) -> Vec { 2 | if up_to < 2 { 3 | return vec![]; 4 | } 5 | 6 | let mut primes: Vec = Vec::new(); 7 | 8 | for number in 2..up_to { 9 | let mut is_prime = true; 10 | let sqrt_number = (number as f64).sqrt() as usize; 11 | for prime_index in 0..sqrt_number { 12 | if primes.len() > 0 && number % primes[prime_index] == 0 { 13 | is_prime = false; 14 | break; 15 | } 16 | } 17 | 18 | if is_prime { 19 | primes.push(number); 20 | } 21 | } 22 | primes 23 | } 24 | 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use super::*; 29 | 30 | #[test] 31 | fn test_trieal_division() { 32 | let primes: Vec = trieal_division(1000000); 33 | assert!(!primes.is_empty()); 34 | assert_eq!(primes.len(), 78498); 35 | assert_eq!(primes.first().unwrap(), &2); 36 | assert_eq!(primes.last().unwrap(), &999983); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /csharp/HeapSort/Program.cs: -------------------------------------------------------------------------------- 1 | using BinaryHeap; 2 | 3 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6 }; 4 | 5 | // Create a min heap. A min heap is used here because we want to sort the array in ascending order. 6 | // In a min heap, the smallest element is always at the root. Therefore, by continuously removing the root, we can obtain the elements in ascending order. 7 | // We can use already implemented heap structure from: DataStructures -> BinaryHeap 8 | var heap = new Heap(HeapType.Min); 9 | 10 | // Build the heap. 11 | // Insert all elements of the array into the heap. 12 | // The heap will rearrange these elements to maintain the min heap property, where the parent is smaller than its children. 13 | foreach (int item in arr) 14 | { 15 | heap.Push(item); 16 | } 17 | 18 | // Extract elements from the heap one by one and store them back into the array. 19 | // Since this is a min heap, each time we call Pop(), we get the smallest remaining element. 20 | // By doing this for each element, we are effectively sort the array. 21 | for (int index = 0; index < arr.Length; index++) 22 | { 23 | arr[index] = heap.Pop(); 24 | } 25 | -------------------------------------------------------------------------------- /rust/src/data_structures/disjoint_set.rs: -------------------------------------------------------------------------------- 1 | pub struct DisjointSet { 2 | parent: Vec, 3 | rank: Vec 4 | } 5 | 6 | impl DisjointSet { 7 | pub fn new(size: usize) -> Self { 8 | DisjointSet { 9 | parent: (0..size).collect(), 10 | rank: vec![0; size] 11 | } 12 | } 13 | 14 | pub fn find(&mut self, index: usize) -> usize { 15 | if self.parent[index] != index { 16 | self.parent[index] = self.find(self.parent[index]); 17 | } 18 | self.parent[index] 19 | } 20 | 21 | pub fn union(&mut self, x: usize, y: usize) { 22 | let x_root = self.find(x); 23 | let y_root = self.find(y); 24 | 25 | if x_root == y_root { 26 | return; 27 | } 28 | 29 | if self.rank[x_root] < self.rank[y_root] { 30 | self.parent[x_root] = y_root; 31 | } 32 | else if self.rank[x_root] > self.rank[y_root] { 33 | self.parent[y_root] = x_root; 34 | } 35 | else { 36 | self.parent[y_root] = x_root; 37 | self.rank[x_root] += 1; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /rust/src/primes/sieve_of_eratosthenes.rs: -------------------------------------------------------------------------------- 1 | pub fn sieve_of_eratosthenes(up_to: usize) -> Vec { 2 | if up_to < 2 { 3 | return vec![]; 4 | } 5 | 6 | let mut sieve: Vec = vec![true; up_to]; 7 | sieve[0] = false; 8 | sieve[1] = false; 9 | 10 | let sqrt_limit = (up_to as f64).sqrt() as usize; 11 | for number in 2..sqrt_limit + 1 { 12 | if sieve[number] == true { 13 | let mut multiple = number * number; 14 | while multiple < up_to { 15 | sieve[multiple] = false; 16 | multiple += number; 17 | } 18 | } 19 | } 20 | sieve.iter().enumerate() 21 | .filter_map(|(number, &is_prime)| if is_prime { Some(number) } else { None }) 22 | .collect() 23 | } 24 | 25 | 26 | #[cfg(test)] 27 | mod tests { 28 | use super::*; 29 | 30 | #[test] 31 | fn test_sieve_of_eratosthenes() { 32 | let primes: Vec = sieve_of_eratosthenes(1000000); 33 | assert!(!primes.is_empty()); 34 | assert_eq!(primes.len(), 78498); 35 | assert_eq!(primes.first().unwrap(), &2); 36 | assert_eq!(primes.last().unwrap(), &999983); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /csharp/BubbleSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6 }; 2 | 3 | bool sorted; 4 | 5 | // Initialize the index for the last sorted element to the array's length 6 | // In bubbleSort after every iteration, the largest element in the unsorted part will move to its correct position at the end 7 | // So after each iteration we do not need to check - arr.Length - index 8 | int indexOfLastSortedElement = arr.Length; 9 | do 10 | { 11 | // Assume the array is sorted, change the value to false if a swap occurs 12 | sorted = true; 13 | for (int index = 1; index < indexOfLastSortedElement; index++) 14 | { 15 | // Compare each pair of elements 16 | // if they are out of order, swap 17 | if (arr[index - 1] > arr[index]) 18 | { 19 | Swap(ref arr[index - 1], ref arr[index]); 20 | 21 | // Since a swap is made, mark the array as unsorted 22 | sorted = false; 23 | } 24 | } 25 | // Decrease the index of the last unsorted element by one 26 | // As the largest element in the unsorted part has moved to its correct position at the end 27 | indexOfLastSortedElement--; 28 | 29 | } while (!sorted); // Repeat until no swaps occurs and sorted variable stay as true 30 | 31 | void Swap(ref int x1, ref int x2) => (x2, x1) = (x1, x2); 32 | -------------------------------------------------------------------------------- /rust/src/sorting/quicksort.rs: -------------------------------------------------------------------------------- 1 | pub fn quicksort(arr: &mut [T]) { 2 | if arr.is_empty() { 3 | return; 4 | } 5 | sort(arr, 0, arr.len() - 1); 6 | } 7 | 8 | fn sort(arr: &mut [T], left: usize, right: usize) { 9 | if left < right { 10 | let pivot_index = partition(arr, left, right); 11 | sort(arr, left, pivot_index); 12 | sort(arr, pivot_index + 1, right); 13 | } 14 | } 15 | 16 | fn partition(arr: &mut [T], left: usize, right: usize) -> usize { 17 | let pivot = right; 18 | let mut p_left = left; 19 | let mut p_right = right - 1; 20 | 21 | loop { 22 | while arr[p_left] < arr[pivot] { 23 | p_left += 1; 24 | } 25 | 26 | while arr[p_right] > arr[pivot] { 27 | p_right -= 1; 28 | } 29 | 30 | if p_left >= p_right { 31 | arr.swap(p_left, pivot); 32 | return p_right; 33 | } 34 | arr.swap(p_left, p_right); 35 | p_left += 1; 36 | p_right -= 1; 37 | } 38 | } 39 | 40 | #[cfg(test)] 41 | mod tests { 42 | use super::*; 43 | 44 | #[test] 45 | fn empty() { 46 | let mut empty_vec: Vec = Vec::new(); 47 | quicksort(&mut empty_vec); 48 | 49 | assert!(empty_vec.is_empty()); 50 | } 51 | 52 | #[test] 53 | fn sort() { 54 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 55 | quicksort(&mut arr); 56 | 57 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /csharp/ShellSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6, 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6, 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6, }; 2 | int[] sequence = GenerateKnuthSequence(arr.Length); 3 | 4 | // Iterate over the Knuth sequence 5 | // and perform insertion sort for every step 6 | for (int stepIndex = 0; stepIndex < sequence.Length; stepIndex++) 7 | { 8 | int step = sequence[stepIndex]; 9 | 10 | for (int index = step; index < arr.Length; index++) 11 | { 12 | var currentItem = arr[index]; 13 | int compareIndex = index - step; 14 | 15 | // Shift elements that are step distance apart and greater than currentItem 16 | while (compareIndex >= 0 && currentItem < arr[compareIndex]) 17 | { 18 | arr[compareIndex + step] = arr[compareIndex]; 19 | compareIndex -= step; 20 | } 21 | 22 | // Place currentItem in its correct position 23 | arr[compareIndex + step] = currentItem; 24 | } 25 | } 26 | 27 | // Generate the Knuth sequence based on the array size 28 | // 1, 4, 13, 40, 121, ... 29 | static int[] GenerateKnuthSequence(int arraySize) 30 | { 31 | int gapSequenceLength = (int)Math.Floor(Math.Log(arraySize, 3)) - 1; 32 | 33 | int[] knuthSequence = new int[gapSequenceLength]; 34 | int value = 1; 35 | 36 | for (int index = 0; index < gapSequenceLength; index++) 37 | { 38 | knuthSequence[index] = (value); 39 | value = 3 * value + 1; // Calculate the next gap size 40 | } 41 | 42 | Array.Reverse(knuthSequence); // Reverse the sequence as per Knuth's suggestion 43 | return knuthSequence; 44 | } 45 | -------------------------------------------------------------------------------- /rust/src/sorting/shell_sort.rs: -------------------------------------------------------------------------------- 1 | pub fn shell_sort(arr: &mut [T]) { 2 | if arr.is_empty() { 3 | return; 4 | } 5 | let sequence: Vec = generate_knuth_sequence(arr.len()); 6 | 7 | for seq_value in sequence.iter() { 8 | let seq_value = *seq_value as usize; // Dereference to get the i32 value 9 | 10 | for index in seq_value..arr.len() { 11 | let current_item: T = arr[index]; 12 | let mut compare_index: usize = index; 13 | 14 | while compare_index >= seq_value && arr[compare_index - seq_value] > current_item { 15 | arr[compare_index] = arr[compare_index - seq_value]; 16 | compare_index -= seq_value; 17 | } 18 | arr[compare_index] = current_item; 19 | } 20 | } 21 | } 22 | 23 | // Generate the Knuth sequence based on the array size 24 | // 1, 4, 13, 40, 121, ... 25 | fn generate_knuth_sequence(array_size: usize) -> Vec { 26 | let gap_sequence_length = (f64::log(array_size as f64, 3.0)).floor() as usize - 1; 27 | 28 | let mut knuth_sequence: Vec = Vec::with_capacity(gap_sequence_length); 29 | let mut value: i32 = 1; 30 | knuth_sequence.push(value); 31 | 32 | for _index in 0..gap_sequence_length { 33 | value = 3 * value + 1; // Calculate the next gap size 34 | knuth_sequence.push(value); 35 | } 36 | 37 | knuth_sequence.reverse(); // Reverse the sequence as per Knuth's suggestion 38 | knuth_sequence 39 | } 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use super::*; 44 | 45 | #[test] 46 | fn empty() { 47 | let mut empty_vec: Vec = Vec::new(); 48 | shell_sort(&mut empty_vec); 49 | 50 | assert!(empty_vec.is_empty()); 51 | } 52 | 53 | #[test] 54 | fn sort() { 55 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 56 | shell_sort(&mut arr); 57 | 58 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /csharp/DepthFirstSearch/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | 3 | namespace DepthFirstSearch; 4 | 5 | /* 6 | for graph with nodes: A, B, C, D 7 | where: A -> B and C; B and C -> D 8 | A 9 | / \ 10 | B C 11 | \ / 12 | D 13 | 14 | DFS traversal sequence: A -> C -> D -> B 15 | */ 16 | 17 | public static class GraphExtensions 18 | { 19 | public static void DFS(this Graph graph, T startValue) 20 | { 21 | // Retrieve the start node from the graph using the provided value 22 | // If the start node is not found, handle the error appropriately 23 | var startNode = graph.GetNode(startValue); 24 | if (startNode == null) 25 | { 26 | // handle 27 | } 28 | 29 | // Initialize a stack to keep track of nodes 30 | // For DFS we use Stack - Last-In-First-Out (LIFO) data structure 31 | // stack is used to explore as far as possible along a branch before backtracking 32 | // ensuring a depth-first traversal of the graph 33 | var stack = new Stack>(); 34 | var visited = new HashSet>(); 35 | 36 | // Add the start node to the stack and mark it as visited 37 | stack.Push(startNode); 38 | visited.Add(startNode); 39 | 40 | // Continue searching as long as there are nodes left to visit 41 | while (stack.Count > 0) 42 | { 43 | var currentNode = stack.Pop(); 44 | if (!graph.Edges.TryGetValue(currentNode, out var edges)) 45 | continue; 46 | 47 | foreach (var edge in edges) 48 | { 49 | var adjacentNode = edge.Node; 50 | 51 | // If an adjacent node hasn't been visited 52 | // add it to the stack and mark it as visited 53 | if (!visited.Contains(adjacentNode)) 54 | { 55 | visited.Add(adjacentNode); 56 | stack.Push(adjacentNode); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /csharp/QuickSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6 }; 2 | arr = Sort(arr, 0, arr.Length - 1); 3 | 4 | T[] Sort(T[] source, int low, int high) where T: IComparable 5 | { 6 | if (low < high) 7 | { 8 | // Partition the array segment and get the pivot's final position 9 | var pivot = Partition(source, low, high); 10 | 11 | // Recursively sort elements before the pivot 12 | Sort(source, low, pivot); 13 | 14 | // Recursively sort elements after the pivot 15 | Sort(source, pivot + 1, high); 16 | } 17 | return source; 18 | } 19 | 20 | int Partition(T[] array, int left, int right) where T : IComparable 21 | { 22 | // Selecting the leftmost element as the pivot for simplicity. 23 | // The pivot is a reference point to divide the array into two parts. 24 | var pivot = array[left]; 25 | while (true) 26 | { 27 | // With two while loops, one from left to pivot and one from right to pivot 28 | // we search for elements that we can swap 29 | // starting from left if we find element that is greater than pivot, 30 | // and fro right if we find element that is less than pivot, 31 | // we swap the two elements from left and right 32 | 33 | // Find the first element from the left that is greater than pivot 34 | while (array[left].CompareTo(pivot) < 0) 35 | { 36 | left++; 37 | } 38 | 39 | // Find the first element from the right that is less than pivot 40 | while (array[right].CompareTo(pivot) > 0) 41 | { 42 | right--; 43 | } 44 | 45 | // If all elements are compared and swapped if necessary, the partition is complete 46 | if (left >= right) 47 | { 48 | return right; 49 | } 50 | 51 | var temp = array[left]; 52 | array[left] = array[right]; 53 | array[right] = temp; 54 | 55 | // Move to next elements in the array for comparison 56 | left++; 57 | right--; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /rust/src/graphs/kruskal.rs: -------------------------------------------------------------------------------- 1 | use crate::data_structures::DisjointSet; 2 | use crate::graphs::graph::{ Graph, Edge, NodeIndex }; 3 | 4 | impl Graph { 5 | pub fn kruskal_mst(&self) -> Vec<(&NodeIndex, &Edge)> { 6 | if self.nodes.len() == 0 { 7 | return vec![]; 8 | } 9 | 10 | let mut edges = self.edges 11 | .iter() 12 | .flat_map(|node_edge| { 13 | node_edge.1.iter().map(move |edge| (node_edge.0, edge)) 14 | }) 15 | .collect::>(); 16 | 17 | edges.sort_by_key(|(_, edge)| edge.cost); 18 | 19 | let mut union_find = DisjointSet::new(self.nodes.len()); 20 | let mut mst = Vec::new(); 21 | 22 | for (node_ix, edge) in edges { 23 | let x_root = union_find.find(node_ix.ix); 24 | let y_root = union_find.find(edge.node_index.ix); 25 | 26 | if x_root != y_root { 27 | mst.push((node_ix, edge)); 28 | union_find.union(x_root, y_root); 29 | } 30 | } 31 | mst 32 | } 33 | } 34 | 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use crate::graphs::graph::{ Graph, GraphType }; 39 | 40 | #[test] 41 | fn kruskal_empty_graph() { 42 | let graph: Graph = Graph::new(GraphType::Undirected); 43 | let mst = graph.kruskal_mst(); 44 | assert!(mst.is_empty()); 45 | } 46 | 47 | #[test] 48 | fn kruskal_single_node() { 49 | let mut graph = Graph::new(GraphType::Undirected); 50 | graph.add_node(1); 51 | let mst = graph.kruskal_mst(); 52 | assert!(mst.is_empty()); 53 | } 54 | 55 | #[test] 56 | fn kruskal_disconnected_graph() { 57 | let mut graph = Graph::new(GraphType::Undirected); 58 | let n1 = graph.add_node(1); 59 | let n2 = graph.add_node(2); 60 | graph.add_edge(n1, n2, 1); 61 | graph.add_node(3); // Disconnected node 62 | 63 | let mst = graph.kruskal_mst(); 64 | assert_eq!(mst.len(), 1); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /csharp/BreadthFirstSearch/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | using System.Xml.Linq; 3 | 4 | namespace BreadthFirstSearch; 5 | 6 | /* 7 | for graph with nodes: A, B, C, D 8 | where: A -> B and C; B and C -> D 9 | A 10 | / \ 11 | B C 12 | \ / 13 | D 14 | 15 | BFS traversal sequence: A -> B -> C -> D 16 | */ 17 | 18 | public static class GraphExtensions 19 | { 20 | public static void BFS(this Graph graph, T startValue) 21 | { 22 | // Retrieve the start node from the graph using the provided value. 23 | // If the start node is not found, handle the error appropriately. 24 | var startNode = graph.GetNode(startValue); 25 | if (startNode == null) 26 | { 27 | // handle 28 | } 29 | 30 | // Initialize a queue to keep track of nodes 31 | // For BFS we use Queue - First-In-First-Out (FIFO) data structure 32 | // queue is used to ensure that nodes are explored in the order they are discovered 33 | // enabling level-by - level traversal of the graph 34 | var queue = new Queue>(); 35 | var visited = new HashSet>(); 36 | 37 | // Add the start node to the queue and mark it as visited 38 | queue.Enqueue(startNode); 39 | visited.Add(startNode); 40 | 41 | // Continue searching as long as there are nodes left to visit 42 | while (queue.Count > 0) 43 | { 44 | var currentNode = queue.Dequeue(); 45 | 46 | if (!graph.Edges.TryGetValue(currentNode, out var edges)) 47 | continue; 48 | 49 | foreach (var edge in edges) 50 | { 51 | var adjacentNode = edge.Node; 52 | 53 | // If an adjacent node hasn't been visited 54 | // add it to the queue and mark it as visited 55 | if (!visited.Contains(adjacentNode)) 56 | { 57 | visited.Add(adjacentNode); 58 | queue.Enqueue(adjacentNode); 59 | } 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /csharp/DijkstraPrimes/Program.cs: -------------------------------------------------------------------------------- 1 | const int PRIMES_UP_TO = 30; 2 | 3 | 4 | var primes = new List(); 5 | var pool = new Pool(); 6 | 7 | primes.Add(2); 8 | pool.Insert(2); 9 | 10 | for (int number = 3; number < PRIMES_UP_TO; number++) 11 | { 12 | var smallestMultiplier = pool.GetSmallestMultiplier(); 13 | if (smallestMultiplier > 0) 14 | { 15 | if (number < smallestMultiplier) 16 | { 17 | primes.Add(number); 18 | pool.Insert(number); 19 | } 20 | else 21 | { 22 | pool.Update(number); 23 | } 24 | } 25 | } 26 | 27 | readonly struct Pool 28 | { 29 | private readonly List<(int Prime, int Multiple)> pairs; 30 | 31 | public Pool() 32 | { 33 | pairs = new(); 34 | } 35 | 36 | public readonly void Insert(int value) 37 | => 38 | this.pairs.Add((value, value * value)); 39 | 40 | public readonly int GetSmallestMultiplier() 41 | => 42 | this.pairs.Count > 0 43 | ? this.pairs[0].Multiple 44 | : 0; 45 | 46 | public void Update(int value) 47 | { 48 | int index = 0; 49 | for (; index < pairs.Count; index++) 50 | { 51 | if (pairs[index].Multiple == value) 52 | { 53 | pairs[index] = (pairs[index].Prime, pairs[index].Multiple + pairs[index].Prime); 54 | } 55 | else 56 | { 57 | break; 58 | } 59 | } 60 | 61 | if (this.pairs.Count > 1) 62 | { 63 | while (index >= 0) 64 | { 65 | index -= 1; 66 | int i = index; 67 | while (this.pairs[i].Multiple > this.pairs[i + 1].Multiple) 68 | { 69 | (this.pairs[i + 1], this.pairs[i]) = (this.pairs[i], this.pairs[i + 1]); 70 | i += 1; 71 | } 72 | if (index == 0) 73 | break; 74 | } 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /csharp/Graphs/Graph.cs: -------------------------------------------------------------------------------- 1 | namespace Graphs; 2 | 3 | public enum GraphType 4 | { 5 | Directed, 6 | Undirected 7 | } 8 | 9 | public class Node 10 | { 11 | public T Value { get; } 12 | 13 | public Node(T value) => Value = value; 14 | } 15 | 16 | public class Edge 17 | { 18 | public int Cost { get; } 19 | public Node Node { get; } 20 | 21 | public Edge(int cost, Node node) 22 | { 23 | Cost = cost; 24 | Node = node; 25 | } 26 | } 27 | 28 | public class Graph 29 | { 30 | public ICollection> Nodes { get; } 31 | public IDictionary, ICollection>> Edges { get; } 32 | public GraphType GraphType { get; } 33 | 34 | public Graph() : this(GraphType.Undirected) 35 | { 36 | } 37 | 38 | public Graph(GraphType graphType) 39 | { 40 | Nodes = new List>(); 41 | Edges = new Dictionary, ICollection>>(); 42 | GraphType = graphType; 43 | } 44 | 45 | public void AddNode(T value) 46 | { 47 | var node = new Node(value); 48 | this.Nodes.Add(node); 49 | } 50 | 51 | public void AddEdge(Node fromNode, Node toNode, int cost) 52 | { 53 | if (fromNode == null || toNode == null) 54 | { 55 | // handle 56 | return; 57 | } 58 | 59 | Add(fromNode, toNode, cost); 60 | 61 | if (this.GraphType == GraphType.Undirected) 62 | { 63 | Add(toNode, fromNode, cost); 64 | } 65 | 66 | void Add(Node from, Node to, int cost) 67 | { 68 | if (!Edges.TryGetValue(from, out ICollection> value)) 69 | { 70 | value = new List>(); 71 | this.Edges.Add(from, value); 72 | } 73 | 74 | var edge = new Edge(cost, to); 75 | value.Add(edge); 76 | } 77 | } 78 | 79 | public Node GetNode(T value) 80 | { 81 | var node = this.Nodes.FirstOrDefault(x => x.Value.Equals(value)); 82 | if (node.Value == null) 83 | { 84 | // handle 85 | } 86 | 87 | return node; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /rust/src/primes/dijkstra_primes.rs: -------------------------------------------------------------------------------- 1 | pub fn dijkstra_primes(up_to: usize) -> Vec { 2 | if up_to < 2 { 3 | return vec![]; 4 | } 5 | 6 | let mut primes: Vec = Vec::new(); 7 | let mut pool = Pool::new(); 8 | 9 | primes.push(2); 10 | pool.insert(2); 11 | 12 | for number in 3..up_to { 13 | if let Some(multiplier) = pool.get_smallest_multiplier() { 14 | if number < multiplier { 15 | primes.push(number); 16 | pool.insert(number); 17 | } else { 18 | pool.update(number); 19 | } 20 | } 21 | } 22 | 23 | primes 24 | } 25 | 26 | struct Pool { 27 | pairs: Vec<(usize, usize)> 28 | } 29 | 30 | impl Pool { 31 | fn new() -> Self { 32 | Pool { pairs: vec![] } 33 | } 34 | 35 | fn insert(&mut self, v: usize) { 36 | self.pairs.push((v, v * v)); 37 | } 38 | 39 | fn update(&mut self, v: usize) { 40 | let mut index = 0; 41 | for pair in self.pairs.iter_mut().take_while(|pair| pair.1 == v) { 42 | pair.1 += pair.0; 43 | index += 1; 44 | } 45 | 46 | if self.pairs.len() > 1 { 47 | index -= 1; 48 | loop { 49 | let mut i = index; 50 | while self.pairs[i].1 > self.pairs[i + 1].1 { 51 | self.pairs.swap(i, i + 1); 52 | i += 1; 53 | } 54 | if index == 0 { 55 | break; 56 | } 57 | index -= 1; 58 | } 59 | } 60 | } 61 | 62 | fn get_smallest_multiplier(&self) -> Option { 63 | if let Some(pair) = self.pairs.first() { 64 | return Some(pair.1); 65 | } 66 | None 67 | } 68 | } 69 | 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | use super::*; 74 | 75 | #[test] 76 | fn test_dijkstra_primes() { 77 | let primes: Vec = dijkstra_primes(1000000); 78 | assert!(!primes.is_empty()); 79 | assert_eq!(primes.len(), 78498); 80 | assert_eq!(primes.first().unwrap(), &2); 81 | assert_eq!(primes.last().unwrap(), &999983); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /csharp/UnionFind/UnionFindSet.cs: -------------------------------------------------------------------------------- 1 | namespace UnionFind; 2 | 3 | public class UnionFindSet 4 | { 5 | private int[] parent; // Stores the parent of each element. For a root element, parent[i] = i. 6 | private int[] rank; // Stores the approximate depth (or 'rank') of the tree for each root. 7 | 8 | public UnionFindSet(int size) 9 | { 10 | this.parent = Enumerable.Range(0, size).ToArray(); 11 | this.rank = new int[size]; 12 | } 13 | 14 | public int Find(int index) 15 | { 16 | // Path Compression: If 'index' is not the root (parent[index] != index), 17 | // recursively find the root and update the parent of 'index' for faster future lookups. 18 | if (parent[index] != index) 19 | { 20 | parent[index] = this.Find(parent[index]); 21 | } 22 | 23 | return parent[index]; 24 | } 25 | 26 | public void Union(int x, int y) 27 | { 28 | // Find the roots of the sets that 'x' and 'y' belong to. 29 | var x_root = this.Find(x); 30 | var y_root = this.Find(y); 31 | 32 | // If both elements have the same root, they are already in the same set. 33 | if (x_root == y_root) 34 | { 35 | return; 36 | } 37 | 38 | // Union by Rank: 39 | /* 40 | * When performing a union of two sets, instead of arbitrarily choosing the root for merging, 41 | * the root with the smaller rank is attached to the root with the larger rank. 42 | * If both roots have the same rank, one is chosen as the new root and its rank is incremented by one. 43 | * 44 | * Attach the smaller tree to the larger tree's root to maintain balanced trees, preventing inefficient linear structures. 45 | * This approach significantly improves the efficiency of 'Find' operations by keeping tree heights minimal 46 | */ 47 | 48 | if (this.rank[x_root] < this.rank[y_root]) 49 | { 50 | this.parent[x_root] = y_root; 51 | } 52 | else if (this.rank[x_root] > this.rank[y_root]) 53 | { 54 | this.parent[y_root] = x_root; 55 | } 56 | else 57 | { 58 | this.parent[y_root] = x_root; 59 | this.rank[x_root]++; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /csharp/Prim/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | 3 | namespace Prim; 4 | 5 | public static class GraphExtensions 6 | { 7 | public static IEnumerable> PrimMst(this Graph graph) 8 | { 9 | if (graph.Nodes.Count == 0) 10 | { 11 | return Enumerable.Empty>(); 12 | } 13 | 14 | var visited = new HashSet>(); 15 | 16 | // PriorityQueue to store nodes along with their edge cost. 17 | // Nodes are processed based on minimum edge cost. 18 | var queue = new PriorityQueue<(Node, int), int>(); 19 | var minimumSpanningTree = new List>(); 20 | 21 | // Choose an arbitrary node as the starting point for Prim's algorithm. 22 | var root = graph.Nodes.First(); 23 | queue.Enqueue((root, 0), 0); 24 | 25 | while (queue.Count > 0) 26 | { 27 | // Dequeue the node with the lowest edge cost. 28 | var queueItem = queue.Dequeue(); 29 | var node = queueItem.Item1; 30 | var cost = queueItem.Item2; 31 | 32 | // Skip nodes that have already been visited to avoid cycles. 33 | if (visited.Contains(node)) 34 | { 35 | continue; 36 | } 37 | 38 | // Add the node to the MST, along with its cost. 39 | minimumSpanningTree.Add(new NodeEdge() 40 | { 41 | Node = node, 42 | Cost = cost 43 | }); 44 | 45 | visited.Add(node); 46 | 47 | if(graph.Edges.TryGetValue(node, out var edges)) 48 | { 49 | foreach (var edge in edges) 50 | { 51 | // For each adjacent node that has not been visited, enqueue it with its cost. 52 | // The cost is the key for the priority queue to determine the processing order. 53 | if (!visited.Contains(edge.Node)) 54 | { 55 | queue.Enqueue((edge.Node, edge.Cost), edge.Cost); 56 | } 57 | } 58 | } 59 | } 60 | 61 | return minimumSpanningTree; 62 | } 63 | 64 | public class NodeEdge 65 | { 66 | public Node Node { get; set; } 67 | public int Cost { get; set; } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /rust/src/sorting/insertion_sort.rs: -------------------------------------------------------------------------------- 1 | pub fn insertion_sort(arr: &mut [T]) { 2 | if arr.is_empty() { 3 | return; 4 | } 5 | for index in 1..arr.len() { 6 | let current_item: T = arr[index]; 7 | let mut insertion_index: usize = index; 8 | 9 | while insertion_index > 0 && arr[insertion_index - 1] > current_item { 10 | arr[insertion_index] = arr[insertion_index - 1]; 11 | insertion_index -= 1; 12 | } 13 | arr[insertion_index] = current_item; 14 | } 15 | } 16 | 17 | // alternatively we can use 'rotate_right' function from rust std 18 | /* 19 | the main idea is only to find the index at which we need to put 'current_item' 20 | and let 'rotate_right' to do all the swaps 21 | 22 | we find the correct position for 'current_item' without making any swaps 23 | and what 'rotate_right(1)' do is: 24 | shift every item one position right and the rightmost items goes to first position 25 | 26 | for example: 27 | 28 | arr = [1, 2, 3] 29 | index = 2 30 | insertion_index = 0 31 | 32 | arr[insertion_index..=index].rotate_right(1); 33 | arr = [3, 1, 2] 34 | 35 | */ 36 | pub fn insertion_sort_with_rotate_right(arr: &mut [T]) { 37 | if arr.is_empty() { 38 | return; 39 | } 40 | for index in 1..arr.len() { 41 | let current_item: T = arr[index]; 42 | let mut insertion_index: usize = index; 43 | 44 | while insertion_index > 0 && arr[insertion_index - 1] > current_item { 45 | insertion_index -= 1; 46 | } 47 | arr[insertion_index..=index].rotate_right(1); 48 | } 49 | } 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use super::*; 54 | 55 | #[test] 56 | fn empty() { 57 | let mut empty_vec: Vec = Vec::new(); 58 | insertion_sort(&mut empty_vec); 59 | 60 | assert!(empty_vec.is_empty()); 61 | } 62 | 63 | #[test] 64 | fn sort() { 65 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 66 | insertion_sort(&mut arr); 67 | 68 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 69 | } 70 | 71 | #[test] 72 | fn sort_with_rotate_right() { 73 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 74 | insertion_sort_with_rotate_right(&mut arr); 75 | 76 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /rust/src/graphs/tarjan.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::graphs::graph::{ Graph, NodeIndex }; 4 | 5 | use super::{tarjan_state::State, Node}; 6 | 7 | /* 8 | NOT READY! 9 | */ 10 | 11 | impl Graph { 12 | pub fn find_low_link_values(&self) -> HashMap { 13 | if self.length == 0 { 14 | return HashMap::new(); 15 | } 16 | 17 | let mut state = State::new(); 18 | let root: &Node = self.nodes.first().unwrap(); 19 | 20 | self.tarjan_dfs(root.index, &mut state); 21 | state.nodes_low_link_value 22 | } 23 | 24 | fn tarjan_dfs(&self, node_index: NodeIndex, state: &mut State) { 25 | state.discovery_time += 1; 26 | state.visited.insert(node_index); 27 | state.nodes_discovery_time.insert(node_index, state.discovery_time); 28 | state.nodes_low_link_value.insert(node_index, state.discovery_time); 29 | 30 | let edges = match self.edges.get(&node_index) { 31 | Some(edges) => edges, 32 | None => return 33 | }; 34 | 35 | for edge in edges { 36 | if !state.visited.contains(&edge.node_index) { 37 | state.parent_node.insert(edge.node_index, node_index); 38 | self.tarjan_dfs(edge.node_index, state); 39 | 40 | state.nodes_low_link_value.insert( 41 | node_index, 42 | std::cmp::min( 43 | state.nodes_low_link_value[&node_index], 44 | state.nodes_low_link_value[&edge.node_index], 45 | ), 46 | ); 47 | } else if Some(&node_index) != state.parent_node.get(&edge.node_index) { 48 | state.nodes_low_link_value.insert( 49 | node_index, 50 | std::cmp::min( 51 | state.nodes_low_link_value[&node_index], 52 | state.nodes_discovery_time[&edge.node_index], 53 | ), 54 | ); 55 | } 56 | } 57 | } 58 | } 59 | 60 | 61 | #[cfg(test)] 62 | mod tests { 63 | use crate::graphs::graph::{ Graph, GraphType }; 64 | 65 | #[test] 66 | fn empty_graph() { 67 | let graph: Graph = Graph::new(GraphType::Undirected); 68 | let llv = graph.find_low_link_values(); 69 | assert!(llv.is_empty()); 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /rust/src/graphs/dfs.rs: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | for graph with nodes: A, B, C, D 4 | where: A -> B and C; B and C -> D 5 | A 6 | / \ 7 | B C 8 | \ / 9 | D 10 | 11 | DFS traversal sequence: A -> C -> D -> B 12 | */ 13 | 14 | use std::collections::HashSet; 15 | 16 | use crate::graphs::graph::{ Graph, Node, NodeIndex }; 17 | 18 | impl Graph { 19 | pub fn dfs(&self, root_node: &Node) -> Vec { 20 | 21 | let mut result: Vec = Vec::new(); 22 | let mut stack: Vec<&NodeIndex> = vec![]; 23 | stack.push(&root_node.index); 24 | 25 | let mut visited: HashSet<&NodeIndex> = HashSet::new(); 26 | 27 | while let Some(node_index) = stack.pop() { 28 | if visited.contains(node_index) { 29 | continue; 30 | } 31 | visited.insert(node_index); 32 | result.push(self.nodes[node_index.ix].value); 33 | 34 | let edges = match self.edges.get(node_index) { 35 | Some(edges) => edges, 36 | None => continue 37 | }; 38 | 39 | for edge in edges { 40 | if !visited.contains(&edge.node_index) { 41 | stack.push(&edge.node_index); 42 | } 43 | } 44 | } 45 | result 46 | } 47 | } 48 | 49 | 50 | #[cfg(test)] 51 | mod tests { 52 | use crate::graphs::GraphType; 53 | 54 | use super::*; 55 | 56 | fn create_test_graph() -> Graph { 57 | let mut graph = Graph::new(GraphType::Directed); 58 | let a = graph.add_node('A'); 59 | let b = graph.add_node('B'); 60 | let c = graph.add_node('C'); 61 | let d = graph.add_node('D'); 62 | 63 | graph.add_edge(a, b, 1); 64 | graph.add_edge(a, c, 1); 65 | graph.add_edge(b, d, 1); 66 | graph.add_edge(c, d, 1); 67 | 68 | graph 69 | } 70 | 71 | #[test] 72 | fn dfs_simple_graph() { 73 | let graph = create_test_graph(); 74 | let root = graph.get_node(NodeIndex { ix: 0 }).unwrap(); 75 | 76 | let traversal = graph.dfs(root); 77 | assert_eq!(traversal, vec!['A', 'C', 'D', 'B']); 78 | } 79 | 80 | #[test] 81 | fn dfs_empty_graph() { 82 | let graph: Graph = Graph::new(GraphType::Directed); 83 | 84 | if let Some(root) = graph.nodes.get(0) { 85 | let traversal = graph.dfs(root); 86 | assert!(traversal.is_empty()); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /rust/src/sorting/merge_sort.rs: -------------------------------------------------------------------------------- 1 | pub fn merge_sort(arr: &mut [T]) { 2 | if arr.is_empty() { 3 | return; 4 | } 5 | sort(arr); 6 | } 7 | 8 | fn sort(arr: &mut [T]) { 9 | if arr.len() == 1 { 10 | return; // If the array has only one element, it's already sorted 11 | } 12 | 13 | // Finding the middle index of the array to split it into two halves 14 | let middle_index: usize = arr.len() / 2; 15 | let (left_array, right_array) = arr.split_at_mut(middle_index); 16 | 17 | sort(left_array); 18 | sort(right_array); 19 | 20 | let merged = merge(left_array, right_array); 21 | for (index, item) in merged.iter().enumerate() { 22 | arr[index] = item.clone(); 23 | } 24 | } 25 | 26 | fn merge(left_array: &[T], right_array: &[T]) -> Vec { 27 | let mut left_array_index: usize = 0; 28 | let mut right_array_index: usize = 0; 29 | let mut merged_vector: Vec = Vec::with_capacity(left_array.len() + right_array.len()); 30 | 31 | // Merging the two arrays until one of them is fully traversed 32 | while left_array_index < left_array.len() && right_array_index < right_array.len() { 33 | if left_array[left_array_index] <= right_array[right_array_index] { 34 | merged_vector.push(left_array[left_array_index]); 35 | left_array_index += 1; 36 | } else { 37 | merged_vector.push(right_array[right_array_index]); 38 | right_array_index += 1; 39 | } 40 | } 41 | 42 | // Adding remaining elements from the left array (if any) 43 | while left_array_index < left_array.len() { 44 | merged_vector.push(left_array[left_array_index]); 45 | left_array_index += 1; 46 | } 47 | 48 | // Adding remaining elements from the right array (if any) 49 | while right_array_index < right_array.len() { 50 | merged_vector.push(right_array[right_array_index]); 51 | right_array_index += 1; 52 | } 53 | 54 | merged_vector 55 | } 56 | 57 | #[cfg(test)] 58 | mod tests { 59 | use super::*; 60 | 61 | #[test] 62 | fn empty() { 63 | let mut empty_vec: Vec = Vec::new(); 64 | merge_sort(&mut empty_vec); 65 | 66 | assert!(empty_vec.is_empty()); 67 | } 68 | 69 | #[test] 70 | fn sort() { 71 | let mut arr: Vec = vec![4, -3, 7, 0, 10, -6, 7, 1]; 72 | merge_sort(&mut arr); 73 | 74 | assert_eq!(arr, vec![-6, -3, 0, 1, 4, 7, 7, 10]); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /rust/src/graphs/bfs.rs: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | for graph with nodes: A, B, C, D 4 | where: A -> B and C; B and C -> D 5 | A 6 | / \ 7 | B C 8 | \ / 9 | D 10 | 11 | BFS traversal sequence: A -> B -> C -> D 12 | */ 13 | 14 | use std::collections::VecDeque; 15 | 16 | use crate::graphs::graph::{ Graph, Node, NodeIndex }; 17 | 18 | impl Graph { 19 | pub fn bfs(&self, root_node: &Node) -> Vec { 20 | 21 | let mut result: Vec = Vec::new(); 22 | let mut queue: VecDeque = VecDeque::new(); 23 | queue.push_back(root_node.index); 24 | 25 | let mut visited: Vec = Vec::new(); 26 | 27 | while let Some(node_index) = queue.pop_front() { 28 | if visited.contains(&node_index) { 29 | continue; 30 | } 31 | 32 | visited.push(node_index); 33 | result.push(self.nodes[node_index.ix].value); 34 | 35 | let edges = match self.edges.get(&node_index) { 36 | Some(edges) => edges, 37 | None => continue 38 | }; 39 | 40 | for edge in edges { 41 | if !visited.contains(&edge.node_index) && !queue.contains(&edge.node_index) { 42 | queue.push_back(edge.node_index); 43 | } 44 | } 45 | } 46 | result 47 | } 48 | } 49 | 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use crate::graphs::GraphType; 54 | 55 | use super::*; 56 | 57 | fn create_test_graph() -> Graph { 58 | let mut graph = Graph::new(GraphType::Directed); 59 | let a = graph.add_node('A'); 60 | let b = graph.add_node('B'); 61 | let c = graph.add_node('C'); 62 | let d = graph.add_node('D'); 63 | 64 | graph.add_edge(a, b, 1); 65 | graph.add_edge(a, c, 1); 66 | graph.add_edge(b, d, 1); 67 | graph.add_edge(c, d, 1); 68 | 69 | graph 70 | } 71 | 72 | #[test] 73 | fn bfs_simple_graph() { 74 | let graph = create_test_graph(); 75 | let root = graph.get_node(NodeIndex { ix: 0 }).unwrap(); 76 | 77 | let traversal = graph.bfs(root); 78 | assert_eq!(traversal, vec!['A', 'B', 'C', 'D']); 79 | } 80 | 81 | #[test] 82 | fn bfs_empty_graph() { 83 | let graph: Graph = Graph::new(GraphType::Directed); 84 | 85 | if let Some(root) = graph.nodes.get(0) { 86 | let traversal = graph.bfs(root); 87 | assert!(traversal.is_empty()); 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /rust/src/graphs/prim.rs: -------------------------------------------------------------------------------- 1 | use std::cmp::Reverse; 2 | use std::collections::{ BinaryHeap, HashSet }; 3 | 4 | use crate::graphs::graph::{ Graph, NodeIndex }; 5 | 6 | impl Graph { 7 | pub fn prim_mst(&self) -> Vec<(&NodeIndex, isize)> { 8 | if self.nodes.len() == 0 { 9 | return vec![]; 10 | } 11 | 12 | let mut heap = BinaryHeap::new(); 13 | let mut visited = HashSet::new(); 14 | let mut mst = Vec::new(); 15 | 16 | let root = self.nodes.first().unwrap(); 17 | heap.push(Reverse((0, &root.index))); 18 | 19 | while let Some(Reverse((cost, node_ix))) = heap.pop() { 20 | if visited.contains(node_ix) { 21 | continue; 22 | } 23 | 24 | visited.insert(node_ix); 25 | mst.push((node_ix, cost)); 26 | 27 | if let Some(edges) = self.edges.get(node_ix) { 28 | for edge in edges { 29 | let next = &edge.node_index; 30 | if !visited.contains(next) { 31 | heap.push(Reverse((edge.cost, next))); 32 | } 33 | } 34 | } 35 | } 36 | mst 37 | } 38 | } 39 | 40 | 41 | #[cfg(test)] 42 | mod tests { 43 | use crate::graphs::GraphType; 44 | 45 | use super::*; 46 | 47 | #[test] 48 | fn prim_single_node() { 49 | let mut graph = Graph::new(GraphType::Undirected); 50 | graph.add_node(1); 51 | let mst = graph.prim_mst(); 52 | assert_eq!(mst.len(), 1); 53 | } 54 | 55 | #[test] 56 | fn prim_disconnected_graph() { 57 | let mut graph = Graph::new(GraphType::Undirected); 58 | let n1 = graph.add_node(1); 59 | let n2 = graph.add_node(2); 60 | graph.add_edge(n1, n2, 1); 61 | 62 | graph.add_node(3); // Disconnected node 63 | 64 | let mst = graph.prim_mst(); 65 | assert_eq!(mst.len(), 2); 66 | } 67 | 68 | #[test] 69 | fn prim_single_mst() { 70 | let mut graph = Graph::new(GraphType::Undirected); 71 | let n1 = graph.add_node(1); 72 | let n2 = graph.add_node(2); 73 | let n3 = graph.add_node(3); 74 | let n4 = graph.add_node(4); 75 | graph.add_edge(n1, n2, 1); 76 | graph.add_edge(n1, n3, 3); 77 | graph.add_edge(n2, n4, 10); 78 | graph.add_edge(n3, n4, 5); 79 | 80 | let mst = graph.prim_mst(); 81 | let total_cost: isize = mst.iter() 82 | .map(|x| x.1) 83 | .sum(); 84 | 85 | assert_eq!(total_cost, 9); 86 | } 87 | } -------------------------------------------------------------------------------- /csharp/LinkedList/SinglyLinkedList.cs: -------------------------------------------------------------------------------- 1 | namespace LinkedList; 2 | 3 | public class SinglyLinkedList 4 | { 5 | private class Node 6 | { 7 | public T Data; 8 | public Node Next; 9 | 10 | public Node(T data) 11 | { 12 | this.Data = data; 13 | this.Next = null; 14 | } 15 | } 16 | 17 | private Node head; 18 | private Node tail; 19 | private int length; 20 | 21 | public int Length 22 | { 23 | get { return this.length; } 24 | private set { length = value; } 25 | } 26 | 27 | public SinglyLinkedList() 28 | { 29 | head = null; 30 | tail = null; 31 | length = 0; 32 | } 33 | 34 | public bool IsEmpty() 35 | { 36 | return length == 0; 37 | } 38 | 39 | public void Add(T data) 40 | { 41 | var node = new Node(data); 42 | 43 | if (IsEmpty()) 44 | { 45 | head = tail = node; 46 | } 47 | else 48 | { 49 | tail.Next = node; 50 | tail = node; 51 | } 52 | 53 | length++; 54 | } 55 | 56 | public T Get(int index) 57 | { 58 | if (IsEmpty() || index < 0 || index >= length) 59 | { 60 | throw new IndexOutOfRangeException("Index out of range."); 61 | } 62 | 63 | var current = head; 64 | for (int i = 0; i < index; i++) 65 | { 66 | current = current.Next; 67 | } 68 | 69 | return current.Data; 70 | } 71 | 72 | public void Delete(int index) 73 | { 74 | if (IsEmpty() || index < 0 || index >= length) 75 | { 76 | throw new IndexOutOfRangeException("Index out of range."); 77 | } 78 | 79 | if (index == 0) 80 | { 81 | head = head.Next; 82 | if (length == 1) 83 | { 84 | tail = null; 85 | } 86 | } 87 | else 88 | { 89 | var current = head; 90 | for (int i = 0; i < index - 1; i++) 91 | { 92 | current = current.Next; 93 | } 94 | 95 | current.Next = current.Next.Next; 96 | if (index == length - 1) // If the last element is being deleted 97 | { 98 | tail = current; 99 | } 100 | } 101 | 102 | length--; 103 | } 104 | 105 | public void Clear() 106 | { 107 | head = null; 108 | tail = null; 109 | length = 0; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /rust/src/graphs/floyd_warshall.rs: -------------------------------------------------------------------------------- 1 | use crate::graphs::graph::Graph; 2 | 3 | impl Graph { 4 | pub fn floyd_warshall_shortest_path(&self) -> Vec> { 5 | 6 | let node_count = self.nodes.len(); 7 | let mut distances = vec![vec![isize::MAX; node_count]; node_count]; 8 | 9 | for (source_index, node) in self.nodes.iter().enumerate() { 10 | distances[source_index][source_index] = 0; // Distance to self is 0 11 | 12 | if let Some(edges) = self.edges.get(&node.index) { 13 | for edge in edges { 14 | distances[source_index][edge.node_index.ix] = edge.cost; 15 | } 16 | } 17 | } 18 | 19 | for intermediate_vertex in 0..node_count { 20 | for source_vertex in 0..node_count { 21 | for destination_vertex in 0..node_count { 22 | let new_distance = std::cmp::min( 23 | distances[source_vertex][destination_vertex], 24 | distances[source_vertex][intermediate_vertex].saturating_add(distances[intermediate_vertex][destination_vertex]), 25 | ); 26 | 27 | distances[source_vertex][destination_vertex] = new_distance; 28 | } 29 | } 30 | } 31 | distances 32 | } 33 | } 34 | 35 | 36 | #[cfg(test)] 37 | mod tests { 38 | use super::*; 39 | use crate::graphs::GraphType; 40 | 41 | #[test] 42 | fn empty_graph() { 43 | let graph: Graph<&str> = Graph::new(GraphType::Undirected); 44 | 45 | let result = graph.floyd_warshall_shortest_path(); 46 | assert_eq!(result, Vec::>::new()); 47 | } 48 | 49 | #[test] 50 | fn single_path() { 51 | let mut graph: Graph<&str> = Graph::new(GraphType::Directed); 52 | let a = graph.add_node("A"); 53 | let b = graph.add_node("B"); 54 | graph.add_edge(a, b, 1); 55 | 56 | let result = graph.floyd_warshall_shortest_path(); 57 | assert_eq!(result, vec![vec![0, 1], vec![isize::MAX, 0]]); 58 | } 59 | 60 | #[test] 61 | fn multiple_paths() { 62 | let mut graph: Graph<&str> = Graph::new(GraphType::Directed); 63 | let a = graph.add_node("A"); 64 | let b = graph.add_node("B"); 65 | let c = graph.add_node("C"); 66 | graph.add_edge(a, b, 3); 67 | graph.add_edge(b, c, 2); 68 | 69 | let result = graph.floyd_warshall_shortest_path(); 70 | assert_eq!(result, vec![vec![0, 3, 5], vec![isize::MAX, 0, 2], vec![isize::MAX, isize::MAX, 0]]); 71 | } 72 | } 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /csharp/MergeSort/Program.cs: -------------------------------------------------------------------------------- 1 | int[] arr = new[] { 1, 7, 3, 2, 9, 5, 4, 2, 7, 3, 8, 6 }; 2 | arr = Sort(arr); 3 | 4 | int[] Sort(int[] sourceArray) 5 | { 6 | // Base case: if the array has only one element, it's already sorted 7 | if (sourceArray.Length == 1) 8 | { 9 | return sourceArray; 10 | } 11 | 12 | // Finding the middle index of the array to split it into two halves 13 | int middleIndex = sourceArray.Length / 2; 14 | 15 | // Create two sub-arrays from the original array and copy values 16 | // for example: if sourceArray is { 1, 2, 3, 4 } after Array.Copy operations leftArray is { 1, 2 } and rightArray is { 4, 3 } 17 | var leftArray = new int[middleIndex]; 18 | var rightArray = new int[sourceArray.Length - middleIndex]; 19 | 20 | Array.Copy(sourceArray, 0, leftArray, 0, middleIndex); 21 | Array.Copy(sourceArray, middleIndex, rightArray, 0, sourceArray.Length - middleIndex); 22 | 23 | // Use recursion to sort the left and right sub-arrays 24 | leftArray = Sort(leftArray); 25 | rightArray = Sort(rightArray); 26 | 27 | // After the two sub-arrays are sorted, Merge() method will merge/combine sub-arrays into one array 28 | return Merge(leftArray, rightArray); 29 | } 30 | 31 | int[] Merge(int[] leftArray, int[] rightArray) 32 | { 33 | int leftArrayIndex = 0; 34 | int rightArrayIndex = 0; 35 | int mergedArrayIndex = 0; 36 | 37 | var mergedArray = new int[leftArray.Length + rightArray.Length]; 38 | 39 | // Merging the two arrays until one of them is fully traversed 40 | while (leftArrayIndex < leftArray.Length && rightArrayIndex < rightArray.Length) 41 | { 42 | // Comparing elements of the two arrays and adding the smaller one to the merged array 43 | if (leftArray[leftArrayIndex] <= rightArray[rightArrayIndex]) 44 | { 45 | mergedArray[mergedArrayIndex] = leftArray[leftArrayIndex]; 46 | leftArrayIndex++; 47 | } 48 | else 49 | { 50 | mergedArray[mergedArrayIndex] = rightArray[rightArrayIndex]; 51 | rightArrayIndex++; 52 | } 53 | mergedArrayIndex++; 54 | } 55 | 56 | // Adding remaining elements from the left array (if any) 57 | while (leftArrayIndex < leftArray.Length) 58 | { 59 | mergedArray[mergedArrayIndex] = leftArray[leftArrayIndex]; 60 | leftArrayIndex++; 61 | mergedArrayIndex++; 62 | } 63 | 64 | // Adding remaining elements from the right array (if any) 65 | while (rightArrayIndex < rightArray.Length) 66 | { 67 | mergedArray[mergedArrayIndex] = rightArray[rightArrayIndex]; 68 | rightArrayIndex++; 69 | mergedArrayIndex++; 70 | } 71 | 72 | return mergedArray; 73 | } 74 | -------------------------------------------------------------------------------- /csharp/BinaryHeap/Heap.cs: -------------------------------------------------------------------------------- 1 | namespace BinaryHeap; 2 | 3 | public enum HeapType 4 | { 5 | Min, 6 | Max 7 | } 8 | 9 | public class Heap where T : IComparable 10 | { 11 | private List heap; 12 | private HeapType heapType; 13 | 14 | public Heap() : this(HeapType.Max) 15 | { 16 | } 17 | 18 | public Heap(HeapType heapType) 19 | { 20 | heap = new List(); 21 | this.heapType = heapType; 22 | } 23 | 24 | public bool IsEmpty() 25 | { 26 | return this.heap.Count == 0; 27 | } 28 | 29 | public void Push(T item) 30 | { 31 | var oldLength = heap.Count; 32 | heap.Add(item); 33 | SiftUp(oldLength); 34 | } 35 | 36 | public T Pop() 37 | { 38 | if (this.IsEmpty()) 39 | { 40 | return default; 41 | } 42 | 43 | var max = heap[0]; 44 | var last = heap[heap.Count - 1]; 45 | heap.RemoveAt(heap.Count - 1); 46 | 47 | if (heap.Count > 0) 48 | { 49 | heap[0] = last; 50 | SiftDown(0); 51 | } 52 | return max; 53 | } 54 | 55 | private void SiftUp(int index) 56 | { 57 | if (index == 0) 58 | { 59 | return; 60 | } 61 | 62 | int parentIndex = (index - 1) / 2; 63 | Func shouldSwap = (heapType == HeapType.Max) ? 64 | new Func((a, b) => a.CompareTo(b) > 0) : 65 | new Func((a, b) => a.CompareTo(b) < 0); 66 | 67 | if (shouldSwap(heap[index], heap[parentIndex])) 68 | { 69 | (heap[index], heap[parentIndex]) = (heap[parentIndex], heap[index]); 70 | SiftUp(parentIndex); 71 | } 72 | } 73 | 74 | private void SiftDown(int index) 75 | { 76 | int leftChildIndex = index * 2 + 1; 77 | int rightChildIndex = index * 2 + 2; 78 | 79 | if (leftChildIndex >= heap.Count) 80 | { 81 | return; 82 | } 83 | 84 | Func comparison = (heapType == HeapType.Max) ? 85 | new Func((a, b) => a.CompareTo(b) > 0) : 86 | new Func((a, b) => a.CompareTo(b) < 0); 87 | 88 | int childIndex = leftChildIndex; 89 | if (rightChildIndex < heap.Count && comparison(heap[rightChildIndex], heap[leftChildIndex])) 90 | { 91 | childIndex = rightChildIndex; 92 | } 93 | 94 | if (comparison(heap[childIndex], heap[index])) 95 | { 96 | (heap[index], heap[childIndex]) = (heap[childIndex], heap[index]); 97 | SiftDown(childIndex); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /csharp/BellmanFord/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | 3 | namespace BellmanFord; 4 | 5 | public static class GraphExtensions 6 | { 7 | public static int BellmanFordShortestPath(this Graph graph, Node from, Node to) 8 | { 9 | // Initialize a dictionary to store the shortest distance from the 'from' node to every other node. 10 | // Initially, the distance to the 'from' node is 0 and infinity (int.MaxValue) to all other nodes. 11 | // 'from' node is 0 because we start from this node 12 | var distances = graph.Nodes.ToDictionary(key => key, value => 13 | { 14 | return value == from ? 0 : int.MaxValue; 15 | }); 16 | 17 | // This flag helps to stop the algorithm early if no updates are made in a full iteration over all nodes. 18 | bool updated = true; 19 | 20 | // Relax edges up to 'n-1' times (where 'n' is the number of nodes). 21 | // This is because the shortest path in a graph without cycles will have at most 'n-1' edges. 22 | for (int node = 0; node < graph.Nodes.Count - 1; node++) 23 | { 24 | if (!updated) { 25 | break; 26 | } 27 | updated = false; 28 | 29 | // Iterate over all edges and update distances if a shorter path is found. 30 | // This process is called 'relaxation'. 31 | foreach (var node_edges in graph.Edges) 32 | { 33 | var currentNode = node_edges.Key; 34 | var cost = distances[currentNode]; 35 | 36 | // Update the distance if the sum of the current node's distance and the edge cost is smaller. 37 | foreach (var edge in node_edges.Value) 38 | { 39 | if (cost + edge.Cost < distances[edge.Node]) 40 | { 41 | distances[edge.Node] = cost + edge.Cost; 42 | updated = true; 43 | } 44 | } 45 | } 46 | } 47 | 48 | // Check for negative weight cycles which can be detected if we can relax any edge further. 49 | // If a further relaxation is possible, it means there's a negative cycle. 50 | foreach (var node_edges in graph.Edges) 51 | { 52 | var currentNode = node_edges.Key; 53 | var cost = distances[currentNode]; 54 | 55 | foreach (var edge in node_edges.Value) 56 | { 57 | if (cost + edge.Cost < distances[edge.Node]) 58 | { 59 | // If a negative cycle exists, the shortest path problem has no solution. 60 | // handle case 61 | return 0; 62 | } 63 | } 64 | } 65 | 66 | // After processing all nodes, retrieve the shortest path distance to the 'to' node 67 | // If this distance is still int.MaxValue, it means there's no path from 'from' node to 'to' node 68 | distances.TryGetValue(to, out int shortestPath); 69 | return shortestPath; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /csharp/Kruskal/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | using UnionFind; 3 | 4 | namespace Kruskal; 5 | 6 | public static class GraphExtensions 7 | { 8 | public static IEnumerable> KruskalMst(this Graph graph) 9 | { 10 | if (graph.Nodes.Count == 0) 11 | { 12 | return Enumerable.Empty>(); 13 | } 14 | 15 | // Map each node to a unique integer index for use in the union-find data structure 16 | var nodeIndexMap = new Dictionary, int>(); 17 | int index = 0; 18 | foreach (var node in graph.Nodes) 19 | { 20 | nodeIndexMap[node] = index++; 21 | } 22 | 23 | // Convert the graph's edges into a flat list and sort them by cost 24 | // Sorting the edges is a key step in Kruskal's algorithm, which processes edges in ascending order of cost 25 | var nodeEdges = graph.Edges 26 | .SelectMany(node => node.Value 27 | .Select(edge => new NodeEdge() 28 | { 29 | Cost = edge.Cost, 30 | From = node.Key, 31 | To = edge.Node 32 | })) 33 | .OrderBy(nodeEdge => nodeEdge.Cost); 34 | 35 | // The Union-Find structure quickly tells us if two nodes are in the same subset by checking if they have the same root. 36 | // If they do, it means they are already connected, and adding an edge between them would form a cycle. 37 | var unionFind = new UnionFindSet(graph.Nodes.Count); 38 | 39 | // Result 40 | var minimumSpanningTree = new List>(); 41 | 42 | foreach (var nodeEdge in nodeEdges) 43 | { 44 | // Determines if the nodes at either end of the current edge (nodeEdge.From and nodeEdge.To) are in different subsets (trees). 45 | // If they are in different subsets, it means that adding this edge will not create a cycle. 46 | // If they are in the same subset, adding the edge would complete a cycle, which we must avoid. 47 | var nodeX = unionFind.Find(nodeIndexMap[nodeEdge.From]); 48 | var nodeY = unionFind.Find(nodeIndexMap[nodeEdge.To]); 49 | 50 | // Ensures that the current edge connects two different subsets 51 | // If nodeX and nodeY are different, the nodes are in different subsets, and adding the edge is safe 52 | // WHY? 53 | // When it's confirmed that adding the edge won't create a cycle, 54 | // the Union operation merges the two subsets into a single subset. 55 | // This step is essential for progressively building the MST, as it connects different parts of the graph. 56 | if (nodeX != nodeY) 57 | { 58 | unionFind.Union(nodeX, nodeY); 59 | minimumSpanningTree.Add(nodeEdge); 60 | } 61 | } 62 | 63 | return minimumSpanningTree; 64 | } 65 | 66 | public class NodeEdge 67 | { 68 | public Node From { get; set; } 69 | public Node To { get; set; } 70 | public int Cost { get; set; } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /rust/src/graphs/dijkstra.rs: -------------------------------------------------------------------------------- 1 | use std::collections::{ BinaryHeap, HashMap, HashSet }; 2 | use std::cmp::Reverse; 3 | 4 | use crate::graphs::graph::{ Graph, Edge, Node }; 5 | 6 | use super::NodeIndex; 7 | 8 | impl Graph { 9 | pub fn dijkstra_shortest_path(&self, from_node: &Node, to_node: &Node) -> Option { 10 | if self.nodes.len() == 0 { 11 | return Some(0); 12 | } 13 | 14 | let mut distances = self.nodes.iter() 15 | .map(|node| { 16 | return if node == from_node { (&node.index, 0) } else { (&node.index, isize::MAX) }; 17 | }) 18 | .collect::>(); 19 | 20 | let mut visited: HashSet<&NodeIndex> = HashSet::new(); 21 | let mut heap: BinaryHeap> = BinaryHeap::new(); 22 | heap.push(Reverse((0, &from_node.index))); 23 | 24 | while let Some(Reverse((cost, node_ix))) = heap.pop() { 25 | if &cost > distances.get(&node_ix).unwrap_or(&isize::MAX) { 26 | continue; 27 | } 28 | 29 | let edges: &Vec = match self.edges.get(&node_ix) { 30 | Some(edges) => edges, 31 | None => continue 32 | }; 33 | 34 | for edge in edges { 35 | if cost + edge.cost < *distances.get(&edge.node_index).unwrap_or(&isize::MAX) { 36 | 37 | distances.insert(&edge.node_index, cost + edge.cost); 38 | if !visited.contains(&edge.node_index) { 39 | heap.push(Reverse((cost + edge.cost, &edge.node_index))); 40 | } 41 | } 42 | } 43 | visited.insert(&node_ix); 44 | } 45 | 46 | distances.get(&to_node.index) 47 | .copied() 48 | .filter(|&distance| distance != isize::MAX) 49 | 50 | } 51 | } 52 | 53 | 54 | #[cfg(test)] 55 | mod tests { 56 | use crate::graphs::GraphType; 57 | 58 | use super::*; 59 | 60 | #[test] 61 | fn find_path() { 62 | let mut graph = Graph::new(GraphType::Directed); 63 | let n1 = graph.add_node(1); 64 | let n2 = graph.add_node(2); 65 | let n3 = graph.add_node(3); 66 | 67 | graph.add_edge(n1, n2, 1); 68 | graph.add_edge(n2, n3, 1); 69 | 70 | let node1 = graph.get_node(n1).unwrap(); 71 | let node3 = graph.get_node(n3).unwrap(); 72 | 73 | assert_eq!(graph.dijkstra_shortest_path(node1, node3), Some(2)); 74 | } 75 | 76 | #[test] 77 | fn no_path_exists() { 78 | let mut graph = Graph::new(GraphType::Directed); 79 | let n1 = graph.add_node(1); 80 | let n2 = graph.add_node(2); 81 | 82 | let node1 = graph.get_node(n1).unwrap(); 83 | let node2 = graph.get_node(n2).unwrap(); 84 | 85 | assert_eq!(graph.dijkstra_shortest_path(node1, node2), None); 86 | } 87 | 88 | #[test] 89 | fn path_to_self() { 90 | let mut graph = Graph::new(GraphType::Directed); 91 | let n1 = graph.add_node(1); 92 | 93 | let node1 = graph.get_node(n1).unwrap(); 94 | 95 | assert_eq!(graph.dijkstra_shortest_path(node1, node1), Some(0)); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /csharp/BinarySearchTree/BinarySearchTree.cs: -------------------------------------------------------------------------------- 1 | namespace BinarySearchTree; 2 | 3 | public class TreeNode where T : IComparable 4 | { 5 | public T Value; 6 | public TreeNode Left; 7 | public TreeNode Right; 8 | 9 | public TreeNode(T value) 10 | { 11 | Value = value; 12 | Left = null; 13 | Right = null; 14 | } 15 | } 16 | 17 | public class BinarySearchTree where T : IComparable 18 | { 19 | public TreeNode Root; 20 | public uint Length { get; private set; } 21 | 22 | public BinarySearchTree() 23 | { 24 | Root = null; 25 | Length = 0; 26 | } 27 | 28 | public void Insert(T value) 29 | { 30 | if (Root != null) 31 | { 32 | InsertValue(Root, value); 33 | } 34 | else 35 | { 36 | Root = new TreeNode(value); 37 | } 38 | Length++; 39 | } 40 | 41 | private void InsertValue(TreeNode node, T value) 42 | { 43 | if (value.CompareTo(node.Value) < 0) 44 | { 45 | if (node.Left != null) 46 | InsertValue(node.Left, value); 47 | else 48 | node.Left = new TreeNode(value); 49 | } 50 | else 51 | { 52 | if (node.Right != null) 53 | InsertValue(node.Right, value); 54 | else 55 | node.Right = new TreeNode(value); 56 | } 57 | } 58 | 59 | public void Delete(T value) 60 | { 61 | Root = DeleteNode(Root, value); 62 | Length--; 63 | } 64 | 65 | private TreeNode DeleteNode(TreeNode node, T value) 66 | { 67 | if (node == null) 68 | return null; 69 | 70 | int compare = value.CompareTo(node.Value); 71 | if (compare < 0) 72 | node.Left = DeleteNode(node.Left, value); 73 | else if (compare > 0) 74 | node.Right = DeleteNode(node.Right, value); 75 | else 76 | { 77 | if (node.Left == null) 78 | return node.Right; 79 | else if (node.Right == null) 80 | return node.Left; 81 | 82 | TreeNode minNode = FindMin(node.Right); 83 | node.Value = minNode.Value; 84 | node.Right = DeleteNode(node.Right, minNode.Value); 85 | } 86 | return node; 87 | } 88 | 89 | private TreeNode FindMin(TreeNode node) 90 | { 91 | TreeNode current = node; 92 | while (current.Left != null) 93 | { 94 | current = current.Left; 95 | } 96 | return current; 97 | } 98 | 99 | public List GetAll() 100 | { 101 | var all = new List(); 102 | InOrderTraversal(Root, all); 103 | return all; 104 | } 105 | 106 | private void InOrderTraversal(TreeNode node, List all) 107 | { 108 | if (node == null) return; 109 | 110 | InOrderTraversal(node.Left, all); 111 | all.Add(node.Value); 112 | InOrderTraversal(node.Right, all); 113 | } 114 | 115 | public void Clear() 116 | { 117 | Root = null; 118 | Length = 0; 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /rust/src/graphs/bellman_ford.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | 3 | use crate::graphs::graph::{ Graph, Node }; 4 | 5 | impl Graph { 6 | pub fn bellman_ford_shortest_path(&self, from_node: &Node, to_node: &Node) -> Option { 7 | if self.nodes.len() == 0 { 8 | return Some(0); 9 | } 10 | 11 | let mut distances = self.nodes 12 | .iter() 13 | .map(|node| (node.index, isize::MAX)) 14 | .collect::>(); 15 | 16 | distances.insert(from_node.index, 0); 17 | 18 | let mut updated = true; 19 | for _ in 0..self.nodes.len() - 1 { 20 | if !updated { 21 | break; 22 | } 23 | updated = false; 24 | 25 | for node_edges in self.edges.iter() { 26 | let node_index = node_edges.0; 27 | let cost = *distances.get(node_index).unwrap_or(&isize::MAX); 28 | 29 | for edge in node_edges.1.iter() { 30 | if cost + edge.cost < *distances.get(&edge.node_index).unwrap_or(&isize::MAX) { 31 | distances.insert(edge.node_index, cost + edge.cost); 32 | updated = true; 33 | } 34 | } 35 | } 36 | } 37 | 38 | for node_edges in self.edges.iter() { 39 | let cost = *distances.get(node_edges.0).unwrap_or(&isize::MAX); 40 | 41 | for edge in node_edges.1.iter() { 42 | if cost + edge.cost < *distances.get(&edge.node_index).unwrap_or(&isize::MAX) { 43 | return None; 44 | } 45 | } 46 | } 47 | 48 | distances.get(&to_node.index) 49 | .copied() 50 | .filter(|&distance| distance != isize::MAX) 51 | } 52 | } 53 | 54 | 55 | #[cfg(test)] 56 | mod tests { 57 | use crate::graphs::GraphType; 58 | 59 | use super::*; 60 | 61 | #[test] 62 | fn find_path() { 63 | let mut graph = Graph::new(GraphType::Directed); 64 | let n1 = graph.add_node("А"); 65 | let n2 = graph.add_node("B"); 66 | let n3 = graph.add_node("C"); 67 | 68 | graph.add_edge(n1, n2, 5); 69 | graph.add_edge(n1, n3, 4); 70 | graph.add_edge(n2, n3, -2); 71 | 72 | let node1 = graph.get_node(n1).unwrap(); 73 | let node3 = graph.get_node(n3).unwrap(); 74 | 75 | assert_eq!(graph.bellman_ford_shortest_path(node1, node3), Some(3)); 76 | } 77 | 78 | #[test] 79 | fn negative_cycle() { 80 | let mut graph = Graph::new(GraphType::Directed); 81 | let n1 = graph.add_node(1); 82 | let n2 = graph.add_node(2); 83 | 84 | graph.add_edge(n1, n1, -1); 85 | 86 | let node1 = graph.get_node(n1).unwrap(); 87 | let node2 = graph.get_node(n2).unwrap(); 88 | 89 | assert_eq!(graph.bellman_ford_shortest_path(node1, node2), None); 90 | } 91 | 92 | #[test] 93 | fn test_path_to_self() { 94 | let mut graph = Graph::new(GraphType::Directed); 95 | let n1 = graph.add_node(1); 96 | 97 | let node1 = graph.get_node(n1).unwrap(); 98 | 99 | assert_eq!(graph.bellman_ford_shortest_path(node1, node1), Some(0)); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /csharp/Dijkstra/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | 3 | namespace Dijkstra; 4 | 5 | public static class GraphExtensions 6 | { 7 | public static int DijkstraShortestPath(this Graph graph, Node from, Node to) 8 | { 9 | // Initialize a dictionary to store the shortest distance from the 'from' node to every other node. 10 | // Initially, the distance to the 'from' node is 0 and infinity (int.MaxValue) to all other nodes. 11 | // 'from' node is 0 because we start from this node 12 | var distances = graph.Nodes.ToDictionary(key => key, value => 13 | { 14 | return value == from ? 0 : int.MaxValue; 15 | }); 16 | 17 | // HashSet to keep track of visited nodes to avoid reprocessing. 18 | var visited = new HashSet>(); 19 | 20 | // PriorityQueue to select the node with the minimum distance for processing next. 21 | // It stores pairs of (Node, Distance) and sorts them by Distance. 22 | var queue = new PriorityQueue<(Node, int), int>(); 23 | queue.Enqueue((from, 0), 0); 24 | 25 | while (queue.Count > 0) 26 | { 27 | // Dequeue the node with the smallest known distance. 28 | // On first step this is 'from' node with 0 29 | var dequeueItem = queue.Dequeue(); 30 | var node = dequeueItem.Item1; 31 | var cost = dequeueItem.Item2; 32 | 33 | // Check if the current node has adjacent nodes. 34 | if (graph.Edges.TryGetValue(node, out var edges)) 35 | { 36 | // For each adjacent node, calculate the distance through the current node. 37 | foreach (var edge in edges) 38 | { 39 | // This line checks if the current path to the adjacent node (edge.Node) is shorter than any previously found paths 40 | // The 'distances.TryGetValue(edge.Node, out int value)' attempts to get the current shortest known distance to the adjacent node 41 | // The 'cost > value' part checks if the current total cost to reach 'edge.Node' 42 | // via the current node is greater than this known shortest distance ('value') 43 | // If it is, this means that the current path is not shorter than the already known path to 'edge.Node',and we skip 44 | if (!distances.TryGetValue(edge.Node, out int value) || cost > value) 45 | continue; 46 | 47 | // If the path through the current node is shorter, update the distance of the adjacent node. 48 | if ((cost + edge.Cost) < distances[edge.Node]) 49 | { 50 | var newCost = cost + edge.Cost; 51 | distances[edge.Node] = newCost; 52 | 53 | // If the adjacent node is unvisited, add it to the queue for further processing. 54 | if (!visited.Contains(edge.Node)) 55 | { 56 | queue.Enqueue((edge.Node, newCost), newCost); 57 | } 58 | } 59 | } 60 | // Mark the current node as visited 61 | visited.Add(node); 62 | } 63 | } 64 | 65 | // After processing all nodes, retrieve the shortest path distance to the 'to' node 66 | // If this distance is still int.MaxValue, it means there's no path from 'from' node to 'to' node 67 | distances.TryGetValue(to, out int shortestPath); 68 | if (shortestPath == int.MaxValue) 69 | { 70 | // handle the case where no path exists 71 | } 72 | return shortestPath; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /rust/src/graphs/kosaraju.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashSet; 2 | 3 | use crate::graphs::graph::{ Graph, NodeIndex }; 4 | 5 | impl Graph { 6 | pub fn kosaraju_scc(&self) -> Vec> { 7 | if self.nodes.len() == 0 { 8 | return vec![]; 9 | } 10 | 11 | let mut visited: HashSet = HashSet::new(); 12 | let mut stack: Vec = Vec::new(); 13 | 14 | for node in self.nodes.iter() { 15 | if !visited.contains(&node.index) { 16 | self.initial_dfs(&node.index, &mut visited, &mut stack); 17 | } 18 | } 19 | 20 | visited.clear(); 21 | let mut components: Vec> = Vec::new(); 22 | 23 | while let Some(node_index) = stack.pop() { 24 | if !visited.contains(&node_index) { 25 | let mut component = Vec::new(); 26 | self.dfs_scc(&node_index, &mut visited, &mut component); 27 | components.push(component); 28 | } 29 | } 30 | 31 | components 32 | } 33 | 34 | fn initial_dfs(&self, node_index: &NodeIndex, visited: &mut HashSet, stack: &mut Vec) { 35 | if visited.contains(&node_index) { 36 | return; 37 | } 38 | 39 | visited.insert(*node_index); 40 | 41 | if let Some(edges) = self.edges.get(&node_index) { 42 | for edge in edges { 43 | self.initial_dfs(&edge.node_index, visited, stack); 44 | } 45 | } 46 | 47 | stack.push(*node_index); 48 | } 49 | 50 | fn dfs_scc(&self, node_index: &NodeIndex, visited: &mut HashSet, component: &mut Vec) { 51 | if visited.contains(&node_index) { 52 | return; 53 | } 54 | 55 | visited.insert(*node_index); 56 | 57 | if let Some(edges) = self.edges.get(&node_index) { 58 | for edge in edges { 59 | self.dfs_scc(&edge.node_index, visited, component); 60 | } 61 | } 62 | 63 | component.push(*node_index); 64 | } 65 | } 66 | 67 | 68 | #[cfg(test)] 69 | mod tests { 70 | use crate::graphs::graph::{Graph, GraphType, Node, NodeIndex, Edge}; 71 | 72 | fn create_test_graph(edges: Vec<(usize, usize)>) -> Graph { 73 | let mut graph = Graph::new(GraphType::Directed); 74 | 75 | for (from, to) in edges { 76 | graph.nodes.push(Node { 77 | value: from as i32, 78 | index: NodeIndex { ix: from }, 79 | }); 80 | graph.edges.entry(NodeIndex { ix: from }) 81 | .or_insert_with(Vec::new) 82 | .push(Edge { 83 | cost: 1, 84 | node_index: NodeIndex { ix: to }, 85 | }); 86 | } 87 | 88 | graph 89 | } 90 | 91 | #[test] 92 | fn empty_graph() { 93 | let graph: Graph = Graph::new(GraphType::Undirected); 94 | let scc = graph.kosaraju_scc(); 95 | assert!(scc.is_empty()); 96 | } 97 | 98 | #[test] 99 | fn multiple_sccs() { 100 | let graph = create_test_graph(vec![(0, 1), (1, 2), (2, 0), (3, 4)]); 101 | let scc = graph.kosaraju_scc(); 102 | assert_eq!(scc.len(), 2); 103 | } 104 | 105 | #[test] 106 | fn single_node_graph() { 107 | let graph = create_test_graph(vec![(0, 0)]); 108 | let scc = graph.kosaraju_scc(); 109 | assert_eq!(scc.len(), 1); 110 | } 111 | 112 | #[test] 113 | fn disconnected_graph() { 114 | let graph = create_test_graph(vec![(0, 1), (2, 3)]); 115 | let scc = graph.kosaraju_scc(); 116 | assert_eq!(scc.len(), 2); 117 | } 118 | 119 | #[test] 120 | fn cycle_graph() { 121 | let graph = create_test_graph(vec![(0, 1), (1, 2), (2, 0)]); 122 | let scc = graph.kosaraju_scc(); 123 | assert_eq!(scc.len(), 1); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /csharp/Floyd–Warshall/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | 3 | namespace Floyd_Warshall; 4 | 5 | public static class GraphExtensions 6 | { 7 | public static int FloydWarshallShortestPath(this Graph graph, Node from, Node to) 8 | { 9 | var vertices = graph.Nodes.Count; 10 | 11 | // Create a map of each node to an integer index. This mapping is crucial for 12 | // using a 2D array to represent the distances between each pair of nodes. 13 | var nodesIndexes = GetNodesIndexes(graph); 14 | 15 | // Initialize a 2D array to store the shortest distances between each pair of vertices. 16 | // This array will be updated throughout the algorithm to reflect the shortest known distances. 17 | var distances = new int[vertices, vertices]; 18 | 19 | // Initialize the distances array. 20 | // The distance from a node to itself is 0; for all other nodes, it is initially set to 'int.MaxValue'. 21 | // This represents that initially, the shortest distance to these nodes is unknown (infinite). 22 | for (var row = 0; row < distances.GetLength(0); row++) 23 | { 24 | for (var column = 0; column < distances.GetLength(1); column++) 25 | { 26 | if (row == column) 27 | distances[row, column] = 0; 28 | else 29 | distances[row, column] = int.MaxValue; 30 | } 31 | } 32 | 33 | // Populate the distances array with the direct distances between nodes as per the graph's edges. 34 | // Sets up the base cases for the algorithm, representing the initial known distances. 35 | foreach (var nodeEdges in graph.Edges) 36 | { 37 | var source = nodesIndexes[nodeEdges.Key]; 38 | foreach (var edge in nodeEdges.Value) 39 | { 40 | var destination = nodesIndexes[edge.Node]; 41 | distances[source, destination] = edge.Cost; 42 | } 43 | } 44 | 45 | // Three nested loops iterate over all triplets of vertices (source, intermediate, destination). 46 | // We check if the path from source to destination via an intermediate vertex is shorter than the current known path. 47 | for (int intermediateVertex = 0; intermediateVertex < vertices; intermediateVertex++) 48 | { 49 | for (int sourceVertex = 0; sourceVertex < vertices; sourceVertex++) 50 | { 51 | for (int destinationVertex = 0; destinationVertex < vertices; destinationVertex++) 52 | { 53 | // Skip if the path from source to intermediate or intermediate to destination is infinite. 54 | // This means that there is no path between nodes. 55 | if (distances[sourceVertex, intermediateVertex] == int.MaxValue || 56 | distances[intermediateVertex, destinationVertex] == int.MaxValue) 57 | { 58 | continue; 59 | } 60 | 61 | // Update the distance if a shorter path is found via the intermediate vertex. 62 | if (distances[sourceVertex, intermediateVertex] + distances[intermediateVertex, destinationVertex] < distances[sourceVertex, destinationVertex]) 63 | distances[sourceVertex, destinationVertex] = distances[sourceVertex, intermediateVertex] + distances[intermediateVertex, destinationVertex]; 64 | } 65 | } 66 | } 67 | 68 | return distances[nodesIndexes[from], nodesIndexes[to]]; 69 | } 70 | 71 | private static IDictionary, int> GetNodesIndexes(Graph graph) 72 | { 73 | var nodesIndex = new Dictionary, int>(); 74 | int index = 0; 75 | 76 | // Creating a node-index mapping is necessary to translate the graph's node references to array indices. 77 | // This mapping simplifies the algorithm's operations on the distances array. 78 | foreach (var node in graph.Nodes) 79 | { 80 | nodesIndex[node] = index++; 81 | } 82 | return nodesIndex; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /csharp/Kosaraju/GraphExtensions.cs: -------------------------------------------------------------------------------- 1 | using Graphs; 2 | 3 | namespace Kosaraju; 4 | 5 | public static class GraphExtensions 6 | { 7 | public static List>> KosarajuSCCs(this Graph graph) 8 | { 9 | // Initialize a list to store the strongly connected components. 10 | var SCCs = new List>>(); 11 | 12 | if (graph.Nodes.Count == 0) 13 | { 14 | return SCCs; 15 | } 16 | 17 | var reverseGraph = new Graph(graph.GraphType); 18 | 19 | var visited = new HashSet>(); 20 | var stack = new Stack>(); 21 | 22 | // Perform the first DFS on the original graph. 23 | // The purpose of this DFS is to fill the stack with nodes in the order of their finishing times. 24 | // This is important for the second DFS phase, where nodes are processed in this order to identify SCCs. 25 | foreach (var node in graph.Nodes) 26 | { 27 | if (visited.Contains(node)) 28 | { 29 | continue; 30 | } 31 | Dfs(node, stack, visited); 32 | } 33 | 34 | Stack> Dfs(Node node, Stack> stack, HashSet> visited) 35 | { 36 | if (visited.Contains(node)) 37 | { 38 | return stack; 39 | } 40 | 41 | visited.Add(node); 42 | 43 | var hasEdges = graph.Edges.TryGetValue(node, out var edges); 44 | if (hasEdges && edges.Count > 0) 45 | { 46 | foreach (var edge in edges) 47 | { 48 | Dfs(edge.Node, stack, visited); 49 | } 50 | } 51 | 52 | stack.Push(node); 53 | return stack; 54 | } 55 | 56 | // Construct a mapping of incoming edges for each node. 57 | // This map will be used in the second DFS, where we need to traverse the graph in the 'reverse' direction without explicitly creating a reversed graph. 58 | var incomingEdges = new Dictionary, List>>(); 59 | foreach (var node in graph.Nodes) 60 | { 61 | if (graph.Edges.TryGetValue(node, out var edges)) 62 | { 63 | foreach (var edge in edges) 64 | { 65 | if (!incomingEdges.ContainsKey(edge.Node)) 66 | incomingEdges[edge.Node] = new List>(); 67 | incomingEdges[edge.Node].Add(node); 68 | } 69 | } 70 | } 71 | 72 | // Reset the visited set for the second DFS. 73 | visited.Clear(); 74 | 75 | // Perform the second DFS using the stack filled during the first DFS. This DFS is done in the reverse 76 | // order of node completion from the first DFS. It uses the incoming edges map to traverse the graph in reverse. 77 | // This step is crucial for identifying SCCs, as nodes in an SCC will be reachable from each other in this reverse traversal. 78 | while (stack.Count != 0) 79 | { 80 | var node = stack.Pop(); 81 | if (!visited.Contains(node)) 82 | { 83 | var component = new List>(); 84 | ReverseDfs(node, component, incomingEdges); 85 | 86 | SCCs.Add(component); 87 | } 88 | } 89 | 90 | // The ReverseDfs method recursively explores nodes using the incoming edges map. 91 | // Nodes are added to the current component if they are reachable in this reversed context. 92 | // This effectively groups nodes of the same SCC together. 93 | void ReverseDfs(Node node, List> component, Dictionary, List>> edges) 94 | { 95 | if (visited.Contains(node)) return; 96 | 97 | visited.Add(node); 98 | component.Add(node); 99 | 100 | if (edges.TryGetValue(node, out var predecessors)) 101 | { 102 | foreach (var pred in predecessors) 103 | { 104 | ReverseDfs(pred, component, edges); 105 | } 106 | } 107 | } 108 | 109 | return SCCs; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /rust/src/data_structures/linked_list.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use std::ptr::NonNull; 3 | 4 | #[derive(Eq, PartialEq, Clone, Copy)] 5 | pub struct Node { 6 | pub value: N, 7 | pub next: Option>>, 8 | prev: Option>> 9 | } 10 | 11 | pub struct LinkedList { 12 | pub head: Option>>, 13 | pub tail: Option>>, 14 | pub length: usize, 15 | } 16 | 17 | impl LinkedList { 18 | pub fn new() -> Self { 19 | LinkedList { 20 | head: None, 21 | tail: None, 22 | length: 0 23 | } 24 | } 25 | 26 | pub fn is_empty(&self) -> bool { 27 | self.length == 0 28 | } 29 | 30 | pub fn add(&mut self, value: N) { 31 | let node: Node = Node { 32 | value, 33 | next: None, 34 | prev: self.tail 35 | }; 36 | 37 | unsafe { 38 | self.add_node(node); 39 | } 40 | self.length += 1; 41 | } 42 | 43 | unsafe fn add_node(&mut self, node: Node) { 44 | let node_box = Box::new(node); 45 | let node_ptr = NonNull::new(Box::into_raw(node_box)); 46 | 47 | match self.tail { 48 | Some(tail) => { 49 | (*tail.as_ptr()).next = node_ptr; 50 | self.tail = node_ptr; 51 | }, 52 | None => { 53 | self.head = node_ptr; 54 | self.tail = node_ptr; 55 | } 56 | } 57 | } 58 | 59 | pub fn get_all(&self) -> Vec { 60 | let node: Option>> = self.head; 61 | 62 | let result: Vec; 63 | unsafe { 64 | match self.get_all_nodes_values(node) { 65 | Some(v) => result = v, 66 | None => result = vec![] 67 | }; 68 | } 69 | result 70 | } 71 | 72 | unsafe fn get_all_nodes_values(&self, mut node: Option>>) -> Option> { 73 | let mut vec: Vec = vec![]; 74 | loop { 75 | match node { 76 | Some(n) => { 77 | let current_node = &(*n.as_ptr()); 78 | vec.push(current_node.value.clone()); 79 | node = current_node.next; 80 | }, 81 | None => break 82 | } 83 | } 84 | Some(vec) 85 | } 86 | 87 | pub fn delete(&mut self, value: N) { 88 | if self.is_empty() { 89 | return; 90 | } 91 | 92 | let node: Option>> = self.head; 93 | unsafe { 94 | self.delete_node(value, node); 95 | } 96 | } 97 | 98 | unsafe fn delete_node(&mut self, value: N, mut node: Option>>) { 99 | while let Some(current_node) = node { 100 | if current_node.as_ref().value == value { 101 | let old_ptr = Box::from_raw(current_node.as_ptr()); 102 | 103 | if let Some(mut prev) = old_ptr.prev { 104 | prev.as_mut().next = old_ptr.next; 105 | } 106 | 107 | if let Some(mut next) = old_ptr.next { 108 | next.as_mut().prev = old_ptr.prev; 109 | } 110 | 111 | self.length -= 1; 112 | break; 113 | } 114 | node = (*current_node.as_ptr()).next; 115 | } 116 | } 117 | 118 | pub fn clear(&mut self) { 119 | unsafe { 120 | self.clear_all_nodes(); 121 | } 122 | 123 | self.head = None; 124 | self.tail = None; 125 | self.length = 0; 126 | } 127 | 128 | unsafe fn clear_all_nodes(&mut self) { 129 | while let Some(node) = self.head { 130 | let boxed_node = Box::from_raw(node.as_ptr()); 131 | self.head = boxed_node.next; 132 | } 133 | } 134 | } 135 | 136 | impl Drop for LinkedList { 137 | fn drop(&mut self) { 138 | while let Some(node) = self.head { 139 | unsafe { 140 | let boxed_node = Box::from_raw(node.as_ptr()); 141 | self.head = boxed_node.next; 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /rust/src/data_structures/heap.rs: -------------------------------------------------------------------------------- 1 | #[derive(PartialEq)] 2 | pub enum HeapType { 3 | Min, 4 | Max 5 | } 6 | 7 | pub struct Heap { 8 | data: Vec, 9 | heap_type: HeapType 10 | } 11 | 12 | impl Heap { 13 | pub fn new(heap_type: HeapType) -> Self { 14 | Self { 15 | data: vec![], 16 | heap_type 17 | } 18 | } 19 | 20 | pub fn is_empty(&self) -> bool { 21 | self.data.len() == 0 22 | } 23 | 24 | pub fn push(&mut self, item: T) { 25 | let old_len = self.data.len(); 26 | self.data.push(item); 27 | self.sift_up(old_len); 28 | } 29 | 30 | pub fn pop(&mut self) -> Option { 31 | if self.is_empty() { 32 | return None; 33 | } 34 | 35 | let max = self.data[0]; 36 | let last = self.data.remove(self.data.len() - 1); 37 | 38 | if self.data.len() > 0 { 39 | self.data[0] = last; 40 | self.sift_down(0); 41 | } 42 | Some(max) 43 | } 44 | 45 | fn sift_up(&mut self, index: usize) { 46 | if index == 0 { 47 | return; 48 | } 49 | 50 | let parent_index = (index - 1) / 2; 51 | let should_swap = match self.heap_type { 52 | HeapType::Max => |a: &T, b: &T| a > b, 53 | HeapType::Min => |a: &T, b: &T| a < b, 54 | }; 55 | 56 | if should_swap(&self.data[index], &self.data[parent_index]) { 57 | self.data.swap(index, parent_index); 58 | self.sift_up(parent_index); 59 | } 60 | } 61 | 62 | fn sift_down(&mut self, index: usize) { 63 | let left_child_index = index * 2 + 1; 64 | let right_child_index = index * 2 + 2; 65 | if !self.is_valid_index(left_child_index) { 66 | return; 67 | } 68 | 69 | let comparison = match self.heap_type { 70 | HeapType::Max => |a: &T, b: &T| a > b, 71 | HeapType::Min => |a: &T, b: &T| a < b, 72 | }; 73 | 74 | let mut child_index = left_child_index; 75 | if self.is_valid_index(right_child_index) && comparison(&self.data[right_child_index], &self.data[left_child_index]) { 76 | child_index = right_child_index; 77 | } 78 | 79 | if comparison(&self.data[child_index], &self.data[index]) { 80 | self.data.swap(index, child_index); 81 | self.sift_down(child_index); 82 | } 83 | } 84 | 85 | fn is_valid_index(&self, index: usize) -> bool { 86 | index < self.data.len() 87 | } 88 | } 89 | 90 | 91 | #[cfg(test)] 92 | mod tests { 93 | use super::*; 94 | 95 | #[test] 96 | fn empty_min_heap() { 97 | let min_heap: Heap = Heap::new(HeapType::Min); 98 | assert!(min_heap.is_empty()); 99 | } 100 | 101 | #[test] 102 | fn empty_max_heap() { 103 | let max_heap: Heap = Heap::new(HeapType::Max); 104 | assert!(max_heap.is_empty()); 105 | } 106 | 107 | #[test] 108 | fn test_single_node_min_heap() { 109 | let mut min_heap = Heap::new(HeapType::Min); 110 | min_heap.push(10); 111 | assert_eq!(min_heap.pop(), Some(10)); 112 | assert!(min_heap.is_empty()); 113 | } 114 | 115 | #[test] 116 | fn test_single_node_max_heap() { 117 | let mut max_heap = Heap::new(HeapType::Max); 118 | max_heap.push(10); 119 | assert_eq!(max_heap.pop(), Some(10)); 120 | assert!(max_heap.is_empty()); 121 | } 122 | 123 | #[test] 124 | fn test_multiple_nodes_min_heap() { 125 | let mut min_heap = Heap::new(HeapType::Min); 126 | min_heap.push(10); 127 | min_heap.push(5); 128 | min_heap.push(15); 129 | assert_eq!(min_heap.pop(), Some(5)); 130 | assert_eq!(min_heap.pop(), Some(10)); 131 | assert_eq!(min_heap.pop(), Some(15)); 132 | } 133 | 134 | #[test] 135 | fn test_multiple_nodes_max_heap() { 136 | let mut max_heap = Heap::new(HeapType::Max); 137 | max_heap.push(10); 138 | max_heap.push(5); 139 | max_heap.push(15); 140 | assert_eq!(max_heap.pop(), Some(15)); 141 | assert_eq!(max_heap.pop(), Some(10)); 142 | assert_eq!(max_heap.pop(), Some(5)); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /rust/src/data_structures/red_black_tree.rs: -------------------------------------------------------------------------------- 1 | use std::{ops::Not, ptr::NonNull}; 2 | 3 | #[derive(Eq, PartialEq, Clone, Copy)] 4 | enum Side { 5 | Left, 6 | Right, 7 | } 8 | 9 | #[derive(Eq, PartialEq)] 10 | enum Color { 11 | Red, 12 | Black, 13 | } 14 | 15 | struct TreeNode { 16 | value: T, 17 | color: Color, 18 | left: Option>>, 19 | right: Option>>, 20 | parent: Option>>, 21 | is_root: bool 22 | } 23 | 24 | #[derive(Eq, PartialEq, Ord, PartialOrd)] 25 | pub struct RedBlackTree { 26 | root: Option>>, 27 | length: usize 28 | } 29 | 30 | impl Not for Side { 31 | type Output = Side; 32 | 33 | fn not(self) -> Self::Output { 34 | match self { 35 | Side::Left => Side::Right, 36 | Side::Right => Side::Left, 37 | } 38 | } 39 | } 40 | 41 | impl TreeNode { 42 | fn new(value: T) -> Self { 43 | TreeNode { 44 | value, 45 | color: Color::Red, 46 | left: None, 47 | right: None, 48 | parent: None, 49 | is_root: false 50 | } 51 | } 52 | 53 | fn root(value: T) -> Self { 54 | TreeNode { 55 | value, 56 | color: Color::Black, 57 | left: None, 58 | right: None, 59 | parent: None, 60 | is_root: true 61 | } 62 | } 63 | 64 | fn change_color(&mut self) { 65 | self.color = match self.color { 66 | Color::Black => Color::Red, 67 | Color::Red => Color::Black 68 | }; 69 | } 70 | 71 | fn child(&mut self, side: Side) -> &Option>> { 72 | match side { 73 | Side::Left => &self.left, 74 | Side::Right => &self.right, 75 | } 76 | } 77 | 78 | fn child_mut(&mut self, side: Side) -> &mut Option>> { 79 | match side { 80 | Side::Left => &mut self.left, 81 | Side::Right => &mut self.right, 82 | } 83 | } 84 | 85 | fn check_color_match(&self) -> Option { 86 | let left_match = self 87 | .left 88 | .as_ref() 89 | .map_or(false, |&left_non_null| unsafe { 90 | self.color == Color::Red && self.color == left_non_null.as_ref().color 91 | }); 92 | 93 | if left_match { 94 | return Some(Side::Left); 95 | } 96 | 97 | let right_match = self 98 | .right 99 | .as_ref() 100 | .map_or(false, |&right_non_null| unsafe { 101 | self.color == Color::Red && self.color == right_non_null.as_ref().color 102 | }); 103 | 104 | if right_match { 105 | return Some(Side::Right); 106 | } 107 | 108 | None // no rotations are needed 109 | } 110 | } 111 | 112 | impl RedBlackTree { 113 | pub fn new() -> Self { 114 | RedBlackTree { 115 | root: None, 116 | length: 0 117 | } 118 | } 119 | 120 | pub fn insert(&mut self, value: T) -> bool { 121 | let inserted; 122 | if let Some(mut root) = self.root { 123 | unsafe { 124 | inserted = insert_value(&mut root, value); 125 | self.update_root(); 126 | self.length += 1; 127 | } 128 | } else { 129 | let root_box = Box::new(TreeNode::::root(value)); 130 | let root_ptr = NonNull::new(Box::into_raw(root_box)); 131 | self.root = root_ptr; 132 | self.length += 1; 133 | inserted = true; 134 | } 135 | inserted 136 | } 137 | 138 | fn update_root(&mut self) { 139 | unsafe { 140 | while let Some(mut root) = self.root { 141 | if let Some(mut parent) = root.as_ref().parent { 142 | root.as_mut().is_root = false; 143 | parent.as_mut().is_root = true; 144 | self.root = Some(parent); 145 | } else { 146 | break; 147 | } 148 | } 149 | } 150 | } 151 | } 152 | 153 | 154 | unsafe fn insert_value(node: &mut NonNull>, value: T) -> bool { 155 | let node_ptr = node.as_mut(); 156 | if node_ptr.value == value { 157 | return false; // Value already exists in the tree 158 | } 159 | 160 | let target_node = 161 | if value < node_ptr.value { 162 | &mut node_ptr.left 163 | } else { 164 | &mut node_ptr.right 165 | }; 166 | 167 | let inserted = match target_node { 168 | Some(mut ptr) => insert_value(&mut ptr, value), 169 | None => { 170 | let mut new_node = TreeNode::::new(value); 171 | new_node.parent = Some(*node); 172 | 173 | let node_box = Box::new(new_node); 174 | let node_ptr = NonNull::new(Box::into_raw(node_box)); 175 | *target_node = node_ptr; 176 | true 177 | } 178 | }; 179 | 180 | let match_side = node.as_ref().check_color_match(); // Return 'Side' if node and new_node are with same 'Red' color 181 | if match_side.is_some() { 182 | // TODO: 183 | } 184 | 185 | inserted 186 | } 187 | -------------------------------------------------------------------------------- /rust/src/data_structures/binary_search_tree.rs: -------------------------------------------------------------------------------- 1 | use std::ptr::NonNull; 2 | 3 | #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] 4 | struct TreeNode { 5 | value: T, 6 | left: Option>>, 7 | right: Option>> 8 | } 9 | 10 | #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] 11 | pub struct BinarySearchTree { 12 | root: Option>>, 13 | pub length: u32 14 | } 15 | 16 | impl TreeNode { 17 | fn new(value: T) -> Self { 18 | TreeNode { 19 | value, 20 | left: None, 21 | right: None 22 | } 23 | } 24 | } 25 | 26 | impl BinarySearchTree { 27 | pub fn new() -> Self { 28 | BinarySearchTree { 29 | root: None, 30 | length: 0 31 | } 32 | } 33 | 34 | pub fn insert(&mut self, value: T) { 35 | if let Some(root) = self.root { 36 | unsafe { 37 | insert_value(&mut (*root.as_ptr()), value); 38 | self.length += 1; 39 | } 40 | } else { 41 | let root_box = Box::new(TreeNode::::new(value)); 42 | let root_ptr = NonNull::new(Box::into_raw(root_box)); 43 | self.root = root_ptr; 44 | self.length += 1; 45 | } 46 | } 47 | 48 | pub fn delete(&mut self, value: T) { 49 | if let Some(mut root) = self.root { 50 | unsafe { 51 | self.root = delete_node(&mut root, value); 52 | self.length -= 1; 53 | } 54 | } 55 | } 56 | 57 | pub fn get_all(&self) -> Vec { 58 | let mut all = Vec::new(); 59 | if let Some(root) = self.root { 60 | unsafe { 61 | get_all_in_order(&root, &mut all); 62 | } 63 | } 64 | all 65 | } 66 | 67 | pub fn clear(&mut self) { 68 | unsafe { 69 | if let Some(root) = self.root { 70 | clear_all_nodes(&root); 71 | } 72 | } 73 | 74 | self.root = None; 75 | self.length = 0; 76 | } 77 | } 78 | 79 | 80 | unsafe fn insert_value(node: &mut TreeNode, value: T) { 81 | let target_node = 82 | if value < node.value { 83 | &mut node.left 84 | } else { 85 | &mut node.right 86 | }; 87 | 88 | match target_node { 89 | Some(ptr) => insert_value(&mut (*ptr.as_ptr()), value), 90 | None => { 91 | let node_box = Box::new(TreeNode::::new(value)); 92 | let node_ptr = NonNull::new(Box::into_raw(node_box)); 93 | *target_node = node_ptr; 94 | } 95 | } 96 | } 97 | 98 | unsafe fn get_all_in_order(node: &NonNull>, all: &mut Vec) { 99 | let tree_node = &(*node.as_ptr()); 100 | 101 | if let Some(left_node) = tree_node.left { 102 | get_all_in_order(&left_node, all); 103 | } 104 | 105 | all.push(tree_node.value); 106 | 107 | if let Some(right_node) = tree_node.right { 108 | get_all_in_order(&right_node, all); 109 | } 110 | } 111 | 112 | unsafe fn clear_all_nodes(node: &NonNull>) { 113 | let boxed_node = Box::from_raw(node.as_ptr()); 114 | 115 | if let Some(left_node) = boxed_node.left { 116 | clear_all_nodes(&left_node); 117 | } 118 | 119 | if let Some(right_node) = boxed_node.right { 120 | clear_all_nodes(&right_node); 121 | } 122 | } 123 | 124 | unsafe fn delete_node(node: &mut NonNull>, value: T) -> Option>> { 125 | let tree_node = &mut *node.as_ptr(); 126 | 127 | if value < tree_node.value { 128 | if let Some(mut left_node) = tree_node.left { 129 | tree_node.left = delete_node(&mut left_node, value); 130 | } 131 | } else if value > tree_node.value { 132 | if let Some(mut right_node) = tree_node.right { 133 | tree_node.right = delete_node(&mut right_node, value); 134 | } 135 | } else { 136 | if tree_node.left.is_none() { 137 | return tree_node.right; 138 | } else if tree_node.right.is_none() { 139 | return tree_node.left; 140 | } 141 | 142 | let mut successor = min_value_node(tree_node.right.unwrap()); 143 | tree_node.value = (*successor.as_ptr()).value; 144 | tree_node.right = delete_node(&mut successor, tree_node.value); 145 | } 146 | 147 | Some(*node) 148 | } 149 | 150 | unsafe fn min_value_node(node: NonNull>) -> NonNull> { 151 | let mut current = node; 152 | while let Some(left) = (*current.as_ptr()).left { 153 | current = left; 154 | } 155 | current 156 | } 157 | 158 | 159 | #[cfg(test)] 160 | mod tests { 161 | use super::*; 162 | 163 | #[test] 164 | fn test_insert() { 165 | let mut bst = BinarySearchTree::new(); 166 | bst.insert(5); 167 | bst.insert(3); 168 | bst.insert(7); 169 | assert_eq!(bst.length, 3); 170 | } 171 | 172 | #[test] 173 | fn test_get_all() { 174 | let mut bst = BinarySearchTree::new(); 175 | bst.insert(5); 176 | bst.insert(3); 177 | bst.insert(7); 178 | assert_eq!(bst.get_all(), vec![3, 5, 7]); 179 | } 180 | 181 | #[test] 182 | fn test_delete() { 183 | let mut bst = BinarySearchTree::new(); 184 | bst.insert(5); 185 | bst.insert(3); 186 | bst.insert(7); 187 | bst.delete(7); 188 | assert_eq!(bst.get_all(), vec![3, 5]); 189 | assert_eq!(bst.length, 2); 190 | } 191 | 192 | #[test] 193 | fn test_clear() { 194 | let mut bst = BinarySearchTree::new(); 195 | bst.insert(5); 196 | bst.insert(3); 197 | bst.insert(7); 198 | bst.clear(); 199 | assert_eq!(bst.get_all(), Vec::::new()); 200 | assert_eq!(bst.length, 0); 201 | } 202 | } -------------------------------------------------------------------------------- /rust/src/graphs/graph.rs: -------------------------------------------------------------------------------- 1 | #[derive(Ord, PartialOrd, Eq, Hash, PartialEq, Clone, Copy)] 2 | pub struct NodeIndex { 3 | pub ix: usize 4 | } 5 | 6 | #[derive(Ord, PartialOrd, Eq, Hash, PartialEq)] 7 | pub struct Node { 8 | pub value: N, 9 | pub index: NodeIndex 10 | } 11 | 12 | #[derive(PartialEq)] 13 | pub enum GraphType { 14 | Directed, 15 | Undirected 16 | } 17 | 18 | #[derive(PartialEq)] 19 | pub struct Edge { 20 | pub cost: isize, 21 | pub node_index: NodeIndex 22 | } 23 | 24 | pub struct Graph { 25 | pub nodes: Vec>, 26 | pub edges: std::collections::HashMap>, 27 | pub ty: GraphType, 28 | pub length: usize 29 | } 30 | 31 | impl Graph { 32 | pub fn new(graph_type: GraphType) -> Self { 33 | Graph { 34 | nodes: Vec::new(), 35 | edges: std::collections::HashMap::new(), 36 | ty: graph_type, 37 | length: 0 38 | } 39 | } 40 | 41 | pub fn add_node(&mut self, value: N) -> NodeIndex { 42 | let index = NodeIndex { 43 | ix: self.nodes.len() 44 | }; 45 | 46 | self.nodes.push(Node { 47 | value: value, 48 | index: index 49 | }); 50 | self.length += 1; 51 | index 52 | } 53 | 54 | pub fn add_edge(&mut self, from: NodeIndex, to: NodeIndex, cost: isize) { 55 | if from.ix >= self.nodes.len() || to.ix >= self.nodes.len() { 56 | return; // Invalid node index 57 | } 58 | 59 | self.edges.entry(from) 60 | .or_insert_with(Vec::new) 61 | .push(Edge { 62 | cost, 63 | node_index: to 64 | }); 65 | 66 | if self.ty == GraphType::Undirected { 67 | self.edges.entry(to) 68 | .or_insert_with(Vec::new) 69 | .push(Edge { 70 | cost, 71 | node_index: from 72 | }); 73 | } 74 | } 75 | 76 | pub fn delete_node(&mut self, node_index: NodeIndex) { 77 | for (_, edges) in self.edges.iter_mut() { 78 | edges.retain(|edge| edge.node_index != node_index); 79 | } 80 | 81 | self.edges.remove(&node_index); 82 | self.nodes.remove(node_index.ix); 83 | 84 | for node in self.nodes.iter_mut() { 85 | if node.index.ix > node_index.ix { 86 | if let Some(edges) = self.edges.remove(&node.index) { 87 | self.edges.insert(NodeIndex { 88 | ix: node.index.ix - 1 89 | }, 90 | edges); 91 | } 92 | node.index.ix -= 1; 93 | } 94 | } 95 | 96 | self.length -= 1; 97 | } 98 | 99 | pub fn delete_edge(&mut self, from: NodeIndex, to: NodeIndex) { 100 | if let Some(edges) = self.edges.get_mut(&from) { 101 | 102 | let pos = edges.iter().position(|edge| edge.node_index == to); 103 | if let Some(pos) = pos { 104 | edges.remove(pos); 105 | } 106 | } 107 | } 108 | 109 | pub fn get_node(&self, node_index: NodeIndex) -> Option<&Node> { 110 | self.nodes.get(node_index.ix) 111 | } 112 | } 113 | 114 | 115 | #[cfg(test)] 116 | mod tests { 117 | use super::*; 118 | 119 | #[test] 120 | fn empty() { 121 | let empty_graph: Graph = Graph::new(GraphType::Undirected); 122 | assert_eq!(empty_graph.length, 0); 123 | } 124 | 125 | #[test] 126 | fn add_node() { 127 | let mut graph: Graph = Graph::new(GraphType::Undirected); 128 | assert_eq!(graph.length, 0); 129 | 130 | let node_index = graph.add_node(5); 131 | assert_eq!(graph.length, 1); 132 | assert_eq!(graph.get_node(node_index).unwrap().value, 5); 133 | } 134 | 135 | #[test] 136 | fn add_edge() { 137 | let mut graph: Graph = Graph::new(GraphType::Undirected); 138 | let node1 = graph.add_node(1); 139 | let node2 = graph.add_node(2); 140 | 141 | graph.add_edge(node1, node2, 10); 142 | 143 | let edges = graph.edges.get(&node1).unwrap(); 144 | assert_eq!(edges[0].cost, 10); 145 | assert_eq!(edges[0].node_index.ix, node2.ix); 146 | } 147 | 148 | #[test] 149 | fn directed_edges() { 150 | let mut graph: Graph = Graph::new(GraphType::Directed); 151 | let node1 = graph.add_node(1); 152 | let node2 = graph.add_node(2); 153 | 154 | graph.add_edge(node1, node2, 10); 155 | 156 | let edges = graph.edges.get(&node1).unwrap(); 157 | assert_eq!(edges[0].cost, 10); 158 | assert_eq!(edges[0].node_index.ix, node2.ix); 159 | assert!(graph.edges.get(&node2).is_none()); 160 | } 161 | 162 | #[test] 163 | fn delete_node() { 164 | let mut graph: Graph = Graph::new(GraphType::Undirected); 165 | let node1 = graph.add_node(1); 166 | let node2 = graph.add_node(2); 167 | 168 | graph.add_edge(node1, node2, 10); 169 | graph.delete_node(node1); 170 | 171 | assert!(graph.get_node(node2).is_none()); 172 | assert_eq!(graph.get_node(node1).unwrap().value, 2); 173 | assert_eq!(graph.edges.get(&node1).unwrap().len(), 0); 174 | assert_eq!(graph.length, 1); 175 | } 176 | 177 | #[test] 178 | fn delete_edge() { 179 | let mut graph: Graph = Graph::new(GraphType::Undirected); 180 | let node1 = graph.add_node(1); 181 | let node2 = graph.add_node(2); 182 | 183 | graph.add_edge(node1, node2, 10); 184 | graph.delete_edge(node1, node2); 185 | 186 | let edges = graph.edges.get(&node1).unwrap(); 187 | assert!(edges.is_empty()); 188 | } 189 | 190 | #[test] 191 | fn get_node() { 192 | let mut graph: Graph = Graph::new(GraphType::Undirected); 193 | let node1 = graph.add_node(1); 194 | 195 | let retrieved_node = graph.get_node(node1).unwrap(); 196 | assert_eq!(retrieved_node.value, 1); 197 | } 198 | 199 | #[test] 200 | fn invalid_node_index() { 201 | let graph: Graph = Graph::new(GraphType::Undirected); 202 | assert!(graph.get_node(NodeIndex { ix: 999 }).is_none()); 203 | } 204 | 205 | #[test] 206 | fn graph_length() { 207 | let mut graph: Graph = Graph::new(GraphType::Undirected); 208 | graph.add_node(1); 209 | graph.add_node(2); 210 | 211 | assert_eq!(graph.length, 2); 212 | } 213 | } -------------------------------------------------------------------------------- /csharp/AVLTree/AVLTree.cs: -------------------------------------------------------------------------------- 1 | namespace AVLTree; 2 | 3 | public enum Side 4 | { 5 | Left, Right, 6 | } 7 | 8 | public static class SideExtensions 9 | { 10 | public static Side Switch(this Side side) 11 | => side switch 12 | { 13 | Side.Left => Side.Right, 14 | Side.Right => Side.Left, 15 | _ => throw new ArgumentOutOfRangeException(nameof(side), side, null), 16 | }; 17 | } 18 | 19 | public class TreeNode where T : IComparable 20 | { 21 | public T Value; 22 | public int Height; 23 | public TreeNode Left; 24 | public TreeNode Right; 25 | 26 | internal TreeNode(T value) 27 | { 28 | Value = value; 29 | this.Height = 1; 30 | } 31 | 32 | internal TreeNode GetChildNode(Side side) 33 | { 34 | var node = side switch 35 | { 36 | Side.Left => this.Left, 37 | Side.Right => this.Right, 38 | _ => throw new ArgumentException(null, nameof(side)), 39 | }; 40 | 41 | return node; 42 | } 43 | 44 | internal int GetHeight(Side side) 45 | { 46 | var node = this.GetChildNode(side); 47 | return node != null 48 | ? node.Height 49 | : 0; 50 | } 51 | 52 | internal void UpdateHeight() 53 | { 54 | this.Height = 1 + Math.Max(this.GetHeight(Side.Left), this.GetHeight(Side.Right)); 55 | } 56 | 57 | internal int GetBalanceFactor() 58 | { 59 | var leftHeight = this.GetHeight(Side.Left); 60 | var rightHeight = this.GetHeight(Side.Right); 61 | 62 | if (leftHeight > rightHeight) 63 | { 64 | return leftHeight - rightHeight; 65 | } 66 | else 67 | { 68 | return -(rightHeight - leftHeight); 69 | } 70 | } 71 | } 72 | 73 | public class AVLTree where T : IComparable 74 | { 75 | public TreeNode Root; 76 | public uint Length { get; private set; } 77 | 78 | public AVLTree() 79 | { 80 | Root = null; 81 | Length = 0; 82 | } 83 | 84 | public bool Insert(T value) 85 | { 86 | bool inserted = true; 87 | if (Root != null) 88 | { 89 | inserted = InsertNode(Root, value); 90 | } 91 | else 92 | { 93 | Root = new TreeNode(value); 94 | } 95 | 96 | if (inserted) 97 | { 98 | Length++; 99 | } 100 | return inserted; 101 | } 102 | 103 | public bool Delete(T value) 104 | { 105 | bool deleted = false; 106 | var deletedNode = DeleteNode(Root, value); 107 | if (deletedNode != null) 108 | { 109 | Length--; 110 | deleted = true; 111 | } 112 | 113 | return deleted; 114 | } 115 | 116 | private bool InsertNode(TreeNode node, T value) 117 | { 118 | if (node.Value.CompareTo(value) == 0) 119 | { 120 | return false; 121 | } 122 | 123 | if (value.CompareTo(node.Value) < 0) 124 | { 125 | if (node.Left != null) 126 | InsertNode(node.Left, value); 127 | else 128 | node.Left = new TreeNode(value); 129 | } 130 | else 131 | { 132 | if (node.Right != null) 133 | InsertNode(node.Right, value); 134 | else 135 | node.Right = new TreeNode(value); 136 | } 137 | 138 | Rebalance(node); 139 | return true; 140 | } 141 | 142 | private TreeNode DeleteNode(TreeNode node, T value) 143 | { 144 | if (node == null) 145 | return null; 146 | 147 | int compare = value.CompareTo(node.Value); 148 | if (compare < 0) 149 | { 150 | node.Left = DeleteNode(node.Left, value); 151 | } 152 | else if (compare > 0) 153 | { 154 | node.Right = DeleteNode(node.Right, value); 155 | } 156 | else 157 | { 158 | if (node.Left == null) 159 | { 160 | return node.Right; 161 | } 162 | else if (node.Right == null) 163 | { 164 | return node.Left; 165 | } 166 | 167 | TreeNode minNode = FindMin(node.Right); 168 | node.Value = minNode.Value; 169 | node.Right = DeleteNode(node.Right, minNode.Value); 170 | } 171 | 172 | Rebalance(node); 173 | return node; 174 | } 175 | 176 | private TreeNode FindMin(TreeNode node) 177 | { 178 | TreeNode current = node; 179 | while (current.Left != null) 180 | { 181 | current = current.Left; 182 | } 183 | return current; 184 | } 185 | 186 | private void Rebalance(TreeNode node) 187 | { 188 | node.UpdateHeight(); 189 | 190 | Side side; 191 | var balanceFactor = node.GetBalanceFactor(); 192 | if (balanceFactor == 2) 193 | { 194 | side = Side.Left; 195 | } 196 | else if (balanceFactor == -2) 197 | { 198 | side = Side.Right; 199 | } 200 | else 201 | { 202 | return; 203 | } 204 | 205 | var subtree = node.GetChildNode(side); 206 | var subtreeBalanceFactor = subtree.GetBalanceFactor(); 207 | if ((side == Side.Left && subtreeBalanceFactor == -1) || (side == Side.Right && subtreeBalanceFactor == 1)) 208 | { 209 | Rotate(side.Switch(), subtree, node); 210 | } 211 | Rotate(side, node); 212 | } 213 | 214 | private void Rotate(Side side, TreeNode node, TreeNode parent = null) 215 | { 216 | var childNode = node.GetChildNode(side); 217 | if (childNode == null) 218 | throw new InvalidOperationException(nameof(childNode)); 219 | 220 | if (side == Side.Left) 221 | { 222 | var rightChildNode = childNode.Right; 223 | childNode.Right = node; 224 | node.Left = rightChildNode; 225 | } 226 | else 227 | { 228 | var leftChildNode = childNode.Left; 229 | childNode.Left = node; 230 | node.Right = leftChildNode; 231 | } 232 | 233 | if (parent != null) 234 | { 235 | if (side.Switch() == Side.Left) 236 | { 237 | parent.Left = childNode; 238 | } 239 | else 240 | { 241 | parent.Right = childNode; 242 | } 243 | } 244 | 245 | if (this.Root.Value.CompareTo(node.Value) == 0) 246 | { 247 | this.Root = childNode; 248 | } 249 | 250 | node.UpdateHeight(); 251 | childNode.UpdateHeight(); 252 | } 253 | } 254 | -------------------------------------------------------------------------------- /csharp/RedBlackTree/RedBlackTree.cs: -------------------------------------------------------------------------------- 1 | namespace RedBlackTree; 2 | 3 | public enum Side 4 | { 5 | Left, Right, 6 | } 7 | 8 | public enum Color 9 | { 10 | Red, Black, 11 | } 12 | 13 | public static class SideExtensions 14 | { 15 | public static Side Switch(this Side side) 16 | => side switch 17 | { 18 | Side.Left => Side.Right, 19 | Side.Right => Side.Left, 20 | _ => throw new ArgumentOutOfRangeException(nameof(side), side, null), 21 | }; 22 | } 23 | 24 | public class TreeNode where T : IComparable 25 | { 26 | public T Value; 27 | public Color Color; 28 | public TreeNode Left; 29 | public TreeNode Right; 30 | public TreeNode Parent; 31 | public bool IsRoot; 32 | 33 | internal TreeNode(T value, TreeNode parent = null, bool isRoot = false) 34 | { 35 | Value = value; 36 | Parent = parent; 37 | if (isRoot) 38 | { 39 | IsRoot = true; 40 | Color = Color.Black; 41 | } 42 | } 43 | 44 | internal TreeNode GetChildNode(Side side) 45 | { 46 | var node = side switch 47 | { 48 | Side.Left => this.Left, 49 | Side.Right => this.Right, 50 | _ => throw new ArgumentException(null, nameof(side)), 51 | }; 52 | 53 | return node; 54 | } 55 | 56 | internal void ChangeColor() 57 | { 58 | this.Color = this.Color switch 59 | { 60 | Color.Red => Color.Black, 61 | Color.Black => Color.Red, 62 | _ => throw new ArgumentException(null, nameof(Color)), 63 | }; 64 | } 65 | 66 | internal Side? CheckColorMatch() 67 | { 68 | if (Left != null && Color == Color.Red && Color == Left.Color) 69 | return Side.Left; 70 | 71 | if (Right != null && Color == Color.Red && Color == Right.Color) 72 | return Side.Right; 73 | 74 | return null; 75 | } 76 | } 77 | 78 | public class RedBlackTree where T : IComparable 79 | { 80 | public TreeNode Root; 81 | public uint Length { get; private set; } 82 | 83 | public RedBlackTree() 84 | { 85 | Root = null; 86 | Length = 0; 87 | } 88 | 89 | public bool Insert(T value) 90 | { 91 | bool inserted = false; 92 | if (Root != null) 93 | { 94 | inserted = InsertNode(Root, value, inserted); 95 | } 96 | else 97 | { 98 | Root = new TreeNode(value, isRoot: true); 99 | inserted = true; 100 | } 101 | 102 | if (inserted) 103 | { 104 | Length++; 105 | } 106 | return inserted; 107 | } 108 | 109 | private bool InsertNode(TreeNode node, T value, bool inserted) 110 | { 111 | TreeNode insertedNode = null; 112 | if (node.Value.CompareTo(value) == 0) 113 | { 114 | inserted = false; 115 | return inserted; 116 | } 117 | 118 | if (value.CompareTo(node.Value) < 0) 119 | { 120 | if (node.Left != null) 121 | inserted = InsertNode(node.Left, value, inserted); 122 | else 123 | { 124 | inserted = true; 125 | node.Left = new TreeNode(value, parent: node); 126 | insertedNode = node.Left; 127 | } 128 | } 129 | else 130 | { 131 | if (node.Right != null) 132 | inserted = InsertNode(node.Right, value, inserted); 133 | else 134 | { 135 | inserted = true; 136 | node.Right = new TreeNode(value, parent: node); 137 | insertedNode = node.Right; 138 | } 139 | } 140 | 141 | if (inserted) 142 | { 143 | var colorMatch = node.CheckColorMatch(); 144 | if (colorMatch.HasValue) 145 | { 146 | CheckForRebalancing(insertedNode, colorMatch.Value); 147 | } 148 | } 149 | 150 | return inserted; 151 | } 152 | 153 | private void CheckForRebalancing(TreeNode node, Side side) 154 | { 155 | if (node.Parent == null) return; 156 | 157 | if (node.Color == Color.Red && node.Parent.Color == Color.Red) 158 | { 159 | TreeNode grandParent = node.Parent?.Parent; 160 | TreeNode uncle = null; 161 | 162 | if (grandParent != null) 163 | { 164 | if (node.Parent == grandParent.Left) 165 | uncle = grandParent.Right; 166 | else 167 | uncle = grandParent.Left; 168 | } 169 | 170 | if (uncle != null && uncle.Color == Color.Red) 171 | { 172 | node.Parent.Color = Color.Black; 173 | uncle.Color = Color.Black; 174 | if (grandParent != null) 175 | { 176 | grandParent.Color = grandParent.IsRoot ? Color.Black : Color.Red; 177 | CheckForRebalancing(grandParent, side); 178 | } 179 | } 180 | else 181 | { 182 | if (uncle == null || uncle.Color == Color.Black) 183 | { 184 | if (grandParent != null) 185 | { 186 | if (node.Parent != grandParent.GetChildNode(side)) 187 | { 188 | Rotate(side, node.Parent); 189 | side = side.Switch(); 190 | } 191 | 192 | Rotate(side, grandParent); 193 | node.ChangeColor(); 194 | node.GetChildNode(side.Switch()).ChangeColor(); 195 | } 196 | } 197 | 198 | Root.Color = Color.Black; // Ensure root is always black 199 | } 200 | } 201 | } 202 | 203 | private void Rotate(Side side, TreeNode node) 204 | { 205 | // Save child and grandchild nodes 206 | TreeNode child = node.GetChildNode(side); 207 | TreeNode grandChild = child?.GetChildNode(side.Switch()); 208 | 209 | // Perform rotation 210 | if (node.IsRoot) 211 | { 212 | Root = child; 213 | child.Parent = null; 214 | child.IsRoot = true; 215 | } 216 | else 217 | { 218 | TreeNode parent = node.Parent; 219 | if (parent.Left == node) 220 | parent.Left = child; 221 | else 222 | parent.Right = child; 223 | 224 | child.Parent = parent; 225 | } 226 | 227 | node.Parent = child; 228 | if (side == Side.Left) 229 | { 230 | child.Right = node; 231 | node.Left = grandChild; 232 | } 233 | else 234 | { 235 | child.Left = node; 236 | node.Right = grandChild; 237 | } 238 | 239 | // Reassign grandchild 240 | if (grandChild != null) 241 | grandChild.Parent = node; 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /assets/logo-algos.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 18 | 21 | 25 | 26 | 27 | 29 | 31 | 35 | 47 | 50 | 52 | 53 | 55 | 59 | 60 | 64 | 66 | 69 | 70 | 72 | 76 | 77 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/visualstudio 2 | # Edit at https://www.gitignore.io/?templates=visualstudio 3 | 4 | ### VisualStudio ### 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 9 | 10 | /rust/target 11 | /rust/.vscode 12 | 13 | # User-specific files 14 | *.rsuser 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # User-specific files (MonoDevelop/Xamarin Studio) 21 | *.userprefs 22 | 23 | # Build results 24 | [Dd]ebug/ 25 | [Dd]ebugPublic/ 26 | [Rr]elease/ 27 | [Rr]eleases/ 28 | x64/ 29 | x86/ 30 | [Aa][Rr][Mm]/ 31 | [Aa][Rr][Mm]64/ 32 | bld/ 33 | [Bb]in/ 34 | [Oo]bj/ 35 | [Ll]og/ 36 | 37 | # Visual Studio 2015/2017 cache/options directory 38 | .vs/ 39 | # Uncomment if you have tasks that create the project's static files in wwwroot 40 | #wwwroot/ 41 | 42 | # Visual Studio 2017 auto generated files 43 | Generated\ Files/ 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUNIT 50 | *.VisualState.xml 51 | TestResult.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # StyleCop 67 | StyleCopReport.xml 68 | 69 | # Files built by Visual Studio 70 | *_i.c 71 | *_p.c 72 | *_h.h 73 | *.ilk 74 | *.meta 75 | *.obj 76 | *.iobj 77 | *.pch 78 | *.pdb 79 | *.ipdb 80 | *.pgc 81 | *.pgd 82 | *.rsp 83 | *.sbr 84 | *.tlb 85 | *.tli 86 | *.tlh 87 | *.tmp 88 | *.tmp_proj 89 | *_wpftmp.csproj 90 | *.log 91 | *.vspscc 92 | *.vssscc 93 | .builds 94 | *.pidb 95 | *.svclog 96 | *.scc 97 | 98 | # Chutzpah Test files 99 | _Chutzpah* 100 | 101 | # Visual C++ cache files 102 | ipch/ 103 | *.aps 104 | *.ncb 105 | *.opendb 106 | *.opensdf 107 | *.sdf 108 | *.cachefile 109 | *.VC.db 110 | *.VC.VC.opendb 111 | 112 | # Visual Studio profiler 113 | *.psess 114 | *.vsp 115 | *.vspx 116 | *.sap 117 | 118 | # Visual Studio Trace Files 119 | *.e2e 120 | 121 | # TFS 2012 Local Workspace 122 | $tf/ 123 | 124 | # Guidance Automation Toolkit 125 | *.gpState 126 | 127 | # ReSharper is a .NET coding add-in 128 | _ReSharper*/ 129 | *.[Rr]e[Ss]harper 130 | *.DotSettings.user 131 | 132 | # JustCode is a .NET coding add-in 133 | .JustCode 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Visual Studio code coverage results 146 | *.coverage 147 | *.coveragexml 148 | 149 | # NCrunch 150 | _NCrunch_* 151 | .*crunch*.local.xml 152 | nCrunchTemp_* 153 | 154 | # MightyMoose 155 | *.mm.* 156 | AutoTest.Net/ 157 | 158 | # Web workbench (sass) 159 | .sass-cache/ 160 | 161 | # Installshield output folder 162 | [Ee]xpress/ 163 | 164 | # DocProject is a documentation generator add-in 165 | DocProject/buildhelp/ 166 | DocProject/Help/*.HxT 167 | DocProject/Help/*.HxC 168 | DocProject/Help/*.hhc 169 | DocProject/Help/*.hhk 170 | DocProject/Help/*.hhp 171 | DocProject/Help/Html2 172 | DocProject/Help/html 173 | 174 | # Click-Once directory 175 | publish/ 176 | 177 | # Publish Web Output 178 | *.[Pp]ublish.xml 179 | *.azurePubxml 180 | # Note: Comment the next line if you want to checkin your web deploy settings, 181 | # but database connection strings (with potential passwords) will be unencrypted 182 | *.pubxml 183 | *.publishproj 184 | 185 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 186 | # checkin your Azure Web App publish settings, but sensitive information contained 187 | # in these scripts will be unencrypted 188 | PublishScripts/ 189 | 190 | # NuGet Packages 191 | *.nupkg 192 | # The packages folder can be ignored because of Package Restore 193 | **/[Pp]ackages/* 194 | # except build/, which is used as an MSBuild target. 195 | !**/[Pp]ackages/build/ 196 | # Uncomment if necessary however generally it will be regenerated when needed 197 | #!**/[Pp]ackages/repositories.config 198 | # NuGet v3's project.json files produces more ignorable files 199 | *.nuget.props 200 | *.nuget.targets 201 | 202 | # Microsoft Azure Build Output 203 | csx/ 204 | *.build.csdef 205 | 206 | # Microsoft Azure Emulator 207 | ecf/ 208 | rcf/ 209 | 210 | # Windows Store app package directories and files 211 | AppPackages/ 212 | BundleArtifacts/ 213 | Package.StoreAssociation.xml 214 | _pkginfo.txt 215 | *.appx 216 | 217 | # Visual Studio cache files 218 | # files ending in .cache can be ignored 219 | *.[Cc]ache 220 | # but keep track of directories ending in .cache 221 | !?*.[Cc]ache/ 222 | 223 | # Others 224 | ClientBin/ 225 | ~$* 226 | *~ 227 | *.dbmdl 228 | *.dbproj.schemaview 229 | *.jfm 230 | *.pfx 231 | *.publishsettings 232 | orleans.codegen.cs 233 | 234 | # Including strong name files can present a security risk 235 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 236 | #*.snk 237 | 238 | # Since there are multiple workflows, uncomment next line to ignore bower_components 239 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 240 | #bower_components/ 241 | # ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true 242 | **/wwwroot/lib/ 243 | 244 | # RIA/Silverlight projects 245 | Generated_Code/ 246 | 247 | # Backup & report files from converting an old project file 248 | # to a newer Visual Studio version. Backup files are not needed, 249 | # because we have git ;-) 250 | _UpgradeReport_Files/ 251 | Backup*/ 252 | UpgradeLog*.XML 253 | UpgradeLog*.htm 254 | ServiceFabricBackup/ 255 | *.rptproj.bak 256 | 257 | # SQL Server files 258 | *.mdf 259 | *.ldf 260 | *.ndf 261 | 262 | # Business Intelligence projects 263 | *.rdl.data 264 | *.bim.layout 265 | *.bim_*.settings 266 | *.rptproj.rsuser 267 | *- Backup*.rdl 268 | 269 | # Microsoft Fakes 270 | FakesAssemblies/ 271 | 272 | # GhostDoc plugin setting file 273 | *.GhostDoc.xml 274 | 275 | # Node.js Tools for Visual Studio 276 | .ntvs_analysis.dat 277 | node_modules/ 278 | 279 | # Visual Studio 6 build log 280 | *.plg 281 | 282 | # Visual Studio 6 workspace options file 283 | *.opt 284 | 285 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 286 | *.vbw 287 | 288 | # Visual Studio LightSwitch build output 289 | **/*.HTMLClient/GeneratedArtifacts 290 | **/*.DesktopClient/GeneratedArtifacts 291 | **/*.DesktopClient/ModelManifest.xml 292 | **/*.Server/GeneratedArtifacts 293 | **/*.Server/ModelManifest.xml 294 | _Pvt_Extensions 295 | 296 | # Paket dependency manager 297 | .paket/paket.exe 298 | paket-files/ 299 | 300 | # FAKE - F# Make 301 | .fake/ 302 | 303 | # JetBrains Rider 304 | .idea/ 305 | *.sln.iml 306 | 307 | # CodeRush personal settings 308 | .cr/personal 309 | 310 | # Python Tools for Visual Studio (PTVS) 311 | __pycache__/ 312 | *.pyc 313 | 314 | # Cake - Uncomment if you are using it 315 | # tools/** 316 | # !tools/packages.config 317 | 318 | # Tabs Studio 319 | *.tss 320 | 321 | # Telerik's JustMock configuration file 322 | *.jmconfig 323 | 324 | # BizTalk build output 325 | *.btp.cs 326 | *.btm.cs 327 | *.odx.cs 328 | *.xsd.cs 329 | 330 | # OpenCover UI analysis results 331 | OpenCover/ 332 | 333 | # Azure Stream Analytics local run output 334 | ASALocalRun/ 335 | 336 | # MSBuild Binary and Structured Log 337 | *.binlog 338 | 339 | # NVidia Nsight GPU debugger configuration file 340 | *.nvuser 341 | 342 | # MFractors (Xamarin productivity tool) working folder 343 | .mfractor/ 344 | 345 | # Local History for Visual Studio 346 | .localhistory/ 347 | 348 | # BeatPulse healthcheck temp database 349 | healthchecksdb 350 | 351 | # End of https://www.gitignore.io/api/visualstudio 352 | -------------------------------------------------------------------------------- /rust/src/data_structures/avl_tree.rs: -------------------------------------------------------------------------------- 1 | use std::{cmp::max, mem, ops::Not, ptr::NonNull}; 2 | 3 | #[derive(Clone, Copy)] 4 | enum Side { 5 | Left, 6 | Right, 7 | } 8 | 9 | #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] 10 | pub struct TreeNode { 11 | pub value: T, 12 | pub left: Option>>, 13 | pub right: Option>>, 14 | height: usize 15 | } 16 | 17 | #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] 18 | pub struct AvlTree { 19 | pub root: Option>>, 20 | pub length: usize 21 | } 22 | 23 | impl Not for Side { 24 | type Output = Side; 25 | 26 | fn not(self) -> Self::Output { 27 | match self { 28 | Side::Left => Side::Right, 29 | Side::Right => Side::Left, 30 | } 31 | } 32 | } 33 | 34 | impl TreeNode { 35 | fn new(value: T) -> Self { 36 | TreeNode { 37 | value, 38 | left: None, 39 | right: None, 40 | height: 1 41 | } 42 | } 43 | 44 | fn child(&mut self, side: Side) -> &mut Option>> { 45 | match side { 46 | Side::Left => &mut self.left, 47 | Side::Right => &mut self.right, 48 | } 49 | } 50 | 51 | fn height(&mut self, side: Side) -> usize { 52 | self.child(side) 53 | .as_ref() 54 | .map_or(0, |n| { 55 | unsafe { 56 | (*n.as_ptr()).height 57 | } 58 | }) 59 | } 60 | 61 | fn balance_factor(&mut self) -> i8 { 62 | let (left, right) = (self.height(Side::Left), self.height(Side::Right)); 63 | if left > right { 64 | (left - right) as i8 65 | } else { 66 | -((right - left) as i8) 67 | } 68 | } 69 | 70 | fn update_height(&mut self) { 71 | self.height = 1 + max(self.height(Side::Left), self.height(Side::Right)); 72 | } 73 | } 74 | 75 | impl AvlTree { 76 | pub fn new() -> Self { 77 | AvlTree { 78 | root: None, 79 | length: 0 80 | } 81 | } 82 | 83 | pub fn len(&self) -> usize { 84 | self.length 85 | } 86 | 87 | pub fn is_empty(&self) -> bool { 88 | self.length == 0 89 | } 90 | 91 | pub fn insert(&mut self, value: T) -> bool { 92 | let mut inserted: bool = true; 93 | if let Some(mut root) = self.root { 94 | unsafe { 95 | inserted = insert_node(&mut root, value); 96 | } 97 | } else { 98 | let root_box = Box::new(TreeNode::::new(value)); 99 | let root_ptr = NonNull::new(Box::into_raw(root_box)); 100 | self.root = root_ptr; 101 | } 102 | 103 | if inserted { 104 | self.length += 1; 105 | } 106 | 107 | inserted 108 | } 109 | 110 | pub fn delete(&mut self, value: T) { 111 | if let Some(mut root) = self.root { 112 | unsafe { 113 | self.root = delete_node(&mut root, value); 114 | self.length -= 1; 115 | } 116 | } 117 | } 118 | } 119 | 120 | 121 | unsafe fn insert_node(node: &mut NonNull>, value: T) -> bool { 122 | let node_ptr = node.as_mut(); 123 | if node_ptr.value == value { 124 | return false; // Value already exists in the tree 125 | } 126 | 127 | let target_node = if value < node_ptr.value { 128 | &mut node_ptr.left 129 | } else { 130 | &mut node_ptr.right 131 | }; 132 | 133 | let inserted = match target_node { 134 | Some(ptr) => { 135 | insert_node(ptr, value) 136 | }, 137 | None => { 138 | let node_box = Box::new(TreeNode::::new(value)); 139 | let node_ptr = NonNull::new(Box::into_raw(node_box)); 140 | *target_node = node_ptr; 141 | true 142 | }, 143 | }; 144 | 145 | if inserted { 146 | rebalance(node); 147 | } 148 | inserted 149 | } 150 | 151 | 152 | unsafe fn delete_node(node: &mut NonNull>, value: T) -> Option>> { 153 | let tree_node = &mut *node.as_ptr(); 154 | 155 | if value < tree_node.value { 156 | if let Some(mut left_node) = tree_node.left { 157 | tree_node.left = delete_node(&mut left_node, value); 158 | } 159 | } else if value > tree_node.value { 160 | if let Some(mut right_node) = tree_node.right { 161 | tree_node.right = delete_node(&mut right_node, value); 162 | } 163 | } else { 164 | if tree_node.left.is_none() { 165 | return tree_node.right; 166 | } else if tree_node.right.is_none() { 167 | return tree_node.left; 168 | } 169 | 170 | let mut successor = min_value_node(tree_node.right.unwrap()); 171 | tree_node.value = (*successor.as_ptr()).value; 172 | tree_node.right = delete_node(&mut successor, tree_node.value); 173 | } 174 | 175 | rebalance(node); 176 | Some(*node) 177 | } 178 | 179 | 180 | unsafe fn min_value_node(node: NonNull>) -> NonNull> { 181 | let mut current = node; 182 | while let Some(left) = (*current.as_ptr()).left { 183 | current = left; 184 | } 185 | current 186 | } 187 | 188 | 189 | unsafe fn rebalance(node: &mut NonNull>) { 190 | let node_ptr = node.as_mut(); 191 | node_ptr.update_height(); 192 | 193 | let side = match node_ptr.balance_factor() { 194 | 2 => Side::Left, 195 | -2 => Side::Right, 196 | _ => return, 197 | }; 198 | 199 | match node_ptr.child(side) { 200 | Some(subtree) => { 201 | if let (Side::Left, -1) | (Side::Right, 1) = (side, (subtree.as_mut()).balance_factor()) { 202 | rotate(subtree, side); 203 | } 204 | rotate(node, !side); 205 | }, 206 | None => return 207 | } 208 | } 209 | 210 | 211 | unsafe fn rotate(node: &mut NonNull>, side: Side) { 212 | let node_ptr = node.as_mut(); 213 | let mut subtree = node_ptr.child(!side).take().unwrap(); 214 | *node_ptr.child(!side) = (subtree.as_mut()).child(side).take(); 215 | node_ptr.update_height(); 216 | 217 | mem::swap(node_ptr, subtree.as_mut()); 218 | 219 | *node_ptr.child(side) = Some(subtree); 220 | node_ptr.update_height(); 221 | } 222 | 223 | 224 | #[cfg(test)] 225 | mod tests { 226 | use super::*; 227 | 228 | #[test] 229 | fn empty_tree() { 230 | let tree: AvlTree = AvlTree::new(); 231 | assert!(tree.is_empty()); 232 | assert_eq!(tree.len(), 0); 233 | } 234 | 235 | #[test] 236 | fn single_element() { 237 | let mut tree = AvlTree::new(); 238 | assert!(tree.insert(10)); 239 | assert!(!tree.is_empty()); 240 | assert_eq!(tree.len(), 1); 241 | } 242 | 243 | #[test] 244 | fn left_left_rotation() { 245 | let mut tree = AvlTree::new(); 246 | tree.insert(30); 247 | tree.insert(20); 248 | 249 | unsafe { 250 | assert_eq!(tree.root.unwrap().as_ref().value, 30); 251 | } 252 | 253 | tree.insert(10); 254 | 255 | unsafe { 256 | let root = tree.root.unwrap(); 257 | assert_eq!(root.as_ref().value, 20); 258 | assert_eq!(root.as_ref().left.unwrap().as_ref().value, 10); 259 | assert_eq!(root.as_ref().right.unwrap().as_ref().value, 30); 260 | } 261 | } 262 | 263 | #[test] 264 | fn left_right_rotation() { 265 | let mut tree = AvlTree::new(); 266 | tree.insert(30); 267 | tree.insert(20); 268 | 269 | unsafe { 270 | assert_eq!(tree.root.unwrap().as_ref().value, 30); 271 | } 272 | 273 | tree.insert(25); 274 | 275 | unsafe { 276 | let root = tree.root.unwrap(); 277 | assert_eq!(root.as_ref().value, 25); 278 | assert_eq!(root.as_ref().left.unwrap().as_ref().value, 20); 279 | assert_eq!(root.as_ref().right.unwrap().as_ref().value, 30); 280 | } 281 | } 282 | 283 | #[test] 284 | fn right_right_rotation() { 285 | let mut tree = AvlTree::new(); 286 | tree.insert(10); 287 | tree.insert(20); 288 | 289 | unsafe { 290 | assert_eq!(tree.root.unwrap().as_ref().value, 10); 291 | } 292 | 293 | tree.insert(30); 294 | 295 | unsafe { 296 | let root = tree.root.unwrap(); 297 | assert_eq!(root.as_ref().value, 20); 298 | assert_eq!(root.as_ref().left.unwrap().as_ref().value, 10); 299 | assert_eq!(root.as_ref().right.unwrap().as_ref().value, 30); 300 | } 301 | } 302 | 303 | #[test] 304 | fn right_left_rotation() { 305 | let mut tree = AvlTree::new(); 306 | tree.insert(10); 307 | tree.insert(20); 308 | 309 | unsafe { 310 | assert_eq!(tree.root.unwrap().as_ref().value, 10); 311 | } 312 | 313 | tree.insert(15); 314 | 315 | unsafe { 316 | let root = tree.root.unwrap(); 317 | assert_eq!(root.as_ref().value, 15); 318 | assert_eq!(root.as_ref().left.unwrap().as_ref().value, 10); 319 | assert_eq!(root.as_ref().right.unwrap().as_ref().value, 20); 320 | } 321 | } 322 | 323 | #[test] 324 | fn delete_node() { 325 | let mut tree = AvlTree::new(); 326 | tree.insert(20); 327 | tree.insert(10); 328 | tree.insert(30); 329 | tree.insert(40); 330 | 331 | unsafe { 332 | assert_eq!(tree.root.unwrap().as_ref().value, 20); 333 | } 334 | 335 | tree.delete(10); 336 | 337 | unsafe { 338 | let root = tree.root.unwrap(); 339 | assert_eq!(root.as_ref().value, 30); 340 | assert_eq!(root.as_ref().left.unwrap().as_ref().value, 20); 341 | assert_eq!(root.as_ref().right.unwrap().as_ref().value, 40); 342 | } 343 | } 344 | } 345 | --------------------------------------------------------------------------------