forked from vedant1771/Hactoberfest2021
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Tarjan.cpp
166 lines (151 loc) · 4.26 KB
/
Tarjan.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <stddef.h>
#include <stdlib.h>
#include <stdbool.h>
#ifndef min
#define min(x, y) ((x)<(y) ? (x) : (y))
#endif
struct edge {
void *from;
void *to;
};
struct components {
int nnodes;
void **nodes;
struct components *next;
};
struct node {
int index;
int lowlink;
bool onStack;
void *data;
};
struct tjstate {
int index;
int sp;
int nedges;
struct edge *edges;
struct node **stack;
struct components *head;
struct components *tail;
};
static int nodecmp(const void *l, const void *r)
{
return (ptrdiff_t)l -(ptrdiff_t)((struct node *)r)->data;
}
static int strongconnect(struct node *v, struct tjstate *tj)
{
struct node *w;
/* Set the depth index for v to the smallest unused index */
v->index = tj->index;
v->lowlink = tj->index;
tj->index++;
tj->stack[tj->sp] = v;
tj->sp++;
v->onStack = true;
for (int i = 0; i<tj->nedges; i++) {
/* Only consider nodes reachable from v */
if (tj->edges[i].from != v) {
continue;
}
w = tj->edges[i].to;
/* Successor w has not yet been visited; recurse on it */
if (w->index == -1) {
int r = strongconnect(w, tj);
if (r != 0)
return r;
v->lowlink = min(v->lowlink, w->lowlink);
/* Successor w is in stack S and hence in the current SCC */
} else if (w->onStack) {
v->lowlink = min(v->lowlink, w->index);
}
}
/* If v is a root node, pop the stack and generate an SCC */
if (v->lowlink == v->index) {
struct components *ng = malloc(sizeof(struct components));
if (ng == NULL) {
return 2;
}
if (tj->tail == NULL) {
tj->head = ng;
} else {
tj->tail->next = ng;
}
tj->tail = ng;
ng->next = NULL;
ng->nnodes = 0;
do {
tj->sp--;
w = tj->stack[tj->sp];
w->onStack = false;
ng->nnodes++;
} while (w != v);
ng->nodes = malloc(ng->nnodes*sizeof(void *));
if (ng == NULL) {
return 2;
}
for (int i = 0; i<ng->nnodes; i++) {
ng->nodes[i] = tj->stack[tj->sp+i]->data;
}
}
return 0;
}
static int ptrcmp(const void *l, const void *r)
{
return (ptrdiff_t)((struct node *)l)->data
- (ptrdiff_t)((struct node *)r)->data;
}
/**
* Calculate the strongly connected components using Tarjan's algorithm:
* en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
*
* Returns NULL when there are invalid edges and sets the error to:
* 1 if there was a malformed edge
* 2 if malloc failed
*
* @param number of nodes
* @param data of the nodes (assumed to be unique)
* @param number of edges
* @param data of edges
* @param pointer to error code
*/
struct components *tarjans(
int nnodes, void *nodedata[],
int nedges, struct edge *edgedata[],
int *error)
{
struct node nodes[nnodes];
struct edge edges[nedges];
struct node *stack[nnodes];
struct node *from, *to;
struct tjstate tj = {0, 0, nedges, edges, stack, NULL, .tail=NULL};
// Populate the nodes
for (int i = 0; i<nnodes; i++) {
nodes[i] = (struct node){-1, -1, false, nodedata[i]};
}
qsort(nodes, nnodes, sizeof(struct node), ptrcmp);
// Populate the edges
for (int i = 0; i<nedges; i++) {
from = bsearch(edgedata[i]->from, nodes, nnodes,
sizeof(struct node), nodecmp);
if (from == NULL) {
*error = 1;
return NULL;
}
to = bsearch(edgedata[i]->to, nodes, nnodes,
sizeof(struct node), nodecmp);
if (to == NULL) {
*error = 1;
return NULL;
}
edges[i] = (struct edge){.from=from, .to=to};
}
//Tarjan's
for (int i = 0; i < nnodes; i++) {
if (nodes[i].index == -1) {
*error = strongconnect(&nodes[i], &tj);
if (*error != 0)
return NULL;
}
}
return tj.head;
}