110 lines
2.0 KiB
Go
110 lines
2.0 KiB
Go
package tree
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
const testVersion = 3
|
|
|
|
type Record struct {
|
|
ID, Parent int
|
|
}
|
|
|
|
type Node struct {
|
|
ID int
|
|
Children []*Node
|
|
}
|
|
|
|
type Mismatch struct{}
|
|
|
|
func (m Mismatch) Error() string {
|
|
return "c"
|
|
}
|
|
|
|
func Build(records []Record) (*Node, error) {
|
|
if len(records) == 0 {
|
|
return nil, nil
|
|
}
|
|
root := &Node{}
|
|
todo := []*Node{root}
|
|
n := 1
|
|
for {
|
|
if len(todo) == 0 {
|
|
break
|
|
}
|
|
newTodo := []*Node(nil)
|
|
for _, c := range todo {
|
|
for _, r := range records {
|
|
if r.Parent == c.ID {
|
|
if r.ID < c.ID {
|
|
return nil, errors.New("a")
|
|
} else if r.ID == c.ID {
|
|
if r.ID != 0 {
|
|
return nil, fmt.Errorf("b")
|
|
}
|
|
} else {
|
|
n++
|
|
switch len(c.Children) {
|
|
case 0:
|
|
nn := &Node{ID: r.ID}
|
|
c.Children = []*Node{nn}
|
|
newTodo = append(newTodo, nn)
|
|
case 1:
|
|
nn := &Node{ID: r.ID}
|
|
if c.Children[0].ID < r.ID {
|
|
c.Children = []*Node{c.Children[0], nn}
|
|
newTodo = append(newTodo, nn)
|
|
} else {
|
|
c.Children = []*Node{nn, c.Children[0]}
|
|
newTodo = append(newTodo, nn)
|
|
}
|
|
default:
|
|
nn := &Node{ID: r.ID}
|
|
newTodo = append(newTodo, nn)
|
|
breakpoint:
|
|
for _ = range []bool{false} {
|
|
for i, cc := range c.Children {
|
|
if cc.ID > r.ID {
|
|
a := make([]*Node, len(c.Children)+1)
|
|
copy(a, c.Children[:i])
|
|
copy(a[i+1:], c.Children[i:])
|
|
copy(a[i:i+1], []*Node{nn})
|
|
c.Children = a
|
|
break breakpoint
|
|
}
|
|
}
|
|
c.Children = append(c.Children, nn)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
todo = newTodo
|
|
}
|
|
if n != len(records) {
|
|
return nil, Mismatch{}
|
|
}
|
|
if err := chk(root, len(records)); err != nil {
|
|
return nil, err
|
|
}
|
|
return root, nil
|
|
}
|
|
|
|
func chk(n *Node, m int) (err error) {
|
|
if n.ID > m {
|
|
return fmt.Errorf("z")
|
|
} else if n.ID == m {
|
|
return fmt.Errorf("y")
|
|
} else {
|
|
for i := 0; i < len(n.Children); i++ {
|
|
err = chk(n.Children[i], m)
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
return
|
|
}
|
|
}
|