Adaptive Euler step doubling for exponential decay Created 2026-10-14 Updated 2026-10-14
Consider the nonstiff scalar initial value problem , , on . Its exact solution is the exponential decay . Use step-doubling error estimation with the explicit Euler method: from the same numerical starting value , form one coarse step and two half steps giving :Accept when the absolute and relative error tolerances test passes, with . There is no Richardson extrapolation in the accepted value. Both approximations have order of a numerical method one, while this local error estimator has step exponent . Consequently the adaptive step-size controller uses a square root, not a cube root:Start with . A rejected trial retains both and , caps at one, and retries. A zero estimate uses . Before every trial, cap at . Stop with a failure if floating-point arithmetic gives , or after 100000 trials. These rules specify the example completely; they are not a prescription for every ordinary differential equation solver.
Adaptive two-half-step Euler decay: exact and numerical trajectories, accepted step sizes and rejected trials
. Details. The first two trials, and , have and and are rejected. The next trial has and and is accepted. For positive decreasing numerical values, , so the local error estimator givesWhen the relative term dominates, this suggests nearly constant accepted steps, approximately . When falls below the crossover size , the absolute term increasingly permits longer steps. The sharp final decrease in only lands on ; it does not indicate a sudden loss of smoothness.
The actual signed local defect from the same numerical input isHere is Big O notation, obtained from Taylor's theorem for the exponential function. Thus agrees with the leading term as , but is not identical to . At , , the estimate is while the actual local defect is . Their closeness improves for the smaller accepted steps. Had we added using Richardson extrapolation, the accepted formula would instead be , of order of a numerical method two; the same raw difference would still scale as and would not estimate that improved value's leading defect.
Estimated versus actual local Euler defects, rejected trials, and actual accumulated global error scaled by the local tolerance
. Details. The global error obeys an exact recurrence relation involving the actual local defects:Each previous global error contracts, yet the local defects keep adding. In the plotted run, 101 steps are accepted and two trials are rejected. Every accepted is at most approximately , while the largest is approximately . At , the numerical value is approximately , compared with the exact , giving absolute error approximately . The right-hand plot deliberately scales actual global error by the same used for local acceptance; it is not a new global error tolerance test.
Tightening both absolute and relative error tolerances by a factor ten gives 315 accepted steps and endpoint absolute error approximately ; tightening both by a factor one hundred gives 991 accepted steps and endpoint absolute error approximately . This is a convergence comparison for this particular initial value problem. The endpoint error decreases by about a factor three per tenfold tightening, rather than by ten: a first-order Euler method accumulates defects across many steps, while its local error estimator varies quadratically with . A variable-step global ODE error bound needs propagation information as well as accepted local tests.
The absolute stability boundary remains a separate constraint. On the Dahlquist test equation with , the accepted two-half-step formula has stability function . It strictly damps perturbations only for . Its local error estimator is , which can pass an absolute-tolerance test at tiny even outside this damping interval. In a stiff two-mode linear system, a fast mode can therefore constrain the step long after its visible amplitude has become small. An adaptive step-size controller does not turn an explicit Euler method into an A-stable method. Official solver documentation likewise distinguishes explicit Runge-Kutta methods for nonstiff problems from implicit Runge-Kutta methods and backward differentiation formulas for stiff equations.[ref]
scipy.integrate.solve_ivp. solve_ivp, method parameter: explicit versus implicit methods and stiffness
Adjacency list storage and query costs 2026-10-14
Write and . Suppose each vertex identifier, list descriptor, link and optional edge weight occupies a constant number of machine words, and indexed array access and identifier comparison take constant time. There are list descriptors and directed, or undirected, neighbour entries. Hence adjacency lists use machine words in Big O notation. A full adjacency matrix has entries, regardless of . These are counts under a storage model, not fixed byte sizes.[ref]
Recitation 19: Graph Representations and Traversals (Cornell course page). Recitation 19, The Adjacency List and The Adjacency Matrix: directed and undirected entry totals, linear list storage, and quadratic full-matrix storage
Our undirected example has six list descriptors and fourteen neighbour entries, versus thirty-six full adjacency matrix entries. The numbers and count different kinds of logical items: they do not prove a particular byte saving. A linked list also needs links; an array may have unused capacity. Storing only half of a symmetric matrix changes its exact count while leaving quadratic growth. If identifiers or weights require growing numbers of machine words, their size must be included in the space complexity.
An unsorted adjacency list answers "does the edge exist?" by linear search through . In the worst case it inspects all entries, giving time, or for . Even if is absent, an uninspected entry could still contain it, so arbitrary lists require the whole scan. On our example, looking for in 's list compares with and fails after three comparisons. A full adjacency matrix instead answers from its single entry in time.[ref]
Recitation 19: Graph Representations and Traversals (Cornell course page). Recitation 19, The Adjacency List: edge-membership question; The Adjacency Matrix: constant-time edge-existence query
Different promises change the query. A sorted array of neighbour identifiers permits binary search in time, but maintaining order after insertion may require shifting entries. A per-vertex hash table permits expected constant-time membership under the hashing and load assumptions of that data structure; it does not give that guarantee to an arbitrary adjacency list. A stored list length can likewise make a vertex degree query constant-time even though neighbour enumeration still has to visit its entries.
The advantage grows with scale. For a graph path on vertices, , so there are undirected neighbour entries and descriptors, versus full adjacency matrix entries. Such a family is a sparse graph with . For a complete graph, , so the undirected neighbour entries already number : the adjacency list advantage in growth rate disappears. Choose by the workload: following existing edges favours adjacency lists; many arbitrary pair-membership queries can favour a full adjacency matrix. The representation organizes the same graph for different questions.
Amortized analysis Created 2026-10-14 Updated 2026-10-18
Amortized analysis bounds the total cost of every permitted sequence of operations from a specified initial state. An amortized bound means that some constants satisfy for every such sequence of length . The cost model and allowed operations are part of the claim; Big O notation alone does not specify them.
- A worst-case bound for one operation limits its cost in any reachable state. Summing these separate maxima can overestimate the cost of a whole sequence because expensive states may take many cheap operations to rebuild.
- An amortized analysis limits the total over every allowed sequence, including an unfavourably chosen one. Dividing that bound by the number of operations is a deterministic guarantee about the sequence.
- A probabilistic average-case analysis bounds an expected value under a stated probability distribution on inputs. For a randomized algorithm, an expected value can instead average over its random choices. Neither interpretation is required by a deterministic amortized analysis.
This distinction, and the credit and potential method viewpoints, are developed in R. Endre Tarjan's 1985 paper Amortized Computational Complexity, sections 1–2, pp. 306–308. The dynamic array doubling example below shows how an expensive operation can pay for itself through the cheap operations that precede it.
The direct divisor summatory function formula evaluates floor divisions. Its balanced Dirichlet hyperbola method formula evaluates floor divisions and reuses their sum for the other strip, followed by doubling and square-overlap subtraction. Thus it uses arithmetic operations, with big O notation, in a model that counts each division, addition and multiplication as one operation. At , the division counts for these two formulas are and .
The balanced Dirichlet hyperbola method reduces floor divisions from to ; for , two sequences of partial sums reach the same exact answer 35
. Details. For a general Dirichlet convolution, the asymmetric formula has outer terms; evaluating and has an additional cost. Under , equal thresholds minimize , but an asymmetric split can be useful if the two partial sums have different evaluation costs. The balanced divisor summatory function gains the further reuse because its two arithmetic functions are identical.
These are arithmetic operation counts, rather than counts of elementary operations on binary digits: the integers grow with , and division of longer integers costs more in that model of computational complexity theory. Computing also requires an exact integer square root, or checking and correcting a numerical square root until holds.
Array (data structure) 2026-10-13
A data structure storing entries at numbered positions, usually starting at index zero. The fixed-capacity representation considered here puts equal-sized slots consecutively in computer memory. The number of occupied slots can be smaller than the capacity; unused slots provide room for later entries. An array of references stores consecutive references, while the objects they identify can be elsewhere. [ref]
https://opendatastructures.org/ods-java/2_Array_Based_Lists.html. Pat Morin, Open Data Structures, chapter 2: array-based lists
Let the first slot have abstract address and each slot occupy address units. Then indexed access computesFor toy values , , the slots for start at ; index goes directly to through . These are illustrative slot addresses, not observed allocation addresses. Under the word-RAM (random-access machine) model for time complexity, word-sized arithmetic operations and any addressed computer memory access have constant cost, and the addresses and entries fit in words. Thus one array access takes time in Big O notation, independently of the index. This is the access assumption needed by binary search. [ref]
https://opendatastructures.org/ods-java/1_4_Model_Computation.html. Pat Morin, Open Data Structures, section 1.4: the word-RAM model
Inserting after in an array holding with one unused slot produces : first copy from slot to slot , then write into slot . Writing first would lose unless it had been saved separately. More generally, insert at index by copying occupied slots from right to left, then fill the gap; with spare capacity this moves entries and takes time in Big O notation, so insertion near the middle has time complexity. Removing an entry closes the gap by shifting later entries left. [ref]
https://opendatastructures.org/ods-java/2_1_ArrayStack_Fast_Stack_O.html. Pat Morin, Open Data Structures, section 2.1.1: indexed access and shifts
A fixed-capacity array cannot accept another entry when full. A resizable representation can allocate a larger array and copy the entries. Doubling capacity when full gives append cost by amortized analysis over a sequence starting empty, but a single append that copies entries still has worst-case time complexity. The outline is a geometric series: copied capacities sum to , less than twice the number of appends that triggered the last copy. Middle insertion still pays for its shifts. [ref]
https://opendatastructures.org/ods-java/2_1_ArrayStack_Fast_Stack_O.html. Pat Morin, Open Data Structures, sections 2.1.2–2.1.3: resizing and amortized costs
Asymptotic analysis 2026-10-14
Asymptotic analysis describes what remains dominant as an argument approaches a specified limit. It compares functions or sequences by scale: how much of a complicated expression can be replaced by a simpler one, and how large is the omitted part? The limit may be for a growing input or for a shrinking approximation parameter.
For example, is eventually dominated by its quadratic term, since division by gives . But at , the linear term contributes , compared with only from the quadratic term. A statement about the limiting scale and a good approximation at a particular input are different claims.
Three useful comparisons keep their strengths distinct. Big O notation supplies an eventual upper bound up to a constant multiplier; big theta notation supplies both an upper bound and a lower bound up to constants; asymptotic equivalence makes the ratio tend to one. Little o notation says that a term becomes negligible relative to a specified scale. These distinctions make approximations checkable instead of merely calling one expression small.
The same language connects time complexity with Taylor remainders. In an operation-count model, one asks how a cost scales with input size. In a Taylor expansion, one asks how the approximation error scales with the increment. Neither use requires interpreting the unspecified constant as one. The asymptotic comparison of exponential functions gives another example: dividing by the largest contributing exponential reveals the terms that disappear.
Asymptotic equivalence Created 2026-09-24 Updated 2026-10-14
For functions with nonzero sufficiently near a specified limit,The same definition applies to sequences as . Equivalently, : replacing by has a relative error tending to zero, and the difference is in little o notation. The limit and reference scale are essential parts of the statement.
For example, because . Replacing the former by the latter gives absolute error , which grows without bound. Thus asymptotic equivalence controls a ratio, rather than requiring the absolute error to vanish. This distinction is crucial when approximating a rapidly growing factorial with Stirling's formula.
By contrast, and have the same order in big theta notation, but are not asymptotically equivalent: their ratio remains two. For positive functions, asymptotic equivalence gives both-sided constant bounds eventually, whereas constant bounds alone do not recover the leading coefficient.
For a local example with real , the exponential function obeys as . The Taylor theorem with Lagrange remainder givesThus for ,This states in big O notation, and division by shows that the relative difference measured against vanishes. The diagram uses positive ; the bound is valid on both sides of zero. At , the absolute error is approximately and the relative difference against is approximately .
Barycentric interpolation formula 2026-10-14
The barycentric interpolation formula evaluates the same Lagrange polynomial using weights that depend only on the distinct interpolation nodes:At , return directly, before dividing; the formula has removable singularities at the interpolation nodes. Multiplying every by the same nonzero constant leaves the answer unchanged. Driscoll and Braun derive this formula as a more efficient, numerically stable way to evaluate polynomial interpolation.[ref]
For the interpolation nodes , the weights are , or equivalently . With data , at the denominator using the latter weights is and the numerator is , giving again. For eleven interpolation nodes in the Runge phenomenon figure, the generator computes the weights by the direct products above and returns stored values exactly at every interpolation node.
The direct products require arithmetic operations once; each subsequent value uses arithmetic operations. Here denotes Big O notation. At large polynomial degree or on poorly scaled intervals, forming these products can exceed the range of floating-point arithmetic; normalization or specialized weight formulas may be needed. Stable evaluation also cannot cure sensitivity intrinsic to the chosen interpolation nodes, measured by the Lebesgue constant of interpolation, or the approximation failure in the Runge phenomenon.
Bellman-Ford algorithm Created 2026-10-14 Updated 2026-10-18
The Bellman-Ford algorithm solves the single-source shortest path problem in a finite directed graph with finite real edge weights, allowing negative weights. It repeatedly applies edge relaxation, so an improved tentative distance can improve its neighbours on a later visit. This makes it a label-correcting shortest-path algorithm.[ref]
BellmanFordSP.java. Algorithms, 4th edition by Robert Sedgewick and others; Robert Sedgewick and Kevin Wayne, BellmanFordSP.java, signed-weight single-source solver and queue-based relaxation
If no negative-cost directed cycle is reachable from the source, at most complete passes suffice for all distances; a further check detects a reachable negative-cost directed cycle.[ref]Lecture 17: Shortest Paths III: Bellman-Ford. 6.006 Introduction to Algorithms, Fall 2011 by Massachusetts Institute of Technology, 6.006 course staff; MIT 6.006, Lecture 17, pp. 3–4: complete-pass algorithm, proof and reachable-cycle corollary
There are two orientations to keep distinct. The usual single-source problem asks for distances from , extending routes along outgoing directed edges. The Bellman inequalities above instead concern distances to a sink , prepending incoming directed edges to known routes. The All-to-one Bellman-Ford recurrence below preserves that convention. Reversing every directed edge, with its weight unchanged, converts one problem into the other.
Here is an original single-source example with source , vertex set , and precisely these directed edges:The negative edge is harmless: this directed graph has no directed cycle. Its best route to is , of cost . The other routes to cost through and through .
Initialize and the other tentative distances to . In each pass apply single-source edge relaxation, , scanning in the order , , , , , . Skip a candidate with . The figure records labels after each complete pass and uses current labels immediately: it is an in-place trace. In pass 2, still uses , giving ; only later does lower to . Pass 3 carries that improvement to , and pass 4 carries it to . The final labels in order are ; the final shortest-path predecessors are for respectively.
The scan order explains the delay. Scanning instead as , , , , , gives those same final labels in just one in-place pass. The Synchronous Bellman-Ford recurrence has a precise bound on the number of edges used by a recorded route; an in-place pass can propagate along several edges and need not have that interpretation. Both implementations have the pass guarantee under the stated no-reachable-negative-cycle hypothesis.
With a stored list of edges, complete-pass Bellman-Ford algorithm has time complexity and uses extra space for labels and shortest-path predecessors, using Big O notation and constant-cost arithmetic. The extra accounts for initialization even when is empty. A pass with no strict decrease permits early termination. A queue variant instead revisits outgoing edges of vertices whose labels improved; the authored implementation provides this alternative and has worst-case running time on its usual nontrivial instances.[ref]
BellmanFordSP.java. Algorithms, 4th edition by Robert Sedgewick and others; Robert Sedgewick and Kevin Wayne, BellmanFordSP.java, class documentation, constructor and relax method
For nonnegative weights, the Dijkstra algorithm and its existing distance-frontier figure explain how permanent labels can avoid these repeated passes; the existing edge relaxation figure illustrates one update at a time. Big omega notation 2026-10-25
For real-valued functions on the natural numbers, means that constants and satisfy for every . This is an eventual lower bound on magnitude. In algorithm analysis the functions are usually nonnegative, so the absolute values can be omitted. Together with the upper bound of big O notation, it gives big theta notation. This is the algorithmic lower-bound convention for , rather than a convention expressing only a positive limit superior along a subsequence.
Big theta notation 2026-10-14
At the specified limit, big theta notation means that two positive constants give both-sided bounds:sufficiently near the limit. Equivalently, and in big O notation. In operation-count analysis, for , using and . This supplies a tight scale without asserting that the normalized ratio tends to one.
For an example with no limiting ratio, let for positive integers . Then , so , but alternates between one and three. A tight growth order is therefore weaker than asymptotic equivalence. The constant bounds also do not fix an exact factor by which a function changes when its argument doubles.
Donald E. Knuth's 1976 paper proposes using for two-sided constant bounds in algorithm analysis. He credits Bob Tarjan and Mike Paterson with independently suggesting the notation. His discussion gives a concrete motivation for distinguishing an eventual upper estimate from a tight comparison. [ref]
https://danluu.com/knuth-big-o.pdf. Knuth, Big Omicron and big Omega and big Theta, 1976, pages 19–20
Binary heap Created 2026-10-13 Updated 2026-10-24
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 powering multiplication count Created 2026-10-14 Updated 2026-10-24
For the optimized left-to-right exponentiation by squaring algorithm, let be the length of the binary expansion of a positive integer , and let be its Hamming weight, the number of digits equal to one. There are exactly digits after the leading one, and exactly remaining ones. Therefore the count isHere counts squarings and counts further multiplications by the base; every squaring counts as one multiplication in . Assignment, digit reading, and any inversion are outside this count. The formula includes , which requires zero multiplications; define separately.
For a fixed length , the bounds are . A power of two reaches the lower bound because its Hamming weight is one; reaches the upper bound because all digits are one. For , and , giving . Thus the arithmetic operation count is in Big O notation, but inputs of similar magnitude can have different counts.
Exact multiplication counts for optimized exponentiation by squaring depend on binary length and Hamming weight
. For positive exponents through , dots show , including each squaring. The dashed curves bound all counts at each binary length. Successive multiplication needs operations. The second panel compares squarings and further multiplications for exponents . These are exact counts, not timing measurements. Details.This is a count for the specified algorithm, not a claim that it always minimizes multiplications among all methods. For instance, at the count is six, but the powers with exponents can be built in five multiplications: square, multiply by , square, square, then multiply by the already stored . Saving operations this way uses a different schedule and stored intermediate powers.
Binary search tree Created 2026-10-13 Updated 2026-10-14
A binary search tree stores key-value entries in a binary tree, with distinct keys drawn from a total order. At every vertex, all keys in its left subtree must be smaller than its own key, and all keys in its right subtree must be larger. Thus the entries represent a partial function from keys to values: a key has at most one associated value and may be absent. [ref]
Lookup starts at the root of a tree. Compare the target with the current key: equality returns its value, a smaller target continues into the left subtree, and a larger target continues into the right subtree. Reaching an empty subtree reports absence. The ordering rule justifies discarding the other subtree at every step; this is the algorithm correctness argument for lookup. It applies to the entire subtree, even if that subtree contains many vertices. [ref]
In the seven-key example, search for . At , the comparison selects the right subtree; at , selects the left subtree; at , equality ends the search. The visited keys are , three key comparisons. The right-child chain stores exactly the same keys and satisfies the same binary search tree rule, but lookup of visits , five comparisons. Searching for absent key visits in the first binary search tree and all seven keys in the chain before reaching an empty right subtree.
Lookup of key in two binary search trees containing the same seven keys
. Orange highlights visited keys and edges; green marks the match. The balanced shape has height of a binary tree and requires three visits, while the chain has height of a binary tree and requires five visits for this target. Details.For a nonempty binary search tree of height of a binary tree , lookup inspects at most vertices. Under constant-cost key comparisons and child-reference access, its time complexity is in Big O notation, usually written for . With entries, , giving worst-case lookup. If the shape is kept balanced so that , lookup takes for . The empty and one-entry cases take constant work. The worst-case linear bound also appears in Sedgewick and Wayne's ordinary, unbalanced implementation. [ref]
https://raw.githubusercontent.com/kevin-wayne/algs4/master/src/main/java/edu/princeton/cs/algs4/BST.java. Sedgewick and Wayne, Algorithms: BST implementation, complexity contract and get method
In a shape with every level full, there are vertices, a geometric series. This explains how a small height of a binary tree can accommodate many entries. The binary search tree ordering rule alone does not guarantee this shape or logarithmic time complexity. Breadth-first search also gains no logarithmic key-lookup guarantee merely from having a binary tree: in the displayed balanced example, its left-to-right level order is , so it inspects six keys before finding , and an absent target requires all seven. Directed lookup uses the total order to choose one branch.
The ordering requirement includes every ancestor on the graph path from the root of a tree. Consider the smaller binary tree with root key , left child , right child , and right child under . Key must satisfy both , from its immediate parent in a rooted tree, and , from its position in the root's left subtree. Replacing by preserves all immediate parent-child comparisons, including , but violates . Lookup for would incorrectly go from to and then to an empty left subtree, overlooking the stored key.
The binary search tree ordering rule constrains an entire subtree
. The valid example has . The invalid example passes immediate parent-child comparisons, but key lies in the left subtree of key and violates its inherited upper bound. Details.An inorder traversal visits a left subtree, then its own vertex, then a right subtree. On the valid small example its output is ; on the invalid example it is , exposing the descent from to . Both seven-key binary search trees yield . The theorem is that an inorder traversal of a finite binary search tree with distinct keys lists every key once in strictly increasing total order. For a short proof outline, use mathematical induction on the number of vertices: each smaller subtree produces its own sorted list, and the full ordering rule places every left key before the current key and every right key after it. Concatenating these three parts preserves strict order. Sedgewick and Wayne's
keys method uses this left-current-right order. [ref]https://raw.githubusercontent.com/kevin-wayne/algs4/master/src/main/java/edu/princeton/cs/algs4/BST.java. Sedgewick and Wayne, Algorithms: BST keys method and inherited-bound isBST check
This combination is useful and attractive: one data structure supports directed lookup and ordered enumeration. An inorder traversal costs time complexity for entries, since it visits every vertex; balance accelerates lookup but cannot eliminate the work of outputting all keys.
// Destination: computer-science.bigb
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 .
Cached cell value 2026-10-13
A numerical value retained for reuse by memoization. It is usable only while the spreadsheet formula and all its relevant inputs remain valid. After changing
A1 from 3 to 5, following outgoing directed edges finds exactly B1,B2,C1,D1. Invalidate their cached cell values before evaluating another requested result; install the new input value for A1. The cached cell values of A2 and E1 remain valid because neither has a directed path from A1.Downstream invalidation after an input edit, and a different formula edit creating a spreadsheet circular reference
. Details. One recomputation in the restricted topological order
B1,B2,C1,D1 gives . Four spreadsheet formulas are recomputed, while E1 stays at 16. Removing invalid values from the cache prevents a subtle error: a finished marker from the previous evaluation does not prove that the old value is correct after an edit. The affected set is conservative; a changed prerequisite might leave a consumer's value numerically equal, but this simple scheme still invalidates it. For a formula edit, update the incoming directed edges and corresponding outgoing consumer lists as well as invalidating the edited spreadsheet cell and its downstream consumers. Microsoft's documentation explicitly describes both direct and indirect dependents being marked for recalculation.[ref]Excel Recalculation by Microsoft. Dependence, Dirty Cells, and Recalculated Cells: paragraph beginning “When a structural change is made”; B1/A1 and C1/B1 dirty-cell example
For demand-driven evaluation, memoization combines with depth-first search. Each spreadsheet cell has one of three states:
UNSEEN means no valid cached cell value; ACTIVE means its evaluation is on the current call stack; FINISHED means a valid value is available. Initialize valid input spreadsheet cells as FINISHED. Start with all spreadsheet formulas UNSEEN, or retain only valid FINISHED entries after invalidation. The following original algorithm uses an ordered references list and an apply_formula operation for each spreadsheet formula:def value(cell):
if state[cell] == FINISHED:
return cache[cell]
if state[cell] == ACTIVE:
i = stack.index(cell)
raise CircularReference(stack[i:] + [cell])
state[cell] = ACTIVE
stack.append(cell)
try:
args = [value(p) for p in references[cell]]
cache[cell] = apply_formula(cell, args)
state[cell] = FINISHED
return cache[cell]
except Exception:
state[cell] = UNSEEN
raise
finally:
stack.pop()Requesting
D1 first makes D1,C1,B1 active, then reads the finished inputs A1,A2. B1 finishes at 7. Evaluating B2 reuses the finished value of A1 and finishes at 6; C1 finishes at 13 and D1 at . A later request for D1 immediately returns its cached cell value. The shared prerequisite A1 is not a directed cycle: it was finished before the second request. The crucial distinction is between a previously visited vertex and a still-active vertex. The exceptional path restores unfinished states while unwinding the call stack, so failed evaluations are not cached as successful results. MIT's depth-first search notes use stack-duration marks to distinguish an edge to an active ancestor and to detect a directed cycle.[ref]Lecture 14: Graphs II: Depth-First Search. Lecture 14: Graphs II: Depth-First Search, printed pp. 3–4: stack-duration marks and cycle detection
With adjacency lists and constant-time state/cache access, the structural work of a successful demand-driven evaluation is in big O notation, where and are the requested spreadsheet cells and their recursively reached prerequisites and references. Each reached spreadsheet formula is computed once; each reference is inspected once. This time complexity counts dependency bookkeeping separately from the cost of the arithmetic operations. Detecting a spreadsheet circular reference can additionally scan the current call stack once to report its witness.
Circular buffer operation costs 2026-10-18
With storage allocated in advance, each successful insertion, removal,
peek, size, and full/empty check uses worst-case time complexity in Big O notation. This assumes constant-cost indexed array access, bounded machine word index arithmetic and fixed-cost scalar item reads and writes. Each operation touches a bounded number of slots and fields regardless of and ; no shifting, scanning or resizing occurs. Rejected operations also take constant work. Producing a copy of all live items takes work under the same scalar-cost assumptions.The preallocated array occupies scalar slots plus constant bookkeeping. Allocation and any initial slot construction are separate setup costs. Copying a large item, running an expensive destructor or callback, allocating an item, or growing a dynamic array changes the operation cost and must be charged separately. The bound is worst-case structural work, with no need for amortized analysis, and says nothing about a measured wall-clock deadline.
These formulas describe sequential calls. Wrapping array indices implies neither atomic operations nor safe access from multiple software threads. Publication of an item's contents and reuse of its slot require a protocol justified under the relevant memory model, including any necessary acquire-release synchronization. The kernel documentation discusses barriers under explicit producer/consumer restrictions; Boost's documentation separately requires mutual exclusion for shared access involving writes. Neither property follows merely from choosing a circular buffer.[ref]
Circular Buffers by David Howells and Paul E. McKenney. David Howells and Paul E. McKenney, Circular Buffers, Using memory barriers with circular buffers; The producer; The Consumer: explicit synchronization and ordering requirements
[ref]Implementation. Jan Gaspar, Boost.Circular Buffer, Implementation, Thread-Safety: shared access involving a writer requires mutual exclusion
Composite midpoint quadrature rule 2026-10-14
Apply the midpoint quadrature rule on each of equal panels of a partition of an interval, with :Each quadrature node is a panel midpoint and each quadrature weight is . For , put . Summing the panel quadrature errors givesfor some . Each panel contributes at most ; there are panels, explaining the composite midpoint rule error of order in big O notation. On a nonuniform partition of an interval with panel widths and largest width , the corresponding bound is .
For on , summing the sampled polynomial exactly yieldsDoubling divides the absolute error by exactly four. For a general function, halving divides the displayed error bound by four, but the actual absolute error need not follow that ratio: cancellation can make it smaller or zero. Continuous functions still give convergence as the largest panel width tends to zero, by uniform continuity; without the bounded second derivative, the second-order rate is not guaranteed. Noise sensitivity of a quadrature rule explains a separate limitation when samples are inexact.

















