Changing it into a graph

Since that's what they actually want, even though the exercise says it's
a tree
This commit is contained in:
Brian Buller 2017-08-24 11:16:04 -05:00
parent dc34a45b94
commit 42d8211402
6 changed files with 325 additions and 120 deletions

Binary file not shown.

View File

@ -8,19 +8,13 @@ import (
func main() { func main() {
g := pov.New() g := pov.New()
g.AddNode("parent") g.AddNode("sibling")
g.AddArc("parent", "x") g.AddNode("x")
g.AddArc("x", "sib-2")
g.AddArc("x", "sib-3")
g.AddArc("x", "sib-4")
g.AddArc("parent", "sibling") g.AddArc("parent", "sibling")
g.AddArc("sibling", "child-1") g.AddArc("parent", "x")
g.AddArc("sibling", "child-2")
g.AddArc("sibling", "child-3")
g.AddArc("child-3", "grandchild-1")
g.AddArc("grandchild-1", "greatgrandchild-1")
pov.PrintGraph(g)
fmt.Println("== Change Root to child-3 ==") fmt.Println("== Change Root to child-3 ==")
n := g.ChangeRoot("parent", "child-3") g.Print("parent")
pov.PrintGraph(n) n := g.ChangeRoot("parent", "x")
fmt.Println(n.ArcList())
g.Print("x")
} }

View File

@ -2,8 +2,14 @@ package pov
const testVersion = 2 const testVersion = 2
// A Graph is just a collection of Nodes
type Node struct {
label string
connections []Node
}
type Graph struct { type Graph struct {
leaves []Node nodes []Node
} }
func New() *Graph { func New() *Graph {
@ -11,124 +17,120 @@ func New() *Graph {
} }
func (g *Graph) AddNode(lbl string) { func (g *Graph) AddNode(lbl string) {
// Make sure that g doesn't already have node lbl if g.getNode(lbl) == nil {
if g.getNode(lbl) != nil { g.nodes = append(g.nodes, Node{label: lbl})
return
} }
g.leaves = append(g.leaves, Node{label: lbl})
}
func (g *Graph) AddArc(fr, to string) {
if frN := g.getNode(fr); frN != nil {
frN.AddNode(to)
}
}
func (g *Graph) ArcList() []string {
var arcList []string
for i := range g.leaves {
arcList = append(arcList, g.leaves[i].ArcList()...)
}
return arcList
}
func (g *Graph) GetPath(fr, to string) []string {
if frN := g.getNode(fr); frN != nil {
return frN.GetPath(to)
}
return []string{}
} }
func (g *Graph) getNode(lbl string) *Node { func (g *Graph) getNode(lbl string) *Node {
for i := range g.leaves { for i := range g.nodes {
if r := g.leaves[i].getNode(lbl); r != nil { if g.nodes[i].label == lbl {
return r return &g.nodes[i]
} }
} }
return nil return nil
} }
// Return a graph from 'newRoot's POV func (g *Graph) AddArc(fr, to string) {
func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph { frN := g.getNode(fr)
root := g.getNode(newRoot) if frN == nil {
if root == nil { g.AddNode(fr)
return nil frN = g.getNode(fr)
} }
ret := New() toN := g.getNode(to)
//pth := g.GetPath(oldRoot, newRoot) if g.getNode(to) == nil {
if root.parent != nil { g.AddNode(to)
root.parent.removeLeaf(root.label) toN = g.getNode(to)
root.parent.parent = root
root.addWholeNode(root.parent)
root.parent = nil
} }
ret.addWholeNode(root) frN.connections = append(frN.connections, *toN)
return ret
} }
func (g *Graph) addWholeNode(n *Node) { func (g *Graph) ArcList() []string {
g.leaves = append(g.leaves, *n)
}
type Node struct {
label string
leaves []Node
parent *Node
}
func (n *Node) AddNode(lbl string) {
nn := Node{label: lbl, parent: n}
n.leaves = append(n.leaves, nn)
}
func (n *Node) addWholeNode(nd *Node) {
n.leaves = append(n.leaves, *nd)
}
func (n *Node) removeLeaf(lbl string) {
for i := range n.leaves {
if n.leaves[i].label == lbl {
n.leaves = append(n.leaves[:i], n.leaves[i+1:]...)
}
}
}
func (n *Node) ArcList() []string {
var ret []string var ret []string
for i := range n.leaves { for _, k := range g.nodes {
// Append this arc for _, l := range k.connections {
ret = append(ret, n.label+" -> "+n.leaves[i].label) ret = append(ret, k.label+" -> "+l.label)
// Append all sub-arcs }
ret = append(ret, n.leaves[i].ArcList()...)
} }
return ret return ret
} }
// GetPath returns a string slice of all leaves leading to 'to' // getPath returns the shortest path from 'fr' to 'to'
func (n *Node) GetPath(to string) []string { func (g *Graph) getPath(fr, to string) []string {
ret := []string{n.label} if fr == to {
if n.label == to { return []string{fr}
return ret
} }
for i := range n.leaves { st := g.getNode(fr)
if toN := n.leaves[i].getNode(to); toN != nil { if st == nil {
// This is the leaf to follow // Couldn't find the starting node
return append(ret, n.leaves[i].GetPath(to)...) return []string{}
}
var valPaths [][]string
for i := range st.connections {
if st.connections[i].label == to {
return []string{fr, to}
}
tst := g.getPath(st.connections[i].label, to)
if len(tst) > 0 {
valPaths = append(valPaths, tst)
} }
} }
// Couldn't get there if len(valPaths) == 0 {
return []string{} // No valid paths found
return []string{}
}
var ret []string
for i := range valPaths {
if len(valPaths[i]) < len(ret) || len(ret) == 0 {
ret = valPaths[i]
}
}
return ret
} }
// Returns the node with label lbl or nil func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
func (n *Node) getNode(lbl string) *Node { pth := g.getPath(oldRoot, newRoot)
if n.label == lbl { if len(pth) == 0 {
return n // No valid path
return g
} }
for i := range n.leaves { for oldRoot != newRoot {
if r := n.leaves[i].getNode(lbl); r != nil { // We just keep swapping the first two in pth until we're done
return r if len(pth) >= 2 {
n := g.getNode(pth[1])
if n == nil {
return g
}
n = n.copy()
p := g.getNode(pth[0])
if p == nil {
return g
}
p = p.copy()
p.removeConnection(n.label)
n.connections = append(n.connections, *p)
oldRoot = n.label
} }
} }
return nil return g
}
func (n *Node) removeConnection(to string) {
for i, k := range n.connections {
if k.label == to {
copy(n.connections[i:], n.connections[i+1:])
n.connections[len(n.connections)-1] = Node{}
n.connections = n.connections[:len(n.connections)-1]
}
}
}
// Node.copy() returns a new node that is a copy of this node
func (n *Node) copy() *Node {
ret := Node{label: n.label}
for _, k := range n.connections {
cp := k.copy()
ret.connections = append(ret.connections, *cp)
}
return &ret
} }

