Data Structures · Union-Find and Succinct Structures

The Inverse Ackermann Bound and Why It Is Effectively Constant

How the α(n) function is defined, why the amortized cost of a disjoint-set sequence lands there, and what the matching lower bound says about improving it.

The claim “disjoint sets are O(1) per operation” is close enough to true that it is repeated without qualification, and wrong enough that a careful engineer should know where it stops being true. The actual statement is that a sequence of m operations on n elements costs O(m · α(n)) amortized, where α is the inverse of a variant of the Ackermann function. Since α(n) ≤ 4 for any n below about 2^65536, the bound is indistinguishable from constant on real inputs. The distinction matters because the bound is amortized rather than worst-case, because the constant is not free, and because the result comes with a matching lower bound that closes off the obvious avenues for improvement.

Defining the function by its growth, not its formula

The Ackermann function is usually presented as a recursive curiosity, and its inverse as an opaque symbol. What matters for the analysis is only the tower-of-exponentials structure.

Define a family of functions A_k by iterated application. A_0(j) = j + 1. A_1(j) = 2j + 1, which is A_0 applied j + 1 times to j. In general A_k(j) is A_{k-1} applied j + 1 times starting from j, so each increment of k adds a level to a tower. A_2 grows roughly like 2^(j+1), A_3 grows like a tower of twos of height j, and A_4 grows like a tower whose height is itself a tower.

The inverse function used in the disjoint-set bound is not a single inverse of one Ackermann function. It is defined by a diagonal construction: α(n) is the smallest k such that A_k(1) ≥ n. Equivalently, α(n) counts how many levels of the tower are needed before the value exceeds n.

The consequences are worth stating in the form the literature uses. Published values for α on small inputs differ between papers, because the family A_k is defined in more than one way and the variants disagree by one or two for tiny n; what all the variants agree on is the growth. Two statements hold across the variants:

  • α(n) is at most 4 for every n below 2^65536, a number with about 19,729 decimal digits.
  • The input at which α(n) first exceeds 4 is comparable to A_4(1), a tower of exponentials, and each further unit of α requires an input larger than anything that could be stored, let alone indexed.

Any element count that fits in the memory of any physically constructible machine is far below the 2^65536 threshold. For n = 2^64, α(n) is at most 4. For n = 2^32 it is at most 4 as well. So the bound O(m α(n)) is, for every input that can exist, O(4m).

The subtlety is that α is not a constant in the asymptotic sense. It grows without bound as n grows, just unimaginably slowly. The threshold at which α(n) first exceeds 4 is A_4(1), a tower of exponentials, so an adversary allocating n = 2^65537 elements would still face α(n) = 4; forcing α(n) = 5 requires an input larger than any count that could be stored. The theorem holds regardless, which is why the result is stated as “almost linear” rather than linear, and why the phrase “inverse Ackermann” appears in the literature rather than “constant”.

Where the potential argument puts the levels

The proof is a potential-function argument, and its shape explains the extra factor. Each element is charged a small number of credits at creation, and those credits pay for link traversals later. The accounting assigns each node a level derived from its rank and from the number of times its parent pointer has been rewritten by compression.

Two facts drive the bound. First, an element’s rank increases at most log₂ n times, because a rank increase happens only when two trees of equal rank merge and the resulting block doubles in size. Second, between two rank increases, the node’s parent chain can only be compressed a bounded number of times before the parent’s rank has risen enough to move the node into a higher level bracket. The levels are indexed by k, and the number of brackets is α(n).

A find traverses a path whose nodes fall into at most α(n) + 2 brackets, and within each bracket the traversal is charged to a credit that was deposited earlier. The total charge over m operations is O(m α(n)), with the n initialization contributing O(n).

The argument is delicate in a way the final statement hides. Tarjan’s 1975 paper gives the O(m α(n)) bound for union by rank with path compression, and the 1975 result is not the last word: Tarjan and van Leeuwen’s 1984 paper analyses path halving and path splitting, shows they achieve the same bound with different constants, and proves a lower bound in the pointer-machine model. That lower bound says that any algorithm in this family — one that maintains a forest of parent pointers and answers connectivity queries by walking it — needs Ω(m α(n)) time. The bound is therefore tight for the technique, not merely an artifact of a particular implementation.

