In looking for a solution to this question, I ran across some old binary tree code by Daniel Lichtblau, reproduced below:
Clear[leftsubtree, rightsubtree, nodevalue, emptyTree, treeInsert] leftsubtree[{left_, _, _}] := left rightsubtree[{_, _, right_}] := right nodevalue[{_, val_, _}] := val emptyTree = {}; treeInsert[emptyTree, elem_] := {emptyTree, elem, emptyTree} treeInsert[tree_, elem_] /; SameQ[nodevalue[tree], elem] := tree treeInsert[tree_, elem_] /; OrderedQ[{nodevalue[tree], elem}] := {leftsubtree[tree], nodevalue[tree], treeInsert[rightsubtree[tree], elem]} treeInsert[tree_, elem_] := {treeInsert[leftsubtree[tree], elem], nodevalue[tree], rightsubtree[tree]} When mapped onto a list, treeInsert gives you a sorted duplicate free list. For example,
tr = {}; Scan[(tr = treeInsert[tr, #]) &, RandomInteger[100, 5]]; Flatten@tr (* {13, 28, 53, 59, 88} *) On my machine, this takes ~2 s to process RandomInteger[10, 10^5], but this increases to nearly 20 s with RandomInteger[10, 10^6]. There are likely other techniques to speed this up, but I am curious as to how memoization could be adapted to this problem. At issue, though, is that the tree changes with each insertion, and so it cannot be used directly for memoization because the definition depends directly on that form. How would one do this?
Edit: as I discovered in my own testing, Fold works much better than Scan for creating a tree, as follows
tr = Fold[treeInsert, {}, RandomInteger[100, 5]]; Flatten@tr (* {13, 28, 53, 59, 88} *) Update: while my question, per se, was not answered directly, the answers themselves indicated that there were better ways to accomplish what I wanted. In the end, I chose the one I did for two reasons: speed and simplicity.
Min[list]-1andMax[list]+1, then useCompile, then replace back. This way, you can keep it almost as fast as without infinities. $\endgroup$