traverse

package
v0.10.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 5, 2026 License: Apache-2.0 Imports: 8 Imported by: 1

README

gograph - Traverse

Graph traversal is an important operation in computer science that involves visiting each node in a graph at least once. There are several graph traversal algorithms that are commonly used to explore graphs in different ways. The gograph/traverse package is a Go library that provides efficient implementation of five of these algorithms:

traverse.NewBreadthFirstIterator exploring a maze level by level
traverse.NewBreadthFirstIterator exploring a maze level by level. Run it step by step on gograph.dev.

All the traversal algorithms in the 'traverse' package are implemented the following iterator interface:

// Iterator represents a general purpose iterator for iterating over
// a sequence of graph's vertices. It provides methods for checking if
// there are more elements to be iterated over, getting the next element,
// iterating over all elements using a callback function, and resetting
// the iterator to its initial state.
type Iterator[T comparable] interface {
	// HasNext returns a boolean value indicating whether there are more
	// elements to be iterated over. It returns true if there are more
	// elements. Otherwise, returns false.
	HasNext() bool

	// Next returns the next element in the sequence being iterated over.
	// If there are no more elements, it returns nil. It also advances
	// the iterator to the next element.
	Next() *gograph.Vertex[T]

	// Iterate iterates over all elements in the sequence and calls the
	// provided callback function on each element. The callback function
	// takes a single argument of type *Vertex, representing the current
	// element being iterated over. It returns an error value, which is
	// returned by the Iterate method. If the callback function returns
	// an error, iteration is stopped and the error is returned.
	Iterate(func(v *gograph.Vertex[T]) error) error

	// Reset  resets the iterator to its initial state, allowing the
	// sequence to be iterated over again from the beginning.
	Reset()
}
Range over a traversal

Every traversal except the random walk also comes as a sequence for a range loop, and the standard helpers such as slices.Collect accept the sequences. BFS, BFSWithDepth, DFS and ClosestFirst do their work as the loop asks for the next vertex, so break ends the traversal there. Topological sorts the graph when it is called.

for v := range traverse.BFS(g, "A") {
	if v.Label() == target {
		break
	}
}
Function Yields
BFS(g, start) The vertices in the order of NewBreadthFirstIterator
BFSWithDepth(g, start) The same vertices, each with its number of edges from start
DFS(g, start) The vertices in the order of NewDepthFirstIterator
ClosestFirst(g, start) The vertices in the order of NewClosestFirstIterator, each with its distance from start
Topological(g) The vertices in topological order, with an error up front for a cycle or an undirected graph

A sequence from a start vertex yields nothing when start isn't in the graph. To get an error instead, check g.GetVertexByID(start) first, or use the iterator constructors, which return ErrVertexDoesNotExist. Each vertex is the graph's own vertex, and ranging over a sequence from a start vertex again runs the traversal again. Like the iterators, a sequence skips a vertex removed from the graph after it was queued. In the root package, gograph.Vertices(g) and gograph.Edges(g) range over all the vertices and edges of a graph without allocating.

Depth-first search events

DFSEvents(g, start) and DFSEventsAll(g) yield each step of a depth-first search as a DFSEvent, so an algorithm built on depth-first search is a loop over the events. DFSEventsAll starts a new search from each vertex not discovered yet, in the order of GetAllVertices.

Kind When
DiscoverVertex The search enters a vertex for the first time
FinishVertex Every vertex reachable from the vertex has been handled
TreeEdge An edge to an undiscovered vertex, which becomes its child
BackEdge An edge to a vertex still on the current path, which closes a cycle
ForwardEdge An edge to a finished descendant, in a directed graph
CrossEdge An edge to a finished vertex that isn't a descendant, in a directed graph
var order []string
for e := range traverse.DFSEventsAll(g) {
	if e.Kind == traverse.FinishVertex {
		order = append(order, e.Vertex.Label())
	}
}
slices.Reverse(order) // a topological order when g has no cycle

