Abstract syntax tree 2026-10-13
An abstract syntax tree is a rooted tree recording the meaningful syntactic pieces of a program and how they fit together. A program identifier such as
x, a literal value such as 2, and a node representing addition have different roles. Their arrangement answers structural questions: which program expression supplies an operand, which name is a variable assignment target, and which construct encloses another. This makes an abstract syntax tree useful to a compiler, an interpreter, and the type system that checks a program.The word "abstract" describes what is omitted. Lexical analysis first recognizes lexical tokens, such as
x, =, 2, +, 3, *, 4. A concrete parse tree can retain grammar derivation structure, including punctuation and intermediate context-free grammar categories such as expression, term and factor. An abstract syntax tree usually keeps the operation and its operands without all those grammar scaffolds. Parentheses can determine its shape without surviving as separate nodes. A parser may construct the abstract syntax tree directly; it need not first allocate a concrete parse tree.An abstract syntax tree records programming language syntax, but does not by itself supply all programming language semantics. In
a+b, the names do not reveal their current values, and + might perform addition of integers or concatenate strings. The programming language rules, name bindings, and operand types determine the meaning. In Python, successfully calling ast.parse also does not guarantee that later compilation will accept the result: parsing return 42 succeeds, but compiling that statement outside a function fails. [ref]ast — Abstract syntax trees, Python 3.14 documentation. ast.parse: parsing performs no scoping checks; the return 42 example
An abstract syntax tree is not machine code. Its nodes describe language constructs. A compiler can check and transform this structure before translating it into executable instructions; an interpreter can evaluate an appropriate tree directly. The little evaluator below demonstrates this distinction without pretending to implement an entire programming language.
Binary heap 2026-10-13
A binary heap represents a priority queue as a complete binary tree obeying a heap order. We use the minimum convention: the priority of every parent in a rooted tree is no greater than the priorities of its children in a rooted tree. Equal priorities are allowed. Each stored entry may be a record carrying a priority key; the numerical example below displays only keys. Reversing the inequalities gives the maximum convention.
The complete binary tree can be stored directly in a zero-indexed array : read its levels from top to bottom, left to right. The root of a tree is at index . The possible children in a rooted tree of index are at and , and an index denotes a present entry only when it is less than . For , its parent in a rooted tree is at , using the floor function. Thus the links of the complete binary tree are determined by arithmetic rather than separately stored pointers.
ConsiderThe children in a rooted tree of index have keys ; those of index have keys ; those of index have keys . The six comparisons , , , , , establish the heap order. At index , the parent in a rooted tree is index , carrying key .
The array is visibly not a sorted array: precedes , and precedes . Nor is the last entry a maximum: it is , whereas the maximum is at index . The heap order compares ancestors and descendants, without imposing an order between separate branches. Nevertheless, following the graph path from the root of a tree to any entry gives a chain of nondecreasing priorities. This short argument proves that
peek can return , a minimum, without inspecting the other entries.Insertion appends an entry to the array, preserving the shape of the complete binary tree, then uses sift up to repair the heap order. Insert key into the displayed binary heap. It is appended at index , and exchanges with indices , , then :The moving key follows ; the keys each move down one level. Only this chain needs repair.
Now apply
extract-min. Save key , move the last key to the root of a tree, and shorten the array to length . Use sift down, always choosing the smaller of the present children in a rooted tree:First exchanges with key at index , since ; then with key at index , since . At index , the possible children in a rooted tree would be indices , both outside the shortened array, so the process stops. The returned key is , and the remaining binary heap is exactly the original one.For a nonempty binary heap with entries, the deepest level is , using the floor function and logarithm. Each exchange moves one level and uses only a bounded number of comparisons. The resulting time complexity bounds, expressed in Big O notation, are:
| Operation | Time complexity | Reason |
|---|---|---|
peek | Read the root of a tree. | |
| Insert | for | Append, then sift up through at most the levels of the complete binary tree. |
extract-min | for | Move the last entry, then sift down through at most those levels. |
| Build from an arbitrary array | Apply sift down from the last index with children in a rooted tree back to index . |
These bounds assume constant-cost indexed access, key comparisons and exchanges, and available array capacity for insertion. Allocating and copying a larger array is a separate cost. Empty and one-entry cases take constant work.
To build a binary heap, begin at index and work backwards. Entries without children in a rooted tree already obey the heap order. Each sift down, also called heapify down, starts with every present smaller rooted tree below it already repaired. Most entries are close to the bottom and can move very little; successively longer repair distances occur for geometrically fewer entries. Summing these distances gives work, rather than charging to every entry. MIT's notes give this bottom-up construction and contrast it with repeated insertion.[ref]
https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/40d4851e550507ca14dc778b9b2266cc_MIT6_006S20_lec8.pdf. MIT 6.006, lecture 8: implicit indices, heap repair and linear build, pp. 3–6
The Dijkstra algorithm additionally needs to decrease the priority of an existing vertex when its tentative distance improves. Given its current index, lowering the key followed by sift up takes time for . An indexed binary heap maintains a separate map from item identity to its current index and updates that map after every exchange. For vertices numbered in a fixed range, the map can be another array, giving constant-time index lookup. An ordinary unindexed binary heap supplies no such guarantee: locating an arbitrary item can require scanning entries. Item identity and priority must remain distinct, especially when several vertices have equal tentative distances.
The attractive compromise is local organization with global usefulness. A binary heap maintains only the heap order, yet every
extract-min gives the next smallest key. Repeated extraction of the original example gives , so a priority queue also supplies a sorting algorithm without storing a sorted array between extractions. Binary tree Created 2026-10-13 Updated 2026-10-14
A binary tree, in the data structure convention used here, is a rooted tree in which each vertex has zero, one or two children in a rooted tree, occupying distinct left and right positions. A single left child and a single right child give different binary trees. A vertex with no children in a rooted tree is called a leaf. An empty binary tree has no root of a tree and is also allowed as a storage case. [ref]
For example, give the root of a tree label , its left child label and its right child label . Attach as the left and right children in a rooted tree of , and as those of . This binary tree has seven vertices, six edges, and height of a binary tree : a longest downward graph path contains two edges. The binary search tree lookup illustration below shows this shape alongside the binary tree consisting only of successive right children , whose height of a binary tree is .
Left and right positions specify an ordered shape, not a numerical total order on stored labels. Swapping labels and in the first example still gives a binary tree, but destroys the binary search tree property. Nor must a binary tree be balanced: the right-child chain is just as valid. The same shape convention supports a binary heap, a Huffman code, or a binary search tree, each with its own additional rules. The useful idea is to describe two smaller subtrees at each vertex, making structural recursion natural.
For a precise recursive description, a finite binary tree is either empty or a root of a tree carrying a value together with an ordered pair of disjoint smaller binary trees. The entries of this ordered pair are its left and right subtrees, each of which may be empty. Thus two binary tree child slots exist even when fewer than two children in a rooted tree exist; an empty slot does not denote an extra vertex. This decomposition is the basis of structural recursion.[ref]
4.4 Symbol Tables. Introduction to Programming in Java, section 4.4, Binary search trees: recursive definition and node representation
Left and right binary tree child slots distinguish shapes even with just one child
. Solid circles are vertices; outlined squares mark empty binary tree child slots. The first two binary trees differ only in the occupied slot at . The last two have the same four labels but different height of a binary tree. Details.In the four-vertex mixed example, has left child and right child , while has only a right child . Count its vertices by structural recursion: the empty binary tree contributes zero and each nonempty binary tree contributes one plus the counts of its left and right subtrees. Thus contributes , and contributes . The same decomposition computes height of a binary tree, supports inorder traversal, and supplies short proofs by structural induction. It separates shape from the values stored in a data structure.
Ignoring values, let count finite binary tree shapes with vertices, retaining left and right slots and counting the empty shape once. Splitting at the root of a tree gives the recurrence relationFor each left subtree size , choose its shape and the right subtree shape independently. This yields the Catalan numbers: , , and . The two shapes at are exactly the left-only and right-only examples. Forgetting the slot distinction would change the counting problem.
Bipartite graph Created 2026-09-24 Updated 2026-10-14
A bipartite graph separates its vertices into two independent sets: every edge goes from one part to the other. Here is a finite simple graph and an undirected graph, with no self-loops and no repeated edges. The two parts satisfyThus neither part contains an edge. The parts need not have equal sizes, and some pairs across them may have no edge; requiring every cross pair gives a complete bipartite graph. The independent set and cross-edge definitions are equivalent.[ref]
The Basics (author-hosted chapter preview). Section 1.1, printed p. 3, independent vertices; Section 1.6, printed p. 17, bipartite and complete multipartite graphs
For example, the six-vertex cycle graph with edges has parts and . Drawing the same graph as a hexagon or in two columns changes neither its edges nor its bipartite property. An extra isolated vertex can go in either part.
We allow either part to be empty. Consequently a graph with no edges is bipartite, even when ; choose , . Here "two colours" means two colours are available, with no requirement to use both. This convention explicitly includes the empty case, whereas definitions requiring two nonempty classes need an exception. For several connected components of a graph, choose the two parts separately in each graph component and take their unions. In a nonempty connected graph that is bipartite, fixing one vertex's colour forces all others along graph paths, so its two-colour assignment is unique up to swapping the colours. Each graph component, including an isolated vertex, can be swapped independently.
The two-colourability criterion for bipartite graphs identifies these parts with the colour classes of a proper vertex colouring: assign colour to and colour to , so adjacent vertices have different colours. More surprisingly, the odd-cycle characterization of bipartite graphs turns a global requirement into one precise obstruction:This statement is for the finite undirected graph and simple graph model above; a graph cycle has distinct vertices except for the repeated starting vertex. Along a graph cycle in a bipartite graph, colours alternate, so returning to the starting colour takes an even number of edges. Therefore any odd cycle, whether or not other edges join its vertices, prevents a bipartite split.[ref]
The Basics (author-hosted chapter preview). Section 1.6, Proposition 1.6.1 and proof, printed pp. 17–18
Breadth-first search supplies the converse constructively. Start an uncoloured vertex with colour , and use a FIFO queue to explore its graph component. When an edge first discovers , give the opposite colour to , record as its parent in a rooted tree, and enqueue . If both endpoints of any scanned edge already have the same colour, stop with a conflict. Restart from an uncoloured vertex until every graph component has been examined. If no conflict occurs, all edges cross the two colour classes, which are the required independent sets.[ref]
A conflict also explains the failure. In the rooted tree produced by breadth-first search, let be the graph distance from . The colour of is its distance's integer parity. An edge in an undirected graph satisfies , so equal colours force . Follow the two parent chains upward to their lowest common ancestor , discard the shared graph path from to , and join the remaining two graph paths with the conflict edge . The result is a genuine graph cycle withedges, an odd integer. The two branches have no shared vertices except , so this is more than a closed walk. This odd cycle is a certificate that anyone can check directly, using only its listed vertices and edges.
In the example, breadth-first search from gives , , and . The conflict edge closes the odd cycle , with five edges. The common edge is excluded. Thus the same procedure returns either two independent sets covering , or an explicit odd cycle. With adjacency lists and constant-time FIFO queue operations, its time complexity is in Big O notation, with additional storage.[ref]
The two parts often have a practical meaning: workers and jobs, with an edge exactly when a worker can perform a job. A matching in a graph chooses compatible worker–job pairs with no reused endpoint; merely being bipartite does not guarantee enough compatible pairs. Hall's marriage theorem characterizes when every worker can be matched, and the assignment problem adds costs to seek an optimal assignment. These connections make the bipartite structure useful after recognition, as the starting point for selecting edges under constraints.
Bounding volume hierarchy 2026-10-14
A bounding volume hierarchy is a data structure arranged as a rooted tree: leaves store objects, and each internal node stores a bounding volume enclosing its children in a rooted tree. Consequently, every node encloses all objects in its subtree. A common choice is a binary tree of axis-aligned bounding boxes. The objects assigned to sibling subtrees can be different even when their bounding volumes overlap.[ref]
Here is an exact two-dimensional example. Use the triangles from bounding volume, together with having vertices of a polygon and having vertices of a polygon . Group under , and under . Their parent axis-aligned bounding boxes and the box at the root of a tree areThe diagram shows all seven nodes. Taking the coordinate-wise minimum and maximum of the two child boxes constructs each parent box; the resulting box contains the set union of the children, and can also contain empty space between them.
Four exact triangles, their enclosing boxes, and a seven-node bounding volume hierarchy arranged as a binary tree
. Details. A bounding volume hierarchy traversal starts at the root of a tree and discards a subtree when its bounding volume misses the query. Accepted internal nodes expose their children; accepted leaves supply candidates for actual shape tests. Box2D's official Collision: Dynamic Tree describes axis-aligned bounding box region queries that return overlapping leaf boxes. A query box that bounds a different query shape can produce additional false candidates.
For the closed query rectangleleft-first depth-first search tests the node boxes in order: root, , , , . The first four overlap ; does not, because its smallest -coordinate is . Pruning skips both and . Five box tests leave two broad phase candidates. The narrow phase rejects , since throughout , and accepts : the point belongs to both and . There are two detailed shape tests and one true hit.
An exact rectangle query prunes the right subtree and leaves two box candidates but only one triangle hit
. Details. For a query asking for all intersections, time complexity depends on the number of visited nodes and the cost of each candidate shape test. With fixed dimension and constant bookkeeping cost per node, the work iswhere counts candidate objects and is Big O notation. A balanced binary tree has small height of a binary tree, but a query can enter both children at every level. In this example a query containing visits all seven nodes and tests all four triangles. More generally, a full binary tree with single-object leaves has nodes, so such a query takes work for constant-cost shape tests even when its height of a binary tree is . Listing hits itself requires outputs. Small height alone gives no unconditional logarithmic query bound.
For collision detection between two bounding volume hierarchies, traverse pairs of nodes: reject disjoint pairs of bounding volumes, expand a nonleaf member of an accepted pair, and apply the narrow phase at accepted leaf pairs. A single collection's self-query must exclude pairing an object with itself and avoid duplicate unordered pairs. If every object overlaps every other object, reporting all pairs already requires results. Construction quality, empty space in boxes and the queries determine how much pruning is useful.[ref]
For a short correctness outline, an object is enclosed by its leaf box, and each child box is enclosed by its parent box. Repeated subset relations carry this property to every ancestor. A true query intersection therefore prevents rejection at every ancestor of the object's leaf. Updating leaf boxes after motion also requires restoring all affected ancestor bounds before querying.
Breadth-first search Created 2026-09-24 Updated 2026-10-14
Breadth-first search is a graph search that explores successive layers of graph distance from a starting vertex . Here the graph is an undirected graph on a finite set of vertices, and distance counts edges, with no differing edge weights. Mark as discovered, assign , and place it in a FIFO queue. Repeatedly remove the front vertex and scan its adjacency list. Whenever a graph neighbour is still undiscovered, mark it immediately, record as its parent in a rooted tree in the discovery tree, assign , and enqueue at the rear. Marking on insertion ensures that another edge cannot enqueue the same vertex again. [ref]
https://raw.githubusercontent.com/kevin-wayne/algs4/master/src/main/java/edu/princeton/cs/algs4/BreadthFirstPaths.java. Sedgewick and Wayne, Algorithms: BreadthFirstPaths queue and discovery rule
Use the same undirected graph as depth-first search, with vertex set and edgeswhere denotes the unordered pair . Start at and scan graph neighbours in lexicographic order of their one-letter labels. The diagram's generator computes the following layers and the parent in a rooted tree assigned to each discovered vertex; the source is the root of a tree and has no parent in a rooted tree.
| Graph distance from | Vertices in discovery order | Parent in a rooted tree in the same order |
|---|---|---|
| none | ||
The discovery and removal orders both happen to be . After processing , the FIFO queue is : must be processed before the newer . Processing then skips the already discovered and enqueues , giving . Processing adds nothing. Processing discovers , giving ; later sees already marked and leaves its parent in a rooted tree unchanged. The discovery edges are , forming a rooted tree on all seven vertices even though the original graph contains graph cycles. The discovery tree contains six edges; it need not contain every examined edge.
First arrival is shortest because the FIFO queue keeps assigned distances in nondecreasing order, with entries from at most two consecutive layers. While processing distance , newly discovered vertices receive distance and join the rear. If an undiscovered vertex had a shorter graph path, its preceding vertex on that graph path would lie in an earlier layer and would already have discovered it. Thus is the minimum number of edges from to . This is a mathematical induction over the layers, not an assumption about the drawing. Following the parent in a rooted tree backwards at each step gives ; reverse that sequence to obtain the three-edge graph path . is another shortest graph path, but the specified graph neighbour order makes discover first. Changing that order can change the parent in a rooted tree without changing graph distances. [ref]
https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-fall-2011/1208e162775f6f5cedfbb9f2b694ede0_MIT6_006F11_lec13.pdf. MIT 6.006, lecture 13: distance layers and shortest paths, pp. 4–6
The shortest-route guarantee concerns the shortest path problem measured by edge count. It also minimizes total cost when every edge has the same positive cost. With unequal edge weights, first discovery need not minimize total cost; nonnegative costs can instead be handled by the Dijkstra algorithm. Breadth-first search is useful for minimum-hop routes and for finding all vertices within a specified graph distance. Its FIFO queue finishes an older layer before the next one, whereas depth-first search uses a call stack or explicit LIFO stack to pursue one branch immediately.
With adjacency lists and constant-cost discovery checks, together with constant worst-case or amortized analysis cost for FIFO queue insertion and removal, the time complexity is in Big O notation. Every reached vertex is enqueued and removed once, each incident edge is scanned at most twice in an undirected graph, and initializing all marks and distances takes . The FIFO queue contains at most vertices; the example's maximum is three. Discovery marks, distances and the recorded parent in a rooted tree for each nonroot vertex also give auxiliary space complexity, excluding the graph. An array that shifts every entry on front removal can lose the linear time complexity; the FIFO queue abstraction alone does not make removal constant-cost. Ordering the adjacency lists is a separate preprocessing cost.
A single start reaches only its connected component of a graph. Unreached vertices retain distance and have no recorded parent in a rooted tree. Restarting at each still-undiscovered vertex, while preserving all discovery marks, produces a forest covering the graph; each new root of a tree gets distance zero, so these distances refer to that root of a tree, not to the original .
Depth-first search 2026-10-13
Depth-first search is a graph search that follows a branch as far as it can before returning to try the next unexplored branch. Starting at a vertex of an undirected graph on a finite set of vertices, mark as discovered. Scan its graph neighbours in a fixed order: for each undiscovered vertex, record the current vertex as its parent in a rooted tree in the discovery tree, mark the new vertex, and explore it immediately using recursion. Return when its adjacency list is exhausted. Discovery marks persist after return, preventing a graph cycle from causing repeated exploration. This branch-and-return rule is the maze exploration described in MIT's notes. [ref]
Use the same unweighted undirected graph as breadth-first search, with vertex set and edgeswhere denotes the unordered pair . Visit graph neighbours in lexicographic order of their one-letter labels, starting at . The discovery order, computed by the diagram's generator, isThe discovery edges in order are . They form a rooted tree spanning the reached vertices, with root of a tree . The other edges, and , remain in the original graph but never discover a new vertex. In particular, the graph cycle causes no repeated discovery.
At there is no undiscovered graph neighbour, so its call returns to . The next call enters , then , then , then . Immediately after discovering , the call stack is , with on top; is still discovered but its call has finished. The maximum call stack depth is six, although seven vertices are discovered. Following the recorded parent in a rooted tree backwards at each step reconstructs a graph path; here the route from to is , using five edges. Breadth-first search instead finds , using three edges. Depth-first search establishes reachability but does not guarantee the fewest edges.
An explicit LIFO stack can replace recursion, but its entries and discovery rule must be specified. To reproduce this exact traversal, store one frame per active vertex, retaining the next position in its adjacency list. Advance the top frame by one graph neighbour; if that vertex is undiscovered, mark it and push its frame immediately; pop an exhausted frame. Pushing all undiscovered graph neighbours at once and marking them on push is a different iterative variant. Even pushing them in reverse lexicographic order does not generally reproduce the parent in a rooted tree relationships above: would already be marked while processing , so could not discover .
With an adjacency list representation, constant-cost discovery checks and frame operations, and the graph neighbours already ordered, depth-first search has time complexity in Big O notation. Each reached vertex is entered once and each incident edge is examined at most twice in an undirected graph; initializing all discovery marks costs . The call stack has depth at most , since no active vertex repeats. Discovery marks and the recorded parent in a rooted tree for each nonroot vertex also need auxiliary space complexity, excluding storage for the graph. Sorting adjacency lists to obtain a chosen order is additional work. [ref]
https://raw.githubusercontent.com/kevin-wayne/algs4/master/src/main/java/edu/princeton/cs/algs4/DepthFirstPaths.java. Sedgewick and Wayne, Algorithms: DepthFirstPaths discovery marks and resource bounds
One start explores only its connected component of a graph. To cover a disconnected graph, start again at every still-undiscovered vertex while keeping all discovery marks; the discovery trees form a forest. Depth-first search is useful for reachability, constructing a spanning tree of a connected graph, and organizing the return steps needed by a depth-first traversal of a tree. For detecting a graph cycle in a simple graph that is an undirected graph, an edge to an already discovered vertex other than the current parent in a rooted tree closes a graph cycle; the immediate return edge to that parent in a rooted tree is not itself a graph cycle.
// Target: computer-science.bigb
DFS discovery time 2026-10-14
The DFS discovery time of a vertex is its first-visit number in depth-first search, assigned by an increasing counter. Discovery edges form a rooted tree in each connected component of a graph. For the joined- example, starting at and visiting graph neighbours in lexicographic order gives first visits , numbered ; its discovery edges are . These numbers encode the chosen traversal, not an invariant of the graph.
DFS lowpoint 2026-10-14
For a finite simple graph that is an undirected graph, the DFS lowpoint of is the smallest DFS discovery time reachable by following zero or more discovery edges down its rooted tree, then at most one non-discovery edge to an ancestor. Staying at is allowed. Ignore the reverse traversal of the discovery edge to the parent in a rooted tree: it is the same edge, not an escape route. Start with . On returning from a child in a rooted tree , replace by . For a non-discovery edge from to an earlier ancestor , replace it by . This summarizes how far upward the explored branch can reconnect. [ref]
https://sites.cs.ucsb.edu/~gilbert/cs240a/notes/TarjanDFS.pdf. Tarjan (1972), §3, LOWPT recurrence, pp. 151–153
The cut vertex criterion has a separate case for each root of a tree in the discovery forest:
- A nonroot vertex is a cut vertex exactly when some child in a rooted tree satisfies .
- A root of a tree is a cut vertex exactly when it has at least two children in a rooted tree, counting discovery edges, rather than all graph neighbours.
- A discovery edge is a bridge in a graph exactly when . A non-discovery edge is never a bridge in a graph.
Why does equality matter? If , the branch below can reconnect to , so the discovery edge lies on a graph cycle and is not a bridge in a graph. Deleting the vertex destroys that reconnection too. If has a parent in a rooted tree, the branch is then separated from that parent in a rooted tree, explaining the non-strict cut vertex test. For a root of a tree, there is no earlier side to separate from; distinct discovery branches cannot have an edge between them, since depth-first search would have explored them as one branch. This gives the two-children in a rooted tree rule. These are proof outlines of the criteria. [ref]
https://algs4.cs.princeton.edu/41graph/Biconnected.java.html. Sedgewick and Wayne, Biconnected.java: discovery, lowpoint and root tests
[ref]In the joined- example with DFS discovery times , the DFS lowpoints in label order are . For and its child in a rooted tree , : is a bridge in a graph, and is a cut vertex. For and its child in a rooted tree , : is a cut vertex, although is not a bridge in a graph. The root of a tree has only one child in a rooted tree, , so it is not a cut vertex. In the shared- example, the root of a tree has two children in a rooted tree, and , and is a cut vertex, while every DFS lowpoint is and no edge passes the strict bridge in a graph test.
Restart depth-first search at every undiscovered vertex to cover a disconnected graph, applying the root of a tree rule separately in each connected component of a graph. With adjacency lists and constant-cost label operations, computing all DFS lowpoints, cut vertices and bridges in a graph has time complexity in Big O notation, because each vertex is discovered once and each edge is inspected twice. The simple parent-skipping rule assumes a simple graph. In a multigraph, skip only the actual parent edge, identified individually: a parallel edge to the same parent in a rooted tree is a valid reconnection and can prevent the first edge from being a bridge in a graph. The criteria here concern undirected graphs; a directed graph requires a different connectivity analysis.
Disjoint-set forest 2026-10-18
A disjoint-set forest represents each block of a set partition by a rooted tree. Each set element stores a pointer to its parent in a rooted tree; the root of a tree stores a pointer to itself as a stopping convention. These self-pointers are sentinels, omitted from the forest's edges. Following parent pointers reaches the disjoint-set representative, the root of a tree. An indexed array
parent suffices when members are numbered consecutively. The rooted trees encode membership; their edges need not be edges of any input graph.To link different blocks of a set partition, point one root of a tree at the other root of a tree. Linking roots preserves every old membership and joins exactly the two rooted trees. Arbitrarily reparenting a nonroot could detach only part of a block of a set partition, so it would not implement the required disjoint-set union operation. The disjoint-set find operation terminates because each nonroot pointer moves towards the unique root of a tree; linking distinct roots cannot introduce a graph cycle.
Exponential generating function Created 2026-10-07 Updated 2026-10-14
An exponential generating function encodes a sequence using . For labelled counting, is the number of structures on a fixed set of distinct labels. Labels distinguish otherwise similar objects: changing which person belongs to a group can change the structure. Recover the count by coefficient extraction as . The raw coefficient is , not .
The factorial makes multiplication account automatically for distributing labels. To combine an -structure on labels and a -structure on the remaining , choose the first label subset in ways, then choose the two structures. The binomial coefficient counts how the two groups of labels interleave within the full label set. ThusThe normalization works because . This explains the usefulness of exponential generating functions for labelled counting: an ordinary Cauchy product would omit the choices of labels. See Peter Magyar, Math 482, notes for 2/7, labelled product principle.
For a concrete example, there is one undecorated set on any given collection of labels. Its exponential generating function is the exponential function . Combine a red set and a blue set, allowing either to be empty:Every label independently receives one of two colours, giving assignments by the rule of product. With three labels, the counts by number of red labels are , totalling eight. Choosing only the two group sizes would give the four possibilities ; it would forget which labels are red.
Indeed, the ordinary generating function for the constant sequence is the geometric series . Its square has coefficient , counting pairs of nonnegative sizes. Both encodings are correct for their respective questions. The decision is whether identity matters when objects are combined.
For unordered sets of labelled components of positive size, an exponential generating function becomes : the term forgets the ordering of components. The existing rooted-tree generating function develops the richer example . A labelled rooted tree consists of its root of a tree and an unordered set of smaller labelled rooted trees, connecting the same label-distribution mechanism to recursive counting.
Factorization tree 2026-10-14
A factorization tree is a rooted tree whose root is an integer . Each nonleaf label is a composite number split into two factors greater than one whose product equals that label; the leaves are prime numbers. Multiplying the leaves recovers . Many factorization trees can have the same root, but the fundamental theorem of arithmetic gives them the same leaf multiset.
Fourth-order conditions for a Runge-Kutta method Created 2026-10-05 Updated 2026-10-14
With and , a Runge-Kutta method has order at least four exactly when the eight Butcher order conditionshold; powers of are componentwise. These conditions match the numerical and exact coefficients indexed by rooted trees through order four. Matching the scalar Dahlquist test equation alone is insufficient to check the nonlinear Butcher order conditions.
Friedman's finite form of Kruskal's theorem 2026-10-06
For every natural parameter , there is a finite length such that every sequence of finite rooted trees satisfying has an earlier tree homeomorphically embedding into a later tree. It is a true finite-combinatorial principle unprovable in Peano arithmetic and in arithmetical transfinite recursion theory. Each fixed-parameter instance can still be verified by a sufficiently large finite search.
Homeomorphic embedding of a rooted tree Created 2026-10-06 Updated 2026-10-07
For finite rooted trees in the ancestor partial order, a rooted-tree homeomorphic embedding is an injective vertex map preserving lowest common ancestors: . The image of the source root need not be the host root. Edge paths and branching are preserved, while paths may be subdivided in the larger tree.
Interpreter arithmetic trace 2026-10-14
Use the compilation arithmetic example with input . An abstract syntax tree interpreter first reads
x, obtains , forms , and finally computes . Interpreting the folded abstract syntax tree skips the addition but gives the same result. The compiled stack machine instructions instead produce the following trace; the top of the stack is written on the right:instruction stack after instruction
initial []
LOAD x [7]
PUSH 5 [7, 5]
MUL [35]
PUSH 4 [35, 4]
SUB [31]Execution of
. Details. x*(2+3)-4 at : the original abstract syntax tree and the folded stack machine instructions both give The order in
SUB is essential: reversing its two popped operands would give . The same stored instruction sequence works for input , yielding , without repeating parsing or constant folding. An abstract syntax tree interpreter can likewise reuse its already-parsed tree. Reusing a representation is therefore useful to both approaches; it does not itself distinguish compilation from interpretation.The pleasing part is that a nested rooted tree and a flat instruction sequence express the same computation. The structural induction in the compilation arithmetic example connects them by a precise stack property. This tiny language always terminates and has no side effects; richer programming language semantics require a correctness argument that also accounts for failures, externally visible actions, and possible nontermination.
Kruskal component merging 2026-10-18
A disjoint-set data structure stores the current partition of a set of vertices into connected components of a graph. The operation returns a representative of the block containing . Two vertices are in the same block exactly when their representatives agree. For each candidate edge , compare and . Equal representatives mean reject; different representatives mean accept and perform , merging the two blocks. The representatives are bookkeeping choices, not preferred vertices of the minimum spanning tree.
Connected components of a graph merge only when an edge is accepted
. The same example as a disjoint-set data structure ledger. Each coloured band is one block of the current partition of a set. The rejection of leaves both the partition of a set and the running cost unchanged. Bands show membership, not internal representative pointers. Details.Every acceptance reduces the connected component of a graph count by one and increases the accepted edge count by one, preserving . Thus the ledger reaches exactly when . Only ten representative queries and four merges are needed for the five examined edges, counting two queries per examination and using the already found representatives for each merge. Neither breadth-first search nor reconstruction of a graph path is needed for these connectivity queries.
For and , comparison sorting algorithm takes time for , using Big O notation. One simple disjoint-set data structure implementation stores each block as a rooted tree and attaches the smaller block's root below the larger block's root. Whenever a vertex's depth increases, its block size at least doubles, so its depth is at most . Consequently each representative query or merge takes time. Initialization plus the scan costs ; including sorting algorithm gives , hence for a connected input with . These are operation bounds, not measured timings.[ref]
WeightedQuickUnionUF.java. Robert Sedgewick and Kevin Wayne, Algorithms, 4th edition, companion WeightedQuickUnionUF.java: class documentation and union method; union by size without path compression, linear initialization and logarithmic operations










