Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add feature directed and undirected graph #158

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions graphs/graph.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package graphs

// Graph holds vertices and edges of a graph
type Graph struct {
isDirected bool
vertices []node
}

type node struct {
name interface{}
edges []interface{}
}

const infinity = int(^uint(0) >> 1)

// NewDirectedGraph is for creating a directed graph
func NewDirectedGraph() *Graph {
g := Graph{}
g.vertices = make([]node, 0)
g.isDirected = true
return &g
}

// NewUndirectedGraph is for creating an undirected graph
func NewUndirectedGraph() *Graph {
g := Graph{}
g.vertices = make([]node, 0)
g.isDirected = false
return &g
}

// AddVertice is for adding a new vertice. id vertice exists do nothing
func (g *Graph) AddVertice(name interface{}) {
g.addVertice(name)
}

// AddEdge if for adding a new edge.
func (g *Graph) AddEdge(from, to interface{}) {
g.addEdge(from, to)
}

// GetEdge is for getting all the edges of vertice n
func (g *Graph) GetEdge(n interface{}) []interface{} {
return g.getEdge(n)
}

// GetVertices is for getting all vertices info
func (g *Graph) GetVertices() []interface{} {
return g.getVertices()
}

// ShortestPath is for finding shortest path from edge s to t by using belman-ford algorithm
func (g *Graph) ShortestPath(s, t interface{}) map[interface{}]int {
return g.shortestPath(s, t)
}

func (g *Graph) addVertice(name interface{}) int {
for i, v := range g.vertices {
if v.name == name {
return i
}
}
n := node{}
n.name = name
n.edges = make([]interface{}, 0)
g.vertices = append(g.vertices, n)

return len(g.vertices) - 1
}

func (g *Graph) addEdge(from, to interface{}) {
f := g.addVertice(from)
t := g.addVertice(to)
g.vertices[f].edges = append(g.vertices[f].edges, to)
if !g.isDirected {
g.vertices[t].edges = append(g.vertices[t].edges, from)
}
}

func (g *Graph) getEdge(n interface{}) []interface{} {
for _, v := range g.vertices {
if v.name == n {
return v.edges
}
}
// todo throw exception
return nil
}

func (g *Graph) getVertices() []interface{} {
vertices := make([]interface{}, 0)
for i := 0; i < len(g.vertices); i++ {
vertices = append(vertices, g.vertices[i].name)
}
return vertices
}

func (g *Graph) shortestPath(sName, tName interface{}) map[interface{}]int {
n := len(g.vertices)
s := g.addVertice(sName)
dist := make([]int, n)
for i := 0; i < n; i++ {
dist[i] = infinity
}
dist[s] = 0
for u := 0; u < n-1; u++ {
for _, vName := range g.vertices[u].edges {
v := g.addVertice(vName)
if dist[u] != infinity && dist[u]+1 < dist[v] {
dist[v] = dist[u] + 1
}
}
}
result := make(map[interface{}]int)
for i, d := range dist {
result[g.vertices[i].name] = d
}
return result
}
102 changes: 102 additions & 0 deletions graphs/graph_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package graphs

import (
"testing"
)

func TestGrsphAddVertice(t *testing.T) {
g1 := NewDirectedGraph()
g1.AddVertice("a")
g1.AddVertice("b")
g1.AddVertice("c")
g1.AddVertice("d")
actualValue1 := g1.GetVertices()
expectedValue1 := []string{"a", "b", "c", "d"}
for i, v := range expectedValue1 {
if v != actualValue1[i] {
t.Errorf("Got %v expected %v", actualValue1, expectedValue1)
return
}
}

g2 := NewDirectedGraph()
g2.AddVertice(1)
g2.AddVertice(2)
g2.AddVertice(3)
g2.AddVertice(4)
actualValue2 := g2.GetVertices()

expectedValue2 := []int{1, 2, 3, 4}
for i, v := range expectedValue2 {
if v != actualValue2[i] {
t.Errorf("Got %v expected %v", actualValue2, expectedValue2)
return
}
}

g3 := NewUndirectedGraph()
g3.AddVertice("a")
g3.AddVertice("b")
g3.AddVertice("c")
g3.AddVertice("d")
actualValue3 := g3.GetVertices()
expectedValue3 := []string{"a", "b", "c", "d"}
for i, v := range expectedValue3 {
if v != actualValue3[i] {
t.Errorf("Got %v expected %v", actualValue3, expectedValue3)
return
}
}
}

func TestGrsphAddEdge(t *testing.T) {
g1 := NewDirectedGraph()
g1.AddVertice("a")
g1.AddVertice("b")
g1.AddEdge("a", "b")
g1.AddEdge("c", "a")
actualValue1 := g1.GetEdge("a")
expectedValue1 := []string{"b"}
for i, v := range expectedValue1 {
if v != actualValue1[i] {
t.Errorf("Got %v expected %v", actualValue1, expectedValue1)
return
}
}

g2 := NewUndirectedGraph()
g2.AddVertice("a")
g2.AddVertice("b")
g2.AddEdge("a", "b")
g2.AddEdge("c", "a")
actualValue2 := g2.GetEdge("a")
expectedValue2 := []string{"b", "c"}
for i, v := range expectedValue2 {
if v != actualValue2[i] {
t.Errorf("Got %v expected %v", actualValue2, expectedValue2)
return
}
}
}

func TestShortestPath(t *testing.T) {
g := NewDirectedGraph()
g.addEdge("a", "b")
g.addEdge("b", "c")
g.addEdge("c", "a")
g.addEdge("c", "d")

tests := [][]interface{}{
{1, "a", 0},
{2, "b", 1},
{3, "c", 2},
{4, "d", 3},
}

for _, test := range tests {
actualValue, expectedValue := g.shortestPath("a", "b")[test[1]], test[2]
if actualValue != expectedValue {
t.Errorf("Got %v expected %v", actualValue, expectedValue)
}
}
}