The neighbors of each vertex are explored in the order of Neighbors, and the events of each vertex nest inside those of its parent. In an undirected graph, each edge comes once, as a tree edge or as a back edge from the deeper vertex, so only those two kinds occur. A self-loop is a back edge. The search keeps its own stack, so the goroutine stack stays small on a path of 100,000 vertices. connectivity.FindCycle uses the first back edge to return the vertices of a cycle.

BFS

BFS iterator is a technique used to implement the Breadth-First Search (BFS) algorithm for traversing a graph or tree in a systematic way. The BFS iterator iteratively visits the vertices reachable from a given source vertex, moving outwards in levels. The iterator maintains a queue of vertices to be visited, and it visits each vertex only once.

One of the most common usages of BFS iterator is to find the shortest path between two vertices in an unweighted graph. It can also be used to perform level-order traversal of a binary tree or to find all the vertices at a given distance from a starting vertex. BFS iterator is also commonly used in graph algorithms, such as finding connected components, bipartite graphs, and cycle detection.

The time complexity of the BFS iterator algorithm is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because the algorithm visits each vertex and edge exactly once. The space complexity of BFS iterator is O(V), where V is the number of vertices in the graph. This is because the algorithm uses a queue to store the vertices to be visited. The maximum size of the queue is equal to the number of vertices at the maximum depth of the BFS traversal.

For example, on this undirected graph:

flowchart LR
    n0["A"]
    n1["B"]
    n2["C"]
    n3["D"]
    n4["E"]
    n5["F"]
    n0 --- n1
    n0 --- n3
    n1 --- n2
    n1 --- n4
    n2 --- n5
    n3 --- n4
    n4 --- n5

the BFS iterator that starts from A returns A, B, D, C, E, F. Run BFS step by step on gograph.dev, with the queue and the visited vertices at each step.

DFS

DFS iterator is a technique used to implement the Depth-First Search (DFS) algorithm for traversing a graph or tree in a systematic way. The DFS iterator visits the vertices reachable from a given source vertex, exploring as far as possible along each branch before backtracking. The iterator maintains a stack of vertices to be visited, and it visits each vertex only once.

One of the most common usages of DFS iterator is to find connected components in a graph. It can also be used to detect cycles in a graph, find strongly connected components in a directed graph, and perform topological sorting. In addition, DFS iterator can be used to find all paths between two vertices in a graph and to solve puzzles such as the n-queens problem.

The time complexity of the DFS iterator algorithm is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because the algorithm visits each vertex and edge exactly once. The space complexity of DFS iterator is O(V), where V is the number of vertices in the graph. This is because the algorithm uses a stack to store the vertices to be visited, and the maximum size of the stack is equal to the maximum depth of the DFS traversal.

On the same graph as the BFS example, the DFS iterator that starts from A returns A, D, E, F, C, B. Run DFS step by step on gograph.dev, with the stack and the visited vertices at each step.

Topological Sort

Topological iterator is a technique used to implement the Topological Sort algorithm for sorting the vertices of a directed acyclic graph (DAG) in a linear ordering. The topological sort orders the vertices such that for every directed edge (u, v), vertex u comes before vertex v in the ordering. Topological iterator iteratively removes the vertices with no incoming edges and adds them to the sorted list. It then removes the outgoing edges of the removed vertex and repeats the process.

One of the most common usages of topological iterator is to schedule tasks or dependencies in a project based on their dependencies. It can also be used to detect cycles in a DAG, which indicates a circular dependency that makes it impossible to find a topological ordering. In addition, topological iterator can be used to generate a linear ordering of events in a causal relationship, such as in a concurrent system or a timeline of events.

The time complexity of topological iterator algorithm is O(V + E), where V is the number of vertices and E is the number of edges in the graph. This is because the algorithm visits each vertex and edge exactly once. The space complexity of topological iterator is O(V), where V is the number of vertices in the graph. This is because the algorithm uses a queue to store the vertices to be visited, and the maximum size of the queue is equal to the number of vertices in the graph.

