Skip to content

Commit 92fa587

Browse files
authored
Implement AllPathsBetween (#137)
1 parent 9144c0b commit 92fa587

File tree

4 files changed

+477
-0
lines changed

4 files changed

+477
-0
lines changed

collection.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,56 @@ func (m *minHeap[T]) Pop() interface{} {
106106

107107
return item
108108
}
109+
110+
type stack[T any] interface {
111+
push(T)
112+
pop() (T, error)
113+
top() (T, error)
114+
isEmpty() bool
115+
// forEach iterate the stack from bottom to top
116+
forEach(func(T))
117+
}
118+
119+
func newStack[T any]() stack[T] {
120+
return &stackImpl[T]{
121+
elements: make([]T, 0),
122+
}
123+
}
124+
125+
type stackImpl[T any] struct {
126+
elements []T
127+
}
128+
129+
func (s *stackImpl[T]) push(t T) {
130+
s.elements = append(s.elements, t)
131+
}
132+
133+
func (s *stackImpl[T]) pop() (T, error) {
134+
e, err := s.top()
135+
if err != nil {
136+
var defaultValue T
137+
return defaultValue, err
138+
}
139+
140+
s.elements = s.elements[:len(s.elements)-1]
141+
return e, nil
142+
}
143+
144+
func (s *stackImpl[T]) top() (T, error) {
145+
if s.isEmpty() {
146+
var defaultValue T
147+
return defaultValue, errors.New("no element in stack")
148+
}
149+
150+
return s.elements[len(s.elements)-1], nil
151+
}
152+
153+
func (s *stackImpl[T]) isEmpty() bool {
154+
return len(s.elements) == 0
155+
}
156+
157+
func (s *stackImpl[T]) forEach(f func(T)) {
158+
for _, e := range s.elements {
159+
f(e)
160+
}
161+
}

collection_test.go

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package graph
22

33
import (
4+
"reflect"
45
"testing"
56
)
67

@@ -222,3 +223,167 @@ func TestPriorityQueue_Len(t *testing.T) {
222223
}
223224
}
224225
}
226+
227+
func Test_stackImpl_push(t *testing.T) {
228+
type args[T any] struct {
229+
t T
230+
}
231+
type testCase[T any] struct {
232+
name string
233+
s stackImpl[T]
234+
args args[T]
235+
}
236+
tests := []testCase[int]{
237+
{
238+
"push 1",
239+
stackImpl[int]{
240+
elements: make([]int, 0),
241+
},
242+
args[int]{
243+
t: 1,
244+
},
245+
},
246+
}
247+
for _, tt := range tests {
248+
t.Run(tt.name, func(t *testing.T) {
249+
tt.s.push(tt.args.t)
250+
})
251+
}
252+
}
253+
254+
func Test_stackImpl_pop(t *testing.T) {
255+
type testCase[T any] struct {
256+
name string
257+
s stackImpl[T]
258+
want T
259+
wantErr bool
260+
}
261+
tests := []testCase[int]{
262+
{
263+
"pop element",
264+
stackImpl[int]{
265+
elements: []int{1},
266+
},
267+
1,
268+
false,
269+
},
270+
{
271+
"pop element from empty stack",
272+
stackImpl[int]{
273+
elements: []int{},
274+
},
275+
0,
276+
true,
277+
},
278+
}
279+
for _, tt := range tests {
280+
t.Run(tt.name, func(t *testing.T) {
281+
got, err := tt.s.pop()
282+
if (err != nil) != tt.wantErr {
283+
t.Errorf("pop() error = %v, wantErr %v", err, tt.wantErr)
284+
return
285+
}
286+
if !reflect.DeepEqual(got, tt.want) {
287+
t.Errorf("pop() got = %v, want %v", got, tt.want)
288+
}
289+
})
290+
}
291+
}
292+
293+
func Test_stackImpl_top(t *testing.T) {
294+
type testCase[T any] struct {
295+
name string
296+
s stackImpl[T]
297+
want T
298+
wantErr bool
299+
}
300+
tests := []testCase[int]{
301+
{
302+
"top element",
303+
stackImpl[int]{
304+
elements: []int{1},
305+
},
306+
1,
307+
false,
308+
},
309+
{
310+
"top element of empty stack",
311+
stackImpl[int]{
312+
elements: []int{},
313+
},
314+
0,
315+
true,
316+
},
317+
}
318+
for _, tt := range tests {
319+
t.Run(tt.name, func(t *testing.T) {
320+
got, err := tt.s.top()
321+
if (err != nil) != tt.wantErr {
322+
t.Errorf("top() error = %v, wantErr %v", err, tt.wantErr)
323+
return
324+
}
325+
if !reflect.DeepEqual(got, tt.want) {
326+
t.Errorf("top() got = %v, want %v", got, tt.want)
327+
}
328+
})
329+
}
330+
}
331+
332+
func Test_stackImpl_isEmpty(t *testing.T) {
333+
type testCase[T any] struct {
334+
name string
335+
s stackImpl[T]
336+
want bool
337+
}
338+
tests := []testCase[int]{
339+
{
340+
"empty",
341+
stackImpl[int]{
342+
elements: []int{},
343+
},
344+
true,
345+
},
346+
{
347+
"not empty",
348+
stackImpl[int]{
349+
elements: []int{1},
350+
},
351+
false,
352+
},
353+
}
354+
for _, tt := range tests {
355+
t.Run(tt.name, func(t *testing.T) {
356+
if got := tt.s.isEmpty(); got != tt.want {
357+
t.Errorf("isEmpty() = %v, want %v", got, tt.want)
358+
}
359+
})
360+
}
361+
}
362+
363+
func Test_stackImpl_forEach(t *testing.T) {
364+
type args[T any] struct {
365+
f func(T)
366+
}
367+
type testCase[T any] struct {
368+
name string
369+
s stackImpl[T]
370+
args args[T]
371+
}
372+
tests := []testCase[int]{
373+
{
374+
name: "forEach",
375+
s: stackImpl[int]{
376+
elements: []int{1, 2, 3, 4, 5, 6},
377+
},
378+
args: args[int]{
379+
f: func(i int) {
380+
},
381+
},
382+
},
383+
}
384+
for _, tt := range tests {
385+
t.Run(tt.name, func(t *testing.T) {
386+
tt.s.forEach(tt.args.f)
387+
})
388+
}
389+
}

