diff --git a/DIRECTORY.md b/DIRECTORY.md index d808756..04e79f9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -5,3 +5,7 @@ ## Sorts * [Quicksort](https://github.com/TheAlgorithms/OCaml/blob/master/Sorts/quicksort.ml) + +## Graphs + * [Prims Algorithm](./Graphs/prims.ml) + * [Dijkstras Algorithm](./Graphs/dijkstra.ml) diff --git a/Graphs/dijkstra.ml b/Graphs/dijkstra.ml new file mode 100644 index 0000000..6938203 --- /dev/null +++ b/Graphs/dijkstra.ml @@ -0,0 +1,89 @@ +(* + #Algorithm + #1) Create a set sptSet (shortest path tree set) that keeps track of vertices included in the shortest-path tree, + # i.e., whose minimum distance from the source is calculated and finalized. + # Initially, this set is empty. + #2) Assign a distance value to all vertices in the input graph. Initialize all distance values as INFINITE. + # Assign distance value as 0 for the source vertex so that it is picked first. + #3) While sptSet doesn’t include all vertices + #….a) Pick a vertex u which is not there in sptSet and has a minimum distance value. + #….b) Include u to sptSet. + #….c) Update distance value of all adjacent vertices of u. + # To update the distance values,iterate through all adjacent vertices. + # For every adjacent vertex v, if the sum of distance value of u (from source) and weight of edge u-v, + # is less than the distance value of v, then update the distance value of v. + *) + +(* Implementation of Dijkstras shortest path alorithm returning the shortest distances between given node and all other nodes in the given graph *) +(* author: https://github.com/maharajamihir *) + +type graph = (int * int) list + +let graphA = [ (1,2); (3,4); (1,3); (2,4)] +let graphB = [ (7, 1); (1, 6); (1, 2); (2, 3); (6 , 3); (4, 2); (2,5); (3, 5)] +let graphC = [ (1,2); (2,3); (4,3); (1,4); (1,3)] +let graphD = [(0,1); (0,7); (7,1); (1,2); (7,6); (7,8); (6,8); (8,2); (2,5); (6,5); (2,3); (3,4); (3,5); (5,4)] + + +let rec get_neighbors g node = + match g with + [] -> [] + | (a,b) :: ns -> + if a = node then + b :: get_neighbors ns node + else if b = node then + a :: get_neighbors ns node + else get_neighbors ns node + +let dijkstra edges node = + (*step one*) + let rec extract_nodes es = + match es with + [] -> [] + | (a,b) :: ess -> + if (List.filter(fun (x,y) -> x=a || x=b || y=a || y=b) ess) = [] + then + extract_nodes ess + else + a :: b :: extract_nodes ess + in + let all_nodes = List.sort (Int.compare) (extract_nodes edges) in + if List.mem node all_nodes = false then failwith "node not in graph" else + (* step two *) + let rec init_distances nodes n = + match nodes with + [] -> [] + | x :: xs -> + if + n = x + then + (n, 0) :: init_distances xs n + else + (x, Int.max_int) :: init_distances xs n in + let dists = init_distances all_nodes node in + (* step three *) + let rec get_distances sptSet queue distances = + let sorted = List.sort Int.compare sptSet in + if List.equal (fun a b -> a=b) all_nodes sorted then distances else + (* 3a *) + match queue with + [] -> List.sort_uniq (fun (a,_) (b,_)-> Int.compare a b) distances + | cur :: xs -> + if List.mem cur sptSet + then get_distances sptSet xs distances + (* 3b *) + else let set = cur :: sptSet in + (*3c*) + let neighbors = get_neighbors edges cur in + let rec update_distances ns dists q = + match ns with + [] -> dists, q + | neighbor :: nss -> + if (List.assoc cur dists) + 1 < (List.assoc neighbor dists) then + let new_dists = (neighbor, (List.assoc cur dists)+1) :: List.filter(fun (a,_) -> a<>neighbor) dists in + update_distances nss new_dists (neighbor :: q) + else + update_distances nss dists q in + let ds,q = update_distances neighbors distances queue in + get_distances set q ds in + get_distances [] [node] dists diff --git a/Graphs/prims.ml b/Graphs/prims.ml new file mode 100644 index 0000000..18e6d01 --- /dev/null +++ b/Graphs/prims.ml @@ -0,0 +1,40 @@ +type graph = (int * float * int) list + +(* Implementation of Prims algorithm to find the minimal spanning tree of a graph in Ocaml *) +(* This was implemented for an uni assignment *) +(* Minimal spanning tree: https://en.wikipedia.org/wiki/Minimum_spanning_tree *) +(* Prims Algorithm: https://en.wikipedia.org/wiki/Prim%27s_algorithm *) + + +(*Some test Graphs to check for testing*) +let graphA = [ (1,1.,2); (3,1.,4); (1,10.,3); (2,10.,4)] +let graphB = [ (7, 0.5, 1); (1, 1.5, 6); (1, 2.4, 2); (2, 3.5, 3); (6, 1.2 , 3); (4, 2.4, 2); (2,1.2,5); (3, 5.4, 5)] +let graphC = [ (1,1.0, 2); (2,0.9,3); (4,1.2,3); (1,2.4, 4); (1,3.4,3)] +let graphD = [(0,4.,1); (0,8.,7); (7,11.,1); (1,8.,2); (7,1.,6); (7,7.,8); (6,6.,8); (8,2.,2); (2,4.,5); (6,2.,5); (2,7.,3); (3,9.,4); (3,14.,5); (5,10.,4)] + +let rec getpossibleedges visitednodes graph = + match graph with + [] -> [] + | (n1,w,n2) :: xs -> if List.mem n1 visitednodes || List.mem n2 visitednodes + then (n1,w,n2) :: getpossibleedges visitednodes xs + else getpossibleedges visitednodes xs + +let rec prims minst visitednodes notvisited = + let possibleedges = + List.sort(fun (_,f1,_) (_,f2,_) -> compare (f1) (f2)) (getpossibleedges visitednodes notvisited) in + let rec choosenode possible = match possible with + [] -> [] + | (a,w,b) :: xs -> + if List.mem a visitednodes && List.mem b visitednodes then choosenode xs else [(a,w,b)] in + let chosen = choosenode possibleedges in + match chosen with + [] -> minst + | [(a,w,b)] -> + let tree = minst @ [(a,w,b)] in + let visited = a :: b :: visitednodes in + prims tree visited notvisited + | _ -> failwith "Something went wrong" + +let mst edges = match edges with + [] -> [] + | (n1,_,_) :: _ -> prims [] [n1] edges