For example, on this directed acyclic graph:

flowchart LR
    n0["A"]
    n1["B"]
    n2["C"]
    n3["D"]
    n4["E"]
    n5["F"]
    n0 --> n1
    n0 --> n3
    n1 --> n4
    n3 --> n4
    n4 --> n5
    n5 --> n2

the topological iterator returns A, B, D, E, F, C. Run the topological sort step by step on gograph.dev, with the queue and the in-degree of each vertex at each step.

Closest First

Closest-first traversal, also known as the Best-First search or Greedy Best-First search, is a technique used to traverse a graph or a tree based on the distance between vertices and a given source vertex. The algorithm iteratively visits the vertex closest to the source vertex first and then expands its neighbors, repeating this process until every vertex reachable from the source has been visited. The distance can be defined in various ways, such as the number of edges, the weight of the edges, or any other distance metric.

One of the most common usages of closest-first iterator is to find the shortest path between two vertices in a graph or to perform nearest-neighbor searches in machine learning or recommendation systems. It can also be used for clustering, community detection, and network analysis.

The time and space complexity of closest-first iterator depend on the implementation of the distance metric and the data structure used for storing the vertices and their distances. If the distance metric is constant and the graph is represented as an adjacency matrix, the time complexity of closest-first iterator is O(V^2), where V is the number of vertices in the graph. If the distance metric is variable and the graph is represented as an adjacency list, the time complexity of closest-first iterator is O(E log V), where E is the number of edges in the graph. The space complexity of closest-first iterator is also O(V) for storing the distances and the visited vertices.

For example, on this weighted graph:

flowchart LR
    n0["A"]
    n1["B"]
    n2["C"]
    n3["D"]
    n4["E"]
    n5["F"]
    n0 ---|"2"| n1
    n0 ---|"3"| n3
    n1 ---|"3"| n2
    n1 ---|"5"| n4
    n2 ---|"4"| n5
    n3 ---|"1"| n4
    n4 ---|"3"| n5

the closest-first iterator that starts from A returns A, B, D, E, C, F. Run closest-first step by step on gograph.dev, with the priority queue at each step.

Random Walk

Random walk iterator is a technique used to traverse a graph in a stochastic manner by randomly selecting the next vertex to visit based on a probability distribution. In the context of graph traversal, random walk iterator can be categorized into two types: weighted and unweighted.

In the weighted random walk iterator, the probability distribution for selecting the next vertex to visit is proportional to the weights of the edges connecting the current vertex to its neighbors. This means that edges with higher weights have a higher probability of being selected in the random walk. Weighted random walk iterator is commonly used in applications such as recommendation systems, where we want to find similar items or users based on their interactions in a network. Edges with a weight of zero or less are never selected, unless none of the edges of the current vertex has a positive weight. Then each of them has an equal probability.

In the unweighted random walk iterator, the probability distribution for selecting the next vertex to visit is uniform and does not depend on the weights of the edges. This means that all neighbors of the current vertex have an equal probability of being selected in the random walk. Unweighted random walk iterator is commonly used in applications such as web crawling, where we want to explore the web in a random and unbiased manner.

The time and space complexity of random walk iterator depend on the size and structure of the graph, the number of vertices visited, and the type of random walk iterator used. In general, the time complexity of random walk iterator is proportional to the number of edges in the graph, while the space complexity is proportional to the number of visited vertices.

Run a random walk step by step on gograph.dev.

Documentation

Overview

Package traverse visits the vertices of a gograph.Graph in breadth-first, depth-first, closest-first, topological and random walk order.

