123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121 |
- // CookieJar - A contestant's algorithm toolbox
- // Copyright 2013 Peter Szilagyi. All rights reserved.
- //
- // CookieJar is dual licensed: use of this source code is governed by a BSD
- // license that can be found in the LICENSE file. Alternatively, the CookieJar
- // toolbox may be used in accordance with the terms and conditions contained
- // in a signed written agreement between you and the author(s).
- // Package bfs implements the breadth-first-search algorithm for the graphs.
- //
- // The BFS is implemented using on demand calculations, meaning that only that
- // part of the search space will be expanded as requested, iteratively expanding
- // it if needed.
- //
- // Neighbor traversal order currently is random due to the graph implementation.
- // Specific order may be added in the future.
- package bfs
- import (
- "gopkg.in/karalabe/cookiejar.v2/collections/queue"
- "gopkg.in/karalabe/cookiejar.v2/collections/stack"
- "gopkg.in/karalabe/cookiejar.v2/graph"
- )
- // Breadth-first-search algorithm data structure.
- type Bfs struct {
- graph *graph.Graph
- source int
- visited []bool
- parents []int
- order []int
- paths map[int][]int
- pending *queue.Queue
- builder *stack.Stack
- }
- // Creates a new random-order bfs structure.
- func New(g *graph.Graph, src int) *Bfs {
- d := new(Bfs)
- d.graph = g
- d.source = src
- d.visited = make([]bool, g.Vertices())
- d.visited[src] = true
- d.parents = make([]int, g.Vertices())
- d.order = make([]int, 1, g.Vertices())
- d.order[0] = src
- d.paths = make(map[int][]int)
- d.pending = queue.New()
- d.pending.Push(src)
- d.builder = stack.New()
- return d
- }
- // Generates the path from the source node to the destination.
- func (d *Bfs) Path(dst int) []int {
- // Return nil if not reachable
- if !d.Reachable(dst) {
- return nil
- }
- // If reachable, but path not yet generated, create and cache
- if cached, ok := d.paths[dst]; !ok {
- for cur := dst; cur != d.source; {
- d.builder.Push(cur)
- cur = d.parents[cur]
- }
- d.builder.Push(d.source)
- path := make([]int, d.builder.Size())
- for i := 0; i < len(path); i++ {
- path[i] = d.builder.Pop().(int)
- }
- d.paths[dst] = path
- return path
- } else {
- return cached
- }
- }
- // Checks whether a given vertex is reachable from the source.
- func (d *Bfs) Reachable(dst int) bool {
- if !d.visited[dst] && !d.pending.Empty() {
- d.search(dst)
- }
- return d.visited[dst]
- }
- // Generates the full order in which nodes were traversed.
- func (d *Bfs) Order() []int {
- // Force bfs termination
- if !d.pending.Empty() {
- d.search(-1)
- }
- return d.order
- }
- // Continues the bfs search from the last yield point, looking for dst.
- func (d *Bfs) search(dst int) {
- for !d.pending.Empty() {
- // Fetch the next node, and visit if new
- src := d.pending.Pop().(int)
- d.graph.Do(src, func(peer interface{}) {
- if p := peer.(int); !d.visited[p] {
- d.visited[p] = true
- d.order = append(d.order, p)
- d.parents[p] = src
- d.pending.Push(p)
- }
- })
- // If we found the destination, yield
- if dst == src {
- return
- }
- }
- }
|