The problem is, since you are marking save / release (although this is not really the case, save / release is slightly near ummm capacity ... we will get there at the end). This is not related to distribution. You do not select unnecessary objects, you just save them for a while, and then release them. I'll start with Kenneth code, which optimizes a lot of performance issues in the original, but still has this problem. (I do not consider recursive code because it crashes in your current use case. However, it shies away from some redundant save.)
Itโs worth saying that the Kenneth code is good and, as a rule, you should do something (as you will see even more when we go).
First note: when you mentioned -Ofast , for ObjC, not for Swift. The flag for Swift is just -O . You also want -whole-module-optimization , but that doesn't help anything.
Another little thing, then we get to it. Mark final classes anytime. This ensures that there is no dynamic dispatch. It doesnโt matter here when compared to saving / releasing, but hey, take some lightweight material.
Sounds good at 30%?
OK, now great, and this is a trick. I find that I can knock out about 30% of the time (from ~ 6 minutes to ~ 4 minutes for a full import) by rewriting this:
guard let subtree = navigator.leftTree else { navigator.leftTree = BinarySearchTree<T>(value: newValue) break } navigator = subtree continue
Like this:
let subtree = navigator.leftTree if subtree == nil { navigator.leftTree = BinarySearchTree(value: newValue) break } navigator = subtree! continue
This is something to be very careful with. In this case, it turns out to be faster, but it may not be so fast on other inputs. This may not be so fast when switching to the optimizer (SIL generation is a bit strange, and I suspect that this may be a mistake, because it seems that in the second case the navigator saved twice, but only if succeeded). But now it is faster. (EDIT: The Swift team was surprised at this finding, and now there is a bug open against . Don't expect this to work in the future.)
How about 85% like that sound?
But as you said, could we avoid all this with structures? But it would be insanely expensive to copy the whole tree every time we touch it. Of course, we could greatly improve this by copying to write, for example using Array. But COW is pretty complicated. If there was only a way to reuse existing material. What if we use Array?
private struct Node<Element: Comparable> { let value: Element var leftIndex = -1
It will take about 45 seconds to work on my system. Of course, this makes delete little more complicated. You will either have to accept the "missed" memory (possibly with periodic repackaging), or you will need to support freelist. But freelancer won't be too hard to add.
Try to improve 99.97% without changing add() .
And, of course, it is important to remember that this is an almost pathological case for BST. Even if you often transmitted data in order, it would be better for you to shuffle it before inserting it, including the cost of shuffling. For example, using shuffleInPlace (and counting its time), inserting exactly the same values:
var values = Array(0 ... count - 1) values.shuffleInPlace() for (loop, value) in values.enumerate() { if (loop % 1000 == 0) { print(loop) } root.add(value) }
It takes from 45 to 0.1 s. (Kenneth version and my version of โ!โ Are approximately 0.2 s on this metric, I would probably use Kenneth's solution, adding final . Even your source code, which has great inefficiency that Kenneth fixed, takes only 0.5 s with this change. Remember that the optimized Kenneth version with the addition in order was 6 minutes on my system.)
Shuffle before inserting. If you get things over time, it might be worth it to dose and shuffle them before inserting. If the tree changes over time, it is worth checking if it is too deep, and periodically rebuild it. Keeping the depth of the tree intelligently overloads every other optimization. Smart ways to work with Swift memory could not touch this change.
Correct the algorithm. Everything else is peanuts in comparison.