What the lower bound does and does not rule out

The lower bound is stated for a restricted model: a pointer machine with O(1)-size cells, where the only operations are following pointers, comparing, and storing. It does not claim that connectivity under unions needs Ω(m α(n)) on every machine model, only that a structure which answers connectivity by walking parent pointers cannot do better.

Gabow and Tarjan gave a linear-time algorithm for the special case where the unions form a known tree structure in advance — the “static tree set union” problem. When the sequence of unions is constrained to a tree that is known before the operations begin, the whole sequence can be processed in O(m + n). That special case covers a real family of applications: computing connected components bottom-up in a tree, or merging along the edges of a fixed forest. The linear bound is not obtained by clever pointer manipulation; it comes from exploiting the known structure to replace the general union logic with a precomputed numbering scheme.

The general case is different. The lower bound belongs to the pointer-machine model, and it is a statement about the representation — a forest of singly linked cells walked one hop at a time — rather than about the problem. A structure that answers connectivity some other way is not covered by it, which is why the Gabow-Tarjan special case can be linear and why the bit-parallel structures later in this cluster have their own bounds.

The engineering conclusion is not “find a better algorithm”. It is that the constant factor, not the asymptotic class, is where any remaining gain lives, and the ways to attack the constant are the subject of Cache Behaviour and Node Layout in Disjoint-Set Arrays.

Reading the bound correctly in practice

Three misreadings are common and each leads to a specific mistake.

Treating amortized as worst-case. The α(n) factor is amortized over the whole sequence. A single find can still walk a path of length Θ(log n) before compression catches up, and in a structure that has just been built by a long run of unions with no queries, the first find pays for the whole path. For n = 2^32 and union by rank alone, that is up to 32 pointer hops. On a machine where each hop is a cache miss, 32 misses is a few microseconds, which is fine for a batch job and unacceptable inside a per-packet path.

Assuming the bound survives other operations. The analysis covers find and unite. It does not cover enumeration of block members, splitting a block, or deleting an element, and each of those changes the cost structure entirely. Adding a member list per block turns unite into a list splice, which is O(1) with a tail pointer, but turns enumeration into O(size) and makes the structure’s behaviour depend on block sizes rather than on α.

Assuming the constant is one. The α(n) term multiplies a per-step constant that includes a bounds check, a load, and a compare, and for small n the two heuristics also cost more than the naive chain would. At n = 8, union by rank adds a comparison and a swap to every union, and compression adds stores to every find, while the longest possible chain is seven links. The heuristics pay off when n reaches the thousands, not before. Above that, the array of parent indices outgrows the levels of cache that hold it — 8 bytes per element at n = 10⁶ is about 8 MB — so each hop in a find is a potential miss. Compression reduces the number of hops, which is why it helps more than the analysis alone predicts: it converts a long sequence of dependent loads into a short one.

A useful sanity check when a run takes far longer than the operation count suggests: with both heuristics the operation count for m = n = 10⁶ is a few million link traversals, and at 8 bytes per element the array is about 8 MB. If a run takes orders of magnitude longer than a few million dependent loads would suggest, the cause is almost certainly the memory hierarchy — cache misses per hop, TLB misses across a large array, or a hash map in front of the structure — rather than the algorithm. Reasoning in operation counts cannot explain that gap; reasoning in cache lines, as in Cache Behaviour and Node Layout in Disjoint-Set Arrays, can.

The remaining articles in this cluster take the structure in directions the classical bound does not cover: merging several disjoint-set structures at once in Small-to-Large Merging and the DSU on Trees, undoing unions in Rollback Union-Find and Offline Dynamic Connectivity, and the bit-parallel structures that replace the parent array altogether, beginning with Bitset Representation and Word-Level Rank and Select.

References

  1. Efficiency of a Good But Not Linear Set Union Algorithm — Robert Tarjan, Journal of the ACM 22(2), 1975
  2. Worst-Case Analysis of Set Union Algorithms — Robert Tarjan and Jan van Leeuwen, Journal of the ACM 31(2), 1984
  3. A Linear-Time Algorithm for a Special Case of Disjoint Set Union — Harold Gabow and Robert Tarjan, Journal of Computer and System Sciences 30(2), 1985