package algo
type Node struct {
Name string
Childs map[string]*Node
}
func (n *Node) AddChild(child *Node) {
if n.Childs == nil {
n.Childs = make(map[string]*Node)
}
n.Childs[child.Name] = child
}
package algo
func (n *Node) ParentsMap(dupCache map[string]struct{}) map[string]map[string]struct{} {
if dupCache == nil {
dupCache = map[string]struct{}{}
}
if _, ok := dupCache[n.Name]; ok {
return nil
}
dupCache[n.Name] = struct{}{}
psM := map[string]map[string]struct{}{
n.Name: map[string]struct{}{},
}
for chName, chNode := range n.Childs {
ps, ok := psM[chName]
if !ok {
ps = map[string]struct{}{}
}
ps[n.Name] = struct{}{}
psM[chName] = ps
chpsM := chNode.ParentsMap(dupCache)
for ch, chps := range chpsM {
ps, ok := psM[ch]
if !ok {
ps = map[string]struct{}{}
}
for p := range chps {
ps[p] = struct{}{}
}
psM[ch] = ps
}
}
return psM
}
package algo
func (n *Node) Sort() ([][][]string, error) {
psm := n.ParentsMap(nil)
origPsm := map[string]map[string]struct{}{} // deepCopy
for n, ps := range psm {
origPs := map[string]struct{}{}
for p := range ps {
origPs[p] = struct{}{}
}
origPsm[n] = origPs
}
sorted := [][][]string{}
curNodes := map[string]*Node{
n.Name: n,
}
for len(curNodes) > 0 {
level := [][]string{}
nextNodes := map[string]*Node{}
for _, curN := range curNodes {
group := []string{curN.Name}
for {
nextNode, ok := curN.chainChild(origPsm)
if ok {
ps := psm[nextNode.Name]
delete(ps, curN.Name)
psm[nextNode.Name] = ps
curN = nextNode
group = append(group, curN.Name)
continue
}
break
}
level = append(level, group)
for nextName, nextNode := range curN.Childs {
ps := psm[nextName]
delete(ps, curN.Name)
psm[nextName] = ps
if len(ps) == 0 {
nextNodes[nextName] = nextNode
}
}
}
sorted = append(sorted, level)
curNodes = nextNodes
}
for _, ps := range psm {
if len(ps) > 0 {
return nil, errors.New("cycle found")
}
}
return sorted, nil
}
// find single chain Child
func (n *Node) chainChild(parentsMap map[string]map[string]struct{}) (*Node, bool) {
if len(n.Childs) != 1 {
return nil, false
}
for chName, chNode := range n.Childs {
if len(parentsMap[chName]) != 1 {
return nil, false
}
return chNode, true
}
return nil, false
}