Each traversal except the random walk comes in two forms. An iterator, such as the one NewBreadthFirstIterator returns, hands out one vertex per Next call and can be Reset. A sequence, such as the one BFS returns, is for a range loop. BFS, BFSWithDepth, DFS and ClosestFirst do their work as the loop asks for the next vertex, so breaking out of the loop ends the traversal there, and ranging over the sequence again runs the traversal again from the start. Topological sorts the graph when it is called.

DFSEvents and DFSEventsAll report each step of a depth-first search: when a vertex is discovered and finished, and whether each edge is a tree, back, forward or cross edge. Algorithms such as cycle finding and topological sort by finish time are a loop over these events.

Each vertex is the graph's own vertex, the one GetVertexByID returns for its label. Changing the graph during a traversal isn't supported, with one exception: a vertex removed from the graph after the traversal queued it is skipped.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func BFS added in v0.10.0

func BFS[T comparable](g gograph.Graph[T], start T) iter.Seq[*gograph.Vertex[T]]

BFS returns the vertices that start reaches, in breadth-first order: the order of NewBreadthFirstIterator. It yields nothing if start isn't in g, and skips a vertex removed from g after it was queued.

Ranging over all of it takes O(V+E) time and O(V) extra space for the V vertices and E edges that start reaches.

Example
package main

import (
	"fmt"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	g := gograph.New[string](gograph.Directed())
	_, _ = g.AddEdge(gograph.NewVertex("A"), gograph.NewVertex("B"))
	_, _ = g.AddEdge(gograph.NewVertex("A"), gograph.NewVertex("C"))
	_, _ = g.AddEdge(gograph.NewVertex("B"), gograph.NewVertex("D"))
	_, _ = g.AddEdge(gograph.NewVertex("C"), gograph.NewVertex("E"))

	for v := range traverse.BFS(g, "A") {
		fmt.Println(v.Label())
		if v.Label() == "C" {
			break
		}
	}
}
Output:
A
B
C

func BFSWithDepth added in v0.10.0

func BFSWithDepth[T comparable](g gograph.Graph[T], start T) iter.Seq2[*gograph.Vertex[T], int]

BFSWithDepth returns the vertices that start reaches, in the order of BFS, each with its depth. start has depth 0, and every other vertex the number of edges on a shortest path from start. It yields nothing if start isn't in g, and skips a vertex removed from g after it was queued.

Ranging over all of it takes O(V+E) time and O(V) extra space for the V vertices and E edges that start reaches.

Example
package main

import (
	"fmt"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	g := gograph.New[string](gograph.Directed())
	_, _ = g.AddEdge(gograph.NewVertex("A"), gograph.NewVertex("B"))
	_, _ = g.AddEdge(gograph.NewVertex("A"), gograph.NewVertex("C"))
	_, _ = g.AddEdge(gograph.NewVertex("B"), gograph.NewVertex("D"))
	_, _ = g.AddEdge(gograph.NewVertex("C"), gograph.NewVertex("D"))

	for v, depth := range traverse.BFSWithDepth(g, "A") {
		fmt.Println(v.Label(), depth)
	}
}
Output:
A 0
B 1
C 1
D 2

func ClosestFirst added in v0.10.0

func ClosestFirst[T comparable](g gograph.Graph[T], start T) iter.Seq2[*gograph.Vertex[T], float64]

ClosestFirst returns the vertices that start reaches, by increasing distance from start: the order of NewClosestFirstIterator. Each vertex comes with its distance, the sum of the edge weights on a shortest path from start. It yields nothing if start isn't in g, and skips a vertex removed from g after it was queued.

Edge weights are expected to be non-negative. An edge with a NaN weight is skipped, and a vertex reached only through a +Inf weight comes after every vertex at a finite distance. An edge added without a weight weighs 0, so in a graph without weights every distance is 0. BFSWithDepth gives the number of edges from start instead.

Ranging over all of it takes O((V+E) log V) time and O(V) extra space for the V vertices and E edges that start reaches.

Example
package main

