《算法》无向图--go语言实现

无向图–go语言实现(持续更新)

在许多计算机应用中,由相连的结点所表示的模型起到了关键的作用。这些结点之间的连接很 自然地会让人们产生一连串的疑问:沿着这些连接能否从一个结点到达另一个结点?有多少个结点 和指定的结点相连?两个结点之间最短的连接是哪一条?
要描述这些问题,我们要使用一种抽象的数学对象,叫做图
摘自《算法》

图的数据结构和基本操作

package graph

import (
    "container/list"
)

// 图的数据结构
type Graph struct {
    v   int          // 顶点数
    e   int          // 边数
    adj []*list.List // 邻边链表切片
}

// 创建一个图
func New(v int, e [][2]int) *Graph {
    graph := new(Graph)
    graph.v = v
    graph.e = len(e)

    var adj []*list.List

    for i := 0; i < v; i++ {
        adj = append(adj, list.New())
    }
    graph.adj = adj

    for _, val := range e {
        graph.AddEdge(val[0], val[1])
    }
    return graph
}

// 获取图的定点数量
func (g *Graph) V() int {
    return g.v
}

// 获取图中边的数量
func (g *Graph) E() int {
    return g.e
}

// 向图中添加一条边
func (g *Graph) AddEdge(v int, w int) {
    g.adj[v].PushFront(w)
    g.adj[w].PushFront(v)
}

// 获取与顶点相通的其他顶点 返回一个链表
func (g *Graph) Adj(v int) *list.List {
    return g.adj[v]
}

`</pre>

#### 深度优先搜索

<pre class="line-numbers prism-highlight" data-start="1">`package graph

/**
深度优先搜索算法
 */

type depth struct {
    marked []bool
    count  int
}

func NewDepth(g *Graph, s int) *depth {

    depth := &amp;depth{
        marked: make([]bool, g.v),
        count:  0,
    }
    depth.dfs(g, s)

    return depth
}

// 利用递归实现图深度优先搜索
func (d *depth) dfs(g *Graph, v int) {
    d.marked[v] = true
    d.count++

    for e := g.Adj(v).Front(); e != nil; e = e.Next() {

        w, _ := e.Value.(int)
        if !d.marked[w] {
            d.dfs(g, w)
        }
    }
}

// 判断传入的顶点是否与初始顶点相通
func (d *depth) Marked(w int) bool {
    return d.marked[w]
}

// 和初始顶点相通的顶点数量
func (d *depth) Count() int {
    return d.count
}

`</pre>

#### 深度优先搜索路径

<pre class="line-numbers prism-highlight" data-start="1">`package graph

type Paths struct {
    marked []bool
    edgeTo []int
    final  int
}

func NewPaths(graph *Graph, s int) *Paths {
    paths := &amp;Paths{
        marked: make([]bool, graph.V()),
        edgeTo: make([]int, graph.V()),
        final:  s,
    }
    paths.dfs(graph, s)
    return paths
}

func (p *Paths) dfs(graph *Graph, v int) {
    p.marked[v] = true

    for e := graph.Adj(v).Front(); e != nil; e = e.Next() {
        w, _ := e.Value.(int)
        if !p.marked[w] {
            p.edgeTo[w] = v
            p.dfs(graph, w)
        }
    }
}

func (p *Paths) HasPathTo(v int) bool {
    return p.marked[v]
}

func (p *Paths) PathTo(v int) []int {
    if !p.HasPathTo(v) {
        return nil
    }
    path := make([]int, 0)
    var x int
    for x = v; x != p.final; x = p.edgeTo[x] {
        path = append(path, x)
    }
    path = append(path, x)
    return path
}

`</pre>

#### 广度优先搜索最短路径

<pre class="line-numbers prism-highlight" data-start="1">`package graph

import "container/list"

/**
*广度优先搜索
*/

type Breadth struct {
    marked []bool
    edgeTo []int
    final  int
}

func NewBreadth(graph *Graph, s int) *Breadth {
    breadth := &amp;Breadth{
        marked: make([]bool, graph.v),
        edgeTo: make([]int, graph.v),
        final:  s,
    }
    breadth.bfs(graph, s)

    return breadth
}

func (b *Breadth) bfs(graph *Graph, s int) {
    queue := list.New()
    b.marked[s] = true
    queue.PushBack(s)

    for queue.Len() != 0 {
        element := queue.Front()
        v, _ := queue.Remove(element).(int)
        for e := graph.Adj(v).Front(); e != nil; e = e.Next() {
            val, _ := e.Value.(int)
            if b.marked[val] == false {
                b.marked[val] = true
                b.edgeTo[val] = v
                queue.PushBack(e.Value)
            }
        }
    }

}

func (b *Breadth) HasPathTo(v int) bool {
    return b.marked[v]
}

func (b *Breadth) Path(v int) []int {
    if !b.HasPathTo(v) {
        return nil
    }
    path := make([]int, 0)
    for p := v; p != b.final;p = b.edgeTo[p] {
        path = append(path,p)
    }
    path = append(path,b.final)

    return path
}

`</pre>

#### 最后测试

<pre class="line-numbers prism-highlight" data-start="1">`package main

import (
    "graph"
    "fmt"
)

func main() {
    data := [][2]int{
        {0, 1},
        {1, 3},
        {0, 3},
    }
    g := graph.New(4, data)

    //depth := graph.NewDepth(g, 1)
    //fmt.Println(depth.Marked(3))

    //paths := graph.NewPaths(g, 0)
    //fmt.Println(paths.PathTo(3))

    paths := graph.NewBreadth(g, 0)
    fmt.Println(paths.Path(3))
}