summaryrefslogtreecommitdiff
path: root/src/shortest/shortest.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shortest/shortest.c')
-rw-r--r--src/shortest/shortest.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/src/shortest/shortest.c b/src/shortest/shortest.c
new file mode 100644
index 0000000..9ea9a1a
--- /dev/null
+++ b/src/shortest/shortest.c
@@ -0,0 +1,259 @@
+/**
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * (c) Vincenzo Nicosia 2009-2017 -- <v.nicosia@qmul.ac.uk>
+ *
+ * This file is part of NetBunch, a package for complex network
+ * analysis and modelling. For more information please visit:
+ *
+ * http://www.complex-networks.net/
+ *
+ * If you use this software, please add a reference to
+ *
+ * V. Latora, V. Nicosia, G. Russo
+ * "Complex Networks: Principles, Methods and Applications"
+ * Cambridge University Press (2017)
+ * ISBN: 9781107103184
+ *
+ ***********************************************************************
+ *
+ * This program computes the distance from a given node to all the
+ * other nodes of an undirected graph, using the Breadth-First Search
+ * algorithm.
+ *
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "utils.h"
+
+
+void usage(char *argv[]){
+ printf("********************************************************************\n"
+ "** **\n"
+ "** -*- shortest -*- **\n"
+ "** **\n"
+ "** Compute the distance from the given 'node' to all the other **\n"
+ "** nodes of an undirected graph. The first parameter 'graph_in' **\n"
+ "** is the name of the file containing the edge list of the **\n"
+ "** graph. The second parameter 'node' is the label of the node **\n"
+ "** for which we want to compute the distances to all the other **\n"
+ "** nodes. **\n"
+ "** **\n"
+ "** If 'graph_in' is equal to '-' (dash), read the edge list **\n"
+ "** from standard input (STDIN) **\n"
+ "** **\n"
+ "** The program prints on output a row of values: **\n"
+ "** **\n"
+ "** d0 d1 d2 d3 d4...... **\n"
+ "** **\n"
+ "** where d0 is the distance between 'node' and '0', 'd1' is the **\n"
+ "** distance between 'node' and '1', and so on. **\n"
+ "** **\n"
+ "** If the third parameter is equal to 'SHOW', the program will **\n"
+ "** dump all the shortest paths from 'node' to all the other **\n"
+ "** nodes on the standard error (STDERR). **\n"
+ "** **\n"
+ "********************************************************************\n"
+ " This is Free Software - You can use and distribute it under \n"
+ " the terms of the GNU General Public License, version 3 or later\n\n"
+ " Please visit http://www.complex-networks.net for more information\n\n"
+ " (c) Vincenzo Nicosia 2009-2017 (v.nicosia@qmul.ac.uk)\n"
+ "********************************************************************\n\n"
+ );
+ printf("Usage: %s <graph_in> <node> [SHOW]\n\n" , argv[0]);
+}
+
+
+/*
+ * Add 'k' to a list of predecessors
+ */
+
+void add_predecessor(unsigned int **pred, unsigned int k){
+
+ (*pred)[0] += 1;
+ *pred = realloc(*pred, ((*pred)[0] + 1) * sizeof(unsigned int));
+ (*pred)[ (*pred)[0] ] = k;
+}
+
+
+
+/*
+ *
+ * This is the implementation of the Breadth-First Search algorithm
+ * (BFS) to compute the shortest paths, and the distances, between a
+ * given node 'i' and all the other nodes of a graph.
+ *
+ */
+unsigned int** compute_shortest_paths(unsigned int N, unsigned int *J_slap, unsigned int *r_slap,
+ unsigned int i, unsigned int **dist){
+
+ unsigned int j, k, cur_node;
+ unsigned int *marked, **preds;
+ unsigned int d;
+ unsigned int n, nd, ndp;
+
+ *dist = malloc(N * sizeof(unsigned int));
+ marked = malloc(N * sizeof(unsigned int));
+ preds = malloc(N * sizeof(unsigned int *));
+
+ for(j=0; j<N; j ++){
+ (*dist)[j] = N;
+ preds[j] = malloc(sizeof(unsigned int));
+ preds[j][0] = 0; /* The list of predecessors is empty! */
+ }
+ (*dist)[i] = 0;
+ marked[0] = i;
+ d = 0;
+ n = 0;
+ nd = 1;
+ ndp = 0;
+ while (d<N && nd > 0){
+ for(k = n; k< n+nd; k ++){
+ cur_node = marked[k];
+ for (j=r_slap[cur_node]; j<r_slap[cur_node +1] ; j++){
+ if ( (*dist)[ J_slap[j] ] == d+1){
+ add_predecessor((unsigned int **)(preds + J_slap[j]), cur_node);
+ }
+ if ( (*dist)[ J_slap[j] ] == N){
+ (*dist)[ J_slap[j] ] = d+1;
+ marked[n + nd + ndp] = J_slap[j];
+ add_predecessor(preds + J_slap[j], cur_node);
+ ndp +=1;
+ }
+ }
+
+ }
+ n = n + nd;
+ nd = ndp;
+ ndp = 0;
+ d += 1;
+ }
+ free(marked);
+ return preds;
+}
+
+/*
+ * Dump on output the distances between 'node' and all the other nodes
+ * of the graph
+ *
+ */
+
+void dump_dists(unsigned int *dists, unsigned int N){
+
+ unsigned int i;
+ for (i=0; i<N; i++){
+ printf("%d ", dists[i]);
+ }
+ printf("\n");
+}
+
+
+/*
+ * recursively show the shortest paths from 'node' to all the other
+ * nodes ot the graph
+ *
+ */
+void recursive_show_paths(unsigned int **preds, unsigned int N, unsigned int k,
+ char *buff, int pos, FILE *fileout){
+
+ int i;
+ char lbuff[10];
+
+
+ if (preds[k][0] == 0){
+ sprintf(buff + pos, "%5d\n", k);
+ fprintf(fileout, "%s", buff );
+ return;
+ }
+
+ sprintf(lbuff, "%5d ", k);
+ strncpy(buff + pos, lbuff, 7);
+ for(i=1; i<= preds[k][0]; i ++){
+ recursive_show_paths(preds, N, preds[k][i], buff, pos + 7, fileout);
+ }
+ return;
+}
+
+/*
+ *
+ * This function calls recursive_show_paths() for each of the nodes of
+ * the graph, to dump the shortest paths between 'node' and all the
+ * other nodes of the graph.
+ *
+ */
+
+void show_paths(unsigned int **preds, unsigned int N, FILE *fileout){
+
+ int j;
+ char buff[256];
+
+ for (j = 0; j<N; j++){
+ if (preds[j][0] > 0)
+ recursive_show_paths(preds, N, j, buff, 0, fileout);
+ }
+
+}
+
+int main(int argc, char *argv[]){
+
+ unsigned int *J_slap=NULL, *r_slap=NULL;
+ unsigned int K, N, i;
+ unsigned int **preds, *dists=NULL;
+ FILE *filein;
+
+ if (argc < 3){
+ usage(argv);
+ exit(1);
+ }
+
+ if (!strcmp(argv[1], "-")){
+ /* take the input from STDIN */
+ filein = stdin;
+ }
+ else {
+ filein = openfile_or_exit(argv[1], "r", 2);
+ }
+
+ read_slap(filein, &K, &N, &J_slap, &r_slap);
+ i = atoi(argv[2]);
+ if (i>N){
+ printf("Node id '%d' does not exist!!!! Exiting....\n", i);
+ exit(3);
+ }
+
+ fclose(filein);
+
+ preds = compute_shortest_paths(N, J_slap, r_slap, i, &dists);
+ dump_dists(dists, N);
+ /* check if we should dump the shortest paths on stderr */
+ if (argc > 3 && !strcmp(argv[3], "SHOW")){
+ show_paths(preds, N, stderr);
+ }
+
+ /* Cleanup */
+
+ for (i=0; i<N; i++){
+ free(preds[i]);
+ }
+ free(preds);
+ free(dists);
+ free(J_slap);
+ free(r_slap);
+}