import (
	"fmt"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	g := gograph.New[string](gograph.Directed(), gograph.Weighted())
	_, _ = g.AddEdge(gograph.NewVertex("home"), gograph.NewVertex("school"), gograph.WithEdgeWeight(4))
	_, _ = g.AddEdge(gograph.NewVertex("home"), gograph.NewVertex("bakery"), gograph.WithEdgeWeight(1))
	_, _ = g.AddEdge(gograph.NewVertex("bakery"), gograph.NewVertex("school"), gograph.WithEdgeWeight(2))

	for v, dist := range traverse.ClosestFirst(g, "home") {
		fmt.Println(v.Label(), dist)
	}
}
Output:
home 0
bakery 1
school 3

func DFS added in v0.10.0

func DFS[T comparable](g gograph.Graph[T], start T) iter.Seq[*gograph.Vertex[T]]

DFS returns the vertices that start reaches, in the order of NewDepthFirstIterator: the next vertex is always the latest one found, and the neighbors of a vertex are found in the order of Neighbors. It yields nothing if start isn't in g, and skips a vertex removed from g after it was found.

Ranging over all of it takes O(V+E) time and O(V) extra space for the V vertices and E edges that start reaches.

Example
package main

import (
	"fmt"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	g := gograph.New[string](gograph.Directed())
	_, _ = g.AddEdge(gograph.NewVertex("A"), gograph.NewVertex("B"))
	_, _ = g.AddEdge(gograph.NewVertex("A"), gograph.NewVertex("C"))
	_, _ = g.AddEdge(gograph.NewVertex("B"), gograph.NewVertex("D"))

	// the latest vertex found comes next, so C comes before B
	for v := range traverse.DFS(g, "A") {
		fmt.Println(v.Label())
	}
}
Output:
A
C
B
D

func DFSEvents added in v0.10.0

func DFSEvents[T comparable](g gograph.Graph[T], start T) iter.Seq[DFSEvent[T]]

DFSEvents returns the events of a depth-first search from start. It discovers a vertex when it first enters it, then looks at its neighbors in the order of Neighbors, one edge event each, and finishes the vertex once all of them are handled. A tree edge discovers its destination right away, so the events of each vertex nest inside the events of its parent, like parentheses. A missing start yields nothing.

In a directed graph, each edge from a vertex the search reaches comes once, as one of the four edge kinds. A forward edge goes to a finished vertex discovered after the edge's source, and a cross edge to one discovered before it. In an undirected graph, each edge comes once too: as a tree edge when it discovers a vertex, or as a back edge from the deeper of its two vertices. The search skips the edge back to the parent and the second direction of an edge it already reported, so only tree and back edges occur. A self-loop is a back edge in both kinds of graph.

The search runs as the loop asks for the next event, so breaking out of the loop ends it there, and ranging over the sequence again searches again. It keeps its own stack, so the goroutine stack stays small on a long path. A vertex or an edge removed from g during the loop is skipped when the search gets to it.

Ranging over all of it takes O(V+E) time for the V vertices and E edges that start reaches. It keeps O(V) state, plus the neighbors still to look at of each vertex on the current path, which is at most O(V+E).

Example
package main

import (
	"fmt"
	"strings"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	g := gograph.New[string](gograph.Directed())
	a := g.AddVertexByLabel("A")
	b := g.AddVertexByLabel("B")
	c := g.AddVertexByLabel("C")
	_, _ = g.AddEdge(a, b)
	_, _ = g.AddEdge(a, c)
	_, _ = g.AddEdge(b, c)
	_, _ = g.AddEdge(c, a)

	for e := range traverse.DFSEvents(g, "A") {
		indent := strings.Repeat("  ", e.Depth)
		if e.Edge != nil {
			fmt.Printf("%s%v %s -> %s\n", indent, e.Kind, e.Edge.Source().Label(), e.Edge.Destination().Label())
			continue
		}
		fmt.Printf("%s%v %s\n", indent, e.Kind, e.Vertex.Label())
	}
}
Output:
DiscoverVertex A
TreeEdge A -> B
  DiscoverVertex B
  TreeEdge B -> C
    DiscoverVertex C
    BackEdge C -> A
    FinishVertex C
  FinishVertex B