paths.go

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,104 @@ func findSCC[K comparable](vertexHash K, state *sccState[K]) {
232232
state.components = append(state.components, component)
233233
}
234234
}
235+
236+
// AllPathsBetween list all paths from start to end.
237+
func AllPathsBetween[K comparable, T any](g Graph[K, T], start, end K) ([][]K, error) {
238+
adjacencyMap, err := g.AdjacencyMap()
239+
if err != nil {
240+
return nil, err
241+
}
242+
243+
mainStack, viceStack := newStack[K](), newStack[stack[K]]()
244+
245+
checkEmpty := func() error {
246+
if mainStack.isEmpty() || viceStack.isEmpty() {
247+
return errors.New("empty stack")
248+
}
249+
return nil
250+
}
251+
252+
buildLayer := func(element K) {
253+
mainStack.push(element)
254+
255+
newElements := newStack[K]()
256+
for e := range adjacencyMap[element] {
257+
var contains bool
258+
mainStack.forEach(func(k K) {
259+
if e == k {
260+
contains = true
261+
}
262+
})
263+
if contains {
264+
continue
265+
}
266+
newElements.push(e)
267+
}
268+
viceStack.push(newElements)
269+
}
270+
271+
buildStack := func() error {
272+
if err = checkEmpty(); err != nil {
273+
return errors.New("empty stack")
274+
}
275+
276+
elements, _ := viceStack.top()
277+
for !elements.isEmpty() {
278+
element, _ := elements.pop()
279+
buildLayer(element)
280+
elements, _ = viceStack.top()
281+
}
282+
283+
return nil
284+
}
285+
286+
removeLayer := func() error {
287+
if err = checkEmpty(); err != nil {
288+
return errors.New("empty stack")
289+
}
290+
291+
e, _ := viceStack.top()
292+
if !e.isEmpty() {
293+
return errors.New("the top element of vice-stack is not empty")
294+
}
295+
296+
_, _ = mainStack.pop()
297+
_, _ = viceStack.pop()
298+
299+
return nil
300+
}
301+
302+
// init the first layer
303+
304+
buildLayer(start)
305+
306+
// loop
307+
308+
allPaths := make([][]K, 0)
309+
310+
for !mainStack.isEmpty() {
311+
v, _ := mainStack.top()
312+
adjs, _ := viceStack.top()
313+
314+
if adjs.isEmpty() {
315+
if v == end {
316+
path := make([]K, 0)
317+
mainStack.forEach(func(k K) {
318+
path = append(path, k)
319+
})
320+
allPaths = append(allPaths, path)
321+
}
322+
323+
err = removeLayer()
324+
if err != nil {
325+
return nil, err
326+
}
327+
} else {
328+
if err = buildStack(); err != nil {
329+
return nil, err
330+
}
331+
}
332+
}
333+
334+
return allPaths, nil
335+
}

0 commit comments

Comments
 (0)