| package treex |
|
|
| type Tree[T any] struct { |
| root *Node[T] |
| } |
|
|
| |
| |
| func NewTree[T any](root *Node[T]) (*Tree[T], error) { |
| if root == nil { |
| return nil, ErrRootNodeIsNil |
| } |
|
|
| visited := make(map[*Node[T]]bool) |
| onStack := make(map[*Node[T]]bool) |
|
|
| var dfs func(n *Node[T]) error |
| dfs = func(n *Node[T]) error { |
| if n == nil { |
| return ErrNodeGraphInvalid |
| } |
|
|
| if onStack[n] { |
| return ErrGraphHasCycle |
| } |
| if visited[n] { |
| return nil |
| } |
|
|
| visited[n] = true |
| onStack[n] = true |
| for _, child := range n.children { |
| if child == nil { |
| return ErrNodeGraphInvalid |
| } |
| if err := dfs(child); err != nil { |
| return err |
| } |
| } |
| onStack[n] = false |
| return nil |
| } |
|
|
| if err := dfs(root); err != nil { |
| return nil, err |
| } |
|
|
| return &Tree[T]{root: root}, nil |
| } |
|
|
| func (t *Tree[T]) Root() *Node[T] { |
| return t.root |
| } |
|
|
| func (t *Tree[T]) DFS(cb func(n *Node[T]) (stop bool, err error)) error { |
| if t.root == nil { |
| return nil |
| } |
|
|
| var walk func(n *Node[T]) error |
| walk = func(n *Node[T]) error { |
| stop, err := cb(n) |
| if err != nil { |
| return err |
| } |
| if stop { |
| return nil |
| } |
|
|
| for _, child := range n.children { |
| if child == nil { |
| return ErrNodeGraphInvalid |
| } |
| if err := walk(child); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
|
|
| return walk(t.root) |
| } |
|
|
| |
| func (t *Tree[T]) Leafs() []*Node[T] { |
| leafs := make([]*Node[T], 0) |
|
|
| _ = t.DFS(func(n *Node[T]) (bool, error) { |
| if n.IsLeaf() { |
| leafs = append(leafs, n) |
| } |
| return false, nil |
| }) |
|
|
| return leafs |
| } |
|
|
| |
| |
| |
| |
| |
| |
| func (t *Tree[T]) SwapNode(old *Node[T], new *Node[T]) error { |
| if old == t.Root() { |
| t.root = new |
| return nil |
| } |
|
|
| if old.Parent() == nil { |
| return ErrNodeHasNoParentButNotRoot |
| } |
|
|
| parent := old.Parent() |
| return parent.SwapChild(old, new) |
| } |
|
|