ForwardEdge A -> C
FinishVertex A

func DFSEventsAll added in v0.10.0

func DFSEventsAll[T comparable](g gograph.Graph[T]) iter.Seq[DFSEvent[T]]

DFSEventsAll returns the events of a depth-first search over all of g. It searches from each vertex not discovered yet, in the order of GetAllVertices, and each of those vertices has depth 0. The events follow the rules of DFSEvents, and a cross edge can go to a vertex of an earlier search.

Ranging over all of it takes O(V+E) time. It keeps O(V) state, plus the neighbors still to look at of each vertex on the current path, which is at most O(V+E).

Example
package main

import (
	"fmt"
	"slices"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	// in a graph without cycles, the reverse of the finish order is a
	// topological order
	g := gograph.New[string](gograph.Directed())
	for _, e := range [][2]string{
		{"shirt", "tie"}, {"tie", "jacket"}, {"pants", "shoes"}, {"pants", "belt"}, {"belt", "jacket"},
	} {
		_, _ = g.AddEdge(gograph.NewVertex(e[0]), gograph.NewVertex(e[1]))
	}

	var order []string
	for e := range traverse.DFSEventsAll(g) {
		if e.Kind == traverse.FinishVertex {
			order = append(order, e.Vertex.Label())
		}
	}
	slices.Reverse(order)
	fmt.Println(order)
}
Output:
[pants belt shoes shirt tie jacket]

func Topological added in v0.10.0

func Topological[T comparable](g gograph.Graph[T]) (iter.Seq[*gograph.Vertex[T]], error)

Topological returns the vertices of g in the order of gograph.TopologySort. It returns gograph.ErrNotDirected if g isn't directed and gograph.ErrDAGHasCycle if g has a cycle, each with a sequence that yields nothing.

It sorts g when it is called, in O(V+E) time and O(V) space, so breaking out of the loop early saves nothing, and ranging over the sequence again yields the same order even if g has changed.

Example
package main

import (
	"fmt"

	"github.com/hmdsefi/gograph"
	"github.com/hmdsefi/gograph/traverse"
)

func main() {
	g := gograph.New[string](gograph.Acyclic())
	_, _ = g.AddEdge(gograph.NewVertex("fetch"), gograph.NewVertex("build"))
	_, _ = g.AddEdge(gograph.NewVertex("build"), gograph.NewVertex("test"))
	_, _ = g.AddEdge(gograph.NewVertex("fetch"), gograph.NewVertex("lint"))

	steps, err := traverse.Topological(g)
	if err != nil {
		fmt.Println(err)
		return
	}
	for v := range steps {
		fmt.Println(v.Label())
	}
}
Output:
fetch
build
lint
test

Types

type DFSEvent added in v0.10.0

type DFSEvent[T comparable] struct {
	Kind DFSEventKind
	// Vertex is set for DiscoverVertex and FinishVertex.
	Vertex *gograph.Vertex[T]
	// Edge is set for the edge kinds. Its source is the vertex the search is
	// at, and its destination the neighbor the search looks at.
	Edge *gograph.Edge[T]
	// Depth is the depth of Vertex, or of the source of Edge, in the
	// depth-first tree. The vertex a search starts from has depth 0.
	Depth int
}

DFSEvent is one step of a depth-first search.

type DFSEventKind added in v0.10.0

type DFSEventKind int

DFSEventKind tells which step of a depth-first search a DFSEvent reports.