View File

@ -5,20 +5,19 @@ import (
"strings" "strings"
) )
func PrintGraph(g *Graph) { func (g *Graph) Print(root string) {
for i := range g.leaves { r := g.getNode(root)
PrintNode(&g.leaves[i], 1) if r != nil {
r.Print(0)
} else {
fmt.Println("Couldn't find root node:", root)
} }
} }
func PrintNode(n *Node, lvl int) { func (n *Node) Print(ind int) {
fmt.Print(strings.Repeat(" ", lvl)) pad := strings.Repeat(" ", ind)
if n.parent == nil { fmt.Println(pad + n.label)
fmt.Println("{label:", n.label, "}") for i := range n.connections {
} else { n.connections[i].Print(ind + 1)
fmt.Println("{label:", n.label, ", parent:", n.parent.label, "}")
}
for i := range n.leaves {
PrintNode(&n.leaves[i], lvl+1)
} }
} }

View File

@ -1,6 +1,7 @@
package pov package pov
import ( import (
"fmt"
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
@ -266,10 +267,13 @@ func TestTestVersion(t *testing.T) {
} }
func TestConstruction(t *testing.T) { func TestConstruction(t *testing.T) {
fmt.Println("TestConstruction")
for _, tc := range testCases { for _, tc := range testCases {
fmt.Println("Starting test:", tc.description)
got := tc.graph().ArcList() got := tc.graph().ArcList()
want := tc.arcStrings want := tc.arcStrings
tc.testResult(got, want, "incorrect graph construction", t) tc.testResult(got, want, "incorrect graph construction", t)
fmt.Println(" Test Passed:", tc.description)
} }
} }

206
go/pov/tree/pov.go Normal file
View File

@ -0,0 +1,206 @@
package pov
const testVersion = 2
type Graph struct {
leaves []Node
Iters int
}
func New() *Graph {
return new(Graph)
}
func (g *Graph) AddNode(lbl string) {
// Make sure that g doesn't already have node lbl
if g.getNode(lbl) != nil {
return
}
g.leaves = append(g.leaves, Node{label: lbl})
}
func (g *Graph) AddArc(fr, to string) {
var frN *Node
if frN = g.getNode(fr); frN == nil {
// frN doesn't exist yet... Create it and
// drop
frN = &Node{label: fr}
}
frN.AddNode(to)
}
func (g *Graph) ArcList() []string {
var arcList []string
for i := range g.leaves {
arcList = append(arcList, g.leaves[i].ArcList()...)
}
return arcList
}
func (g *Graph) GetPath(fr, to string) []string {
if frN := g.getNode(fr); frN != nil {
return frN.GetPath(to)
}
return []string{}
}
func (g *Graph) getNode(lbl string) *Node {
for i := range g.leaves {
if r := g.leaves[i].getNode(lbl); r != nil {
return r
}
}
return nil
}
// Return a graph from newRoot's POV
func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
ret := g
pth := ret.GetPath(oldRoot, newRoot)
for oldRoot != newRoot {
// Swap the first two in pth
if len(pth) >= 2 {
n := ret.getNode(pth[1])
if n == nil {
return ret
}
n = n.copy()
p := ret.getNode(pth[0])
if p == nil {
return ret
}
p = p.copy()
if n != nil && p != nil {
p.removeLeaf(n.label)
n.addWholeNode(p)
if p.parent != nil {
n.parent = p.parent
p.parent = nil
} else {
n.parent = nil
}
}
ret = New()
ret.addWholeNode(n)
oldRoot = n.label
}
pth = ret.GetPath(oldRoot, newRoot)
}
return ret
}
/*
// Return a graph from newRoot's POV
func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
if oldRoot == newRoot {
return g
}
ret := New()
pth := g.GetPath(oldRoot, newRoot)
fmt.Println(pth)
// Swap the first two in pth
if len(pth) >= 2 {
fmt.Println("Swap ", pth[0], "<>", pth[1])
n := g.getNode(pth[1])
p := g.getNode(pth[0])
if n != nil && p != nil {
p.removeLeaf(n.label)
n.addWholeNode(p)
if p.parent != nil {
n.parent = p.parent
p.parent = nil
} else {
n.parent = nil
}
}
ret.addWholeNode(n)
}
PrintGraph(ret)
if pth[1] != newRoot {
fmt.Println("Recurse:", pth[1], "<>", newRoot)
return ret
//return ret.ChangeRoot(pth[1], newRoot)
} else {
return ret
}
}
*/
func (g *Graph) addWholeNode(n *Node) {
g.leaves = append(g.leaves, *n)
}
type Node struct {
label string
leaves []Node
parent *Node
}
func (n *Node) copy() *Node {
// Returns a new node that is a copy of this node
ret := Node{label: n.label, parent: n.parent}
for _, k := range n.leaves {
cp := k.copy()
ret.leaves = append(ret.leaves, *cp)
}
return &ret
}
func (n *Node) AddNode(lbl string) {
nn := Node{label: lbl, parent: n}
n.leaves = append(n.leaves, nn)
}
func (n *Node) addWholeNode(nd *Node) {
n.leaves = append(n.leaves, *nd)
}
func (n *Node) removeLeaf(lbl string) {
for i, k := range n.leaves {
if k.label == lbl {
copy(n.leaves[i:], n.leaves[i+1:])
n.leaves[len(n.leaves)-1] = Node{}
n.leaves = n.leaves[:len(n.leaves)-1]
}
}
}
func (n *Node) ArcList() []string {
var ret []string
for i := range n.leaves {
// Append this arc
ret = append(ret, n.label+" -> "+n.leaves[i].label)
// Append all sub-arcs
ret = append(ret, n.leaves[i].ArcList()...)
}
return ret
}
// GetPath returns a string slice of all leaves leading to 'to'
func (n *Node) GetPath(to string) []string {
ret := []string{n.label}
if n.label == to {
return ret
}
for i := range n.leaves {
if toN := n.leaves[i].getNode(to); toN != nil {
// This is the leaf to follow
return append(ret, n.leaves[i].GetPath(to)...)
}
}
// Couldn't get there
return []string{}
}
// Returns the node with label lbl or nil
func (n *Node) getNode(lbl string) *Node {
if n.label == lbl {
return n
}
for i := range n.leaves {
if r := n.leaves[i].getNode(lbl); r != nil {
return r
}
}
return nil
}