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:
parent
dc34a45b94
commit
42d8211402
BIN
go/pov/cmd/cmd
BIN
go/pov/cmd/cmd
Binary file not shown.
@ -8,19 +8,13 @@ import (
|
||||
|
||||
func main() {
|
||||
g := pov.New()
|
||||
g.AddNode("parent")
|
||||
g.AddArc("parent", "x")
|
||||
g.AddArc("x", "sib-2")
|
||||
g.AddArc("x", "sib-3")
|
||||
g.AddArc("x", "sib-4")
|
||||
g.AddNode("sibling")
|
||||
g.AddNode("x")
|
||||
g.AddArc("parent", "sibling")
|
||||
g.AddArc("sibling", "child-1")
|
||||
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)
|
||||
g.AddArc("parent", "x")
|
||||
fmt.Println("== Change Root to child-3 ==")
|
||||
n := g.ChangeRoot("parent", "child-3")
|
||||
pov.PrintGraph(n)
|
||||
g.Print("parent")
|
||||
n := g.ChangeRoot("parent", "x")
|
||||
fmt.Println(n.ArcList())
|
||||
g.Print("x")
|
||||
}
|
||||
|
194
go/pov/pov.go
194
go/pov/pov.go
@ -2,8 +2,14 @@ package pov
|
||||
|
||||
const testVersion = 2
|
||||
|
||||
// A Graph is just a collection of Nodes
|
||||
type Node struct {
|
||||
label string
|
||||
connections []Node
|
||||
}
|
||||
|
||||
type Graph struct {
|
||||
leaves []Node
|
||||
nodes []Node
|
||||
}
|
||||
|
||||
func New() *Graph {
|
||||
@ -11,124 +17,120 @@ func New() *Graph {
|
||||
}
|
||||
|
||||
func (g *Graph) AddNode(lbl string) {
|
||||
// Make sure that g doesn't already have node lbl
|
||||
if g.getNode(lbl) != nil {
|
||||
return
|
||||
if g.getNode(lbl) == nil {
|
||||
g.nodes = append(g.nodes, Node{label: lbl})
|
||||
}
|
||||
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 {
|
||||
for i := range g.leaves {
|
||||
if r := g.leaves[i].getNode(lbl); r != nil {
|
||||
return r
|
||||
for i := range g.nodes {
|
||||
if g.nodes[i].label == lbl {
|
||||
return &g.nodes[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Return a graph from 'newRoot's POV
|
||||
func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
|
||||
root := g.getNode(newRoot)
|
||||
if root == nil {
|
||||
return nil
|
||||
func (g *Graph) AddArc(fr, to string) {
|
||||
frN := g.getNode(fr)
|
||||
if frN == nil {
|
||||
g.AddNode(fr)
|
||||
frN = g.getNode(fr)
|
||||
}
|
||||
ret := New()
|
||||
//pth := g.GetPath(oldRoot, newRoot)
|
||||
if root.parent != nil {
|
||||
root.parent.removeLeaf(root.label)
|
||||
root.parent.parent = root
|
||||
root.addWholeNode(root.parent)
|
||||
root.parent = nil
|
||||
toN := g.getNode(to)
|
||||
if g.getNode(to) == nil {
|
||||
g.AddNode(to)
|
||||
toN = g.getNode(to)
|
||||
}
|
||||
ret.addWholeNode(root)
|
||||
return ret
|
||||
frN.connections = append(frN.connections, *toN)
|
||||
}
|
||||
|
||||
func (g *Graph) addWholeNode(n *Node) {
|
||||
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 {
|
||||
func (g *Graph) 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()...)
|
||||
for _, k := range g.nodes {
|
||||
for _, l := range k.connections {
|
||||
ret = append(ret, k.label+" -> "+l.label)
|
||||
}
|
||||
}
|
||||
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
|
||||
// getPath returns the shortest path from 'fr' to 'to'
|
||||
func (g *Graph) getPath(fr, to string) []string {
|
||||
if fr == to {
|
||||
return []string{fr}
|
||||
}
|
||||
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
|
||||
st := g.getNode(fr)
|
||||
if st == nil {
|
||||
// Couldn't find the starting node
|
||||
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)
|
||||
}
|
||||
}
|
||||
if len(valPaths) == 0 {
|
||||
// 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 (n *Node) getNode(lbl string) *Node {
|
||||
if n.label == lbl {
|
||||
return n
|
||||
func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
|
||||
pth := g.getPath(oldRoot, newRoot)
|
||||
if len(pth) == 0 {
|
||||
// No valid path
|
||||
return g
|
||||
}
|
||||
for i := range n.leaves {
|
||||
if r := n.leaves[i].getNode(lbl); r != nil {
|
||||
return r
|
||||
for oldRoot != newRoot {
|
||||
// We just keep swapping the first two in pth until we're done
|
||||
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
|
||||
}
|
||||
|
@ -5,20 +5,19 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func PrintGraph(g *Graph) {
|
||||
for i := range g.leaves {
|
||||
PrintNode(&g.leaves[i], 1)
|
||||
func (g *Graph) Print(root string) {
|
||||
r := g.getNode(root)
|
||||
if r != nil {
|
||||
r.Print(0)
|
||||
} else {
|
||||
fmt.Println("Couldn't find root node:", root)
|
||||
}
|
||||
}
|
||||
|
||||
func PrintNode(n *Node, lvl int) {
|
||||
fmt.Print(strings.Repeat(" ", lvl))
|
||||
if n.parent == nil {
|
||||
fmt.Println("{label:", n.label, "}")
|
||||
} else {
|
||||
fmt.Println("{label:", n.label, ", parent:", n.parent.label, "}")
|
||||
}
|
||||
for i := range n.leaves {
|
||||
PrintNode(&n.leaves[i], lvl+1)
|
||||
func (n *Node) Print(ind int) {
|
||||
pad := strings.Repeat(" ", ind)
|
||||
fmt.Println(pad + n.label)
|
||||
for i := range n.connections {
|
||||
n.connections[i].Print(ind + 1)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package pov
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"testing"
|
||||
@ -266,10 +267,13 @@ func TestTestVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConstruction(t *testing.T) {
|
||||
fmt.Println("TestConstruction")
|
||||
for _, tc := range testCases {
|
||||
fmt.Println("Starting test:", tc.description)
|
||||
got := tc.graph().ArcList()
|
||||
want := tc.arcStrings
|
||||
tc.testResult(got, want, "incorrect graph construction", t)
|
||||
fmt.Println(" Test Passed:", tc.description)
|
||||
}
|
||||
}
|
||||
|
||||
|
206
go/pov/tree/pov.go
Normal file
206
go/pov/tree/pov.go
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user