const (
	// DiscoverVertex is the first time the search reaches a vertex.
	DiscoverVertex DFSEventKind = iota
	// FinishVertex comes once every vertex reachable from the vertex has been
	// handled.
	FinishVertex
	// TreeEdge is an edge to an undiscovered vertex. The tree edges form the
	// depth-first tree, and the source of each one is the parent of its
	// destination.
	TreeEdge
	// BackEdge is an edge to a vertex still on the current path, which closes
	// a cycle. A self-loop is a back edge.
	BackEdge
	// ForwardEdge is an edge to a finished descendant. It occurs in directed
	// graphs only.
	ForwardEdge
	// CrossEdge is an edge to a finished vertex that isn't a descendant. It
	// occurs in directed graphs only.
	CrossEdge
)

func (DFSEventKind) String added in v0.10.0

func (k DFSEventKind) String() string

String returns the name of the kind, such as "TreeEdge", or "DFSEventKind(n)" for a value outside the constants.

type Iterator

type Iterator[T comparable] interface {
	// HasNext returns a boolean value indicating whether there are more
	// elements to be iterated over. It returns true if there are more
	// elements. Otherwise, returns false.
	HasNext() bool

	// Next returns the next element in the sequence being iterated over.
	// If there are no more elements, it returns nil. It also advances
	// the iterator to the next element.
	Next() *gograph.Vertex[T]

	// Iterate iterates over all elements in the sequence and calls the
	// provided callback function on each element. The callback function
	// takes a single argument of type *Vertex, representing the current
	// element being iterated over. It returns an error value, which is
	// returned by the Iterate method. If the callback function returns
	// an error, iteration is stopped and the error is returned.
	Iterate(func(v *gograph.Vertex[T]) error) error

	// Reset  resets the iterator to its initial state, allowing the
	// sequence to be iterated over again from the beginning.
	Reset()
}

Iterator represents a general purpose iterator for iterating over a sequence of graph's vertices. It provides methods for checking if there are more elements to be iterated over, getting the next element, iterating over all elements using a callback function, and resetting the iterator to its initial state.

func NewBreadthFirstIterator

func NewBreadthFirstIterator[T comparable](g gograph.Graph[T], start T) (Iterator[T], error)

NewBreadthFirstIterator creates a new instance of breadthFirstIterator and returns it as the Iterator interface.

func NewClosestFirstIterator added in v0.2.0

func NewClosestFirstIterator[T comparable](graph gograph.Graph[T], start T) (Iterator[T], error)

NewClosestFirstIterator creates a new instance of closestFirstIterator and returns it as the Iterator interface.

Edge weights are expected to be non-negative. An edge with a NaN weight is skipped. A vertex reached only through a +Inf weight is visited after every vertex at a finite distance.

if the start node doesn't exist, returns error.

func NewDepthFirstIterator

func NewDepthFirstIterator[T comparable](g gograph.Graph[T], start T) (Iterator[T], error)

NewDepthFirstIterator creates a new instance of depthFirstIterator and returns it as the Iterator interface.

func NewRandomWalkIterator added in v0.2.0

func NewRandomWalkIterator[T comparable](graph gograph.Graph[T], start T, steps int) (Iterator[T], error)

NewRandomWalkIterator creates a new instance of randomWalkIterator and returns it as the Iterator interface.

The walk returns the start vertex first. The steps argument is the maximum number of vertices returned, including the start vertex, so a walk with five steps moves at most four times.

Without gograph.Weighted(), each neighbor has an equal chance of being picked. With gograph.Weighted(), each step picks a neighbor with a probability proportional to the weight of the edge to it. Edges with a weight of zero or less are never picked, unless none of the edges of the current vertex has a positive weight. Then each of them has an equal chance. An edge with a weight of positive infinity is picked over any edge with a finite weight.

func NewTopologicalIterator

func NewTopologicalIterator[T comparable](g gograph.Graph[T]) (Iterator[T], error)

NewTopologicalIterator creates a new instance of topologicalIterator and returns it as the Iterator interface. It returns gograph.ErrNotDirected if the graph is not directed, and gograph.ErrDAGHasCycle if the graph has a cycle.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL