У меня большая популяционная родословная (map[int][]int
), где ключом является животное, а родители (два) в срезе значения. Животные без родителей будут иметь отрицательные целые числа для родителей.
Во-вторых, у меня есть список животных, для которых я хочу построить свои родословные специфицированные c и записать в файл. Родословная всех животных из моего списка должна быть записана в один файл.
pedigree := map[int][]int{
1: []int{2, 3},
2: []int{-1, 5},
3: []int{6, 7},
4: []int{8, 9},
5: []int{-1, -2},
6: []int{8, -2},
7: []int{-1, -2},
8: []int{-1, -2},
9: []int{10, -2},
10: []int{-1, 4}
}
list := []int{1, 4}
И что я ожидаю от файла, написанного io.Writer:
1 2 3
2 -1 5
3 6 7
5 -1 -2
6 8 -2
7 -1 -2
8 -1 -2
4 8 9
9 10 -2
10 -1 4
Итак Мне нужна рекурсивная функция для прохождения родословной, начиная с базового животного, а затем продолжая по всем путям, пока не будут достигнуты родители с отрицательными числами.
БОЛЬШЕ ВАЖНО животные в моем списке определены как животные, которые вызывают циклы в родословной (животное 4 становится великим родителем самого себя).
Я пробовал это со следующим кодом:
type tree struct {
sire *tree
dam *tree
animal int
base int
path []int
}
func newTree(a, s, d, b int) tree {
return tree{
animal: a,
sire: &tree{animal: s, base: b},
dam: &tree{animal: d, base: b},
base: b,
}
}
for _, animal := range list {
myTree = newTree(animal, pedigree[animal][0], pedigree[animal][1], 0)
walk(myTree, written, fw) // written is a map of integers and fw is io.Writer
}
func walk(t tree, written map[int]int, writer io.Writer) tree {
style := "%12d%12d%12d\n"
if t.animal == t.base {
return t
}
if t.base == 0 { // for the first iteration
t.base = t.animal
}
if _, ok := written[t.animal]; !ok {
sire := t.sire.animal
dam := t.dam.animal
if sire == 0 {
sire = t.base
}
if dam == 0 {
dam = t.base
}
written[t.animal] = 0
io.WriteString(writer, fmt.Sprintf(style, t.animal, sire, dam))
}
// Shift forward.
if t.sire.animal > 0 {
myTree := newTree(t.sire.animal, pedigree[t.sire.animal][0], pedigree[t.dam.animal][1], t.base)
walk(myTree, written, writer)
}
if t.dam.animal > 0 {
myTree := newTree(t.dam.animal, pedigree[t.dam.animal][0], pedigree[t.dam.animal][1], t.base)
walk(myTree, written, writer)
}
return t
}
Моя родословная состоит из примерно 13 миллионов животных , но я не могу заставить функцию остановиться в нужной точке и получить stack overflow
pani c после нескольких животных. Я считаю, что некоторые из моих проблем:
- Животное, которое участвует в цикле, является базовым животным, поэтому я должен проверить, является ли
animal == base
(1->2->3->1)
- Животным, которое является участие в цикле НЕ базовое животное
(1->2->3->4->5->6->3)
Любая помощь будет оценена.