I've been trying with limited success to find a more efficient way of discovering all paths along a tree - from multiple roots to multiple leaves. I had it working somewhat using mutable strings and snipping the heads and tails (like a blockchain) but it's buggy and my gut says there has to be a more efficient route (no pun intended).
All relationships between nodes are first defined as parent-child and are held in a dictionary like so:
Parent1 = [child1, child2, child3] Parent2 = [child1, child2, child4]
Combined with a list of all nodes, the following sets can be calculated:
- Elders (nodes without parents but with children)
- Younglings (nodes with parents but without children)
- Everyone else (children / parents, any generation)
- Free floaters (nodes with neither parents nor children)
My thinking is that the elders should be the starting point (root) and all possible paths to the younglings (leaves) could be calculated using BFS Breath-First-Search, but was under the impression that it only allowed for a single root-node / elder. I need an algorithm that can accept multiple elders and multiple younglings. My code so far:
NSMutableArray * ma = [NSMutableArray new];
NSArray * from = [NSArray arrayWithArray:[eldersSet allObjects]];
NSArray * to = [NSArray arrayWithArray:[youngSet allObjects]];
for (int n = 0; n < (int)from.count; n++){
NSString * fromString = from[n];
for (int k = 0; k < (int)to.count; k++){
NSString * toString = to[k];
NSString * toFrom = [NSString stringWithFormat:@"%@ -> %@", fromString, toString];
NSArray * array = [self searchTreeFrom:fromString childID:toString runArray:[NSArray new]];
if (array.count == 0){
continue;
}
[ma addObject:@{@"path":toFrom, @"array":array}];
}
}
NSLog(@"ma is %@", ma);
-(NSArray *)searchTreeFrom:(NSString *)parentID childID:(NSString *)childID runArray:(NSArray *)runArray{
if ([parentID isEqualToString:childID]){
NSMutableArray * ma = [NSMutableArray array];
[ma addObjectsFromArray:runArray];
[ma addObject:childID];
return (NSArray *)ma;
}
NSMutableArray * result = [NSMutableArray new];
if ([localR valueForKey:parentID]){
NSArray * localArray = localR[parentID];
for (int n = 0; n < (int)localArray.count; n++){
result = [NSMutableArray arrayWithArray:[self searchTreeFrom:localArray[n] childID:childID runArray:result]];
if (result.count > 0){
[result insertObject:parentID atIndex:0];
return result;
}
}
}
return result;
}
It's mostly working, even where routes overlap in an (X) shape, with two elders, one shared child node in the middle and two younglings - it still calculates all the paths correctly. However a (<>) diamond shape leads to the issue that the returned path only goes along the top route (the first child node).
A (<>) diamond has two paths, but the issue is that only one path is requested, from single elder to single youngling, whereas in the former (X) four are requested (two elders, two younglings). I'm wondering if I'm going about this all wrong, as the total number of paths in a (<>) diamond style shape cannot be known in advance, and instead to focus on the recursive function, not returning a value where n == 0, but forcing it through the entire list of children.
Has anyone had any experience with multiple-root -> multiple-leaf path generation? Am I doing something stupid? The goal isn't to find the most efficient path or anything, only to discover all paths. I should mention that the localR
variable listed above is the parent=[child,child] dictionary. I'll include output and visual below: