AC-3 2026-10-25
An arc consistency algorithm maintaining a work list of directed constrained variable pairs. Revising deletes each value of with no compatible value in . If shrinks, incoming arcs are reconsidered; the just-used neighbor need not be included, since deleted values had no support in and hence supported no surviving value there. Initially empty constraint domains are rejected before processing.
Each deletion preserves every complete solution: a solution using the removed value would supply its missing support. Therefore an empty constraint domain certifies impossibility. Successful termination establishes arc consistency but need not establish satisfiability. A triangle of two-valued inequality constraints supplies a counterexample: all values have pairwise support, but no assignment can satisfy all three inequalities.
For variables, constrained pairs and maximum constraint domain size , assume constant-time compatibility tests for combined pair relations. A revision costs , and each shrinking source constraint domain can cause at most rounds of reconsideration of its incoming arcs. Thus there are revisions and time complexity . Fixed , including two-valued constraint domains, gives linear time in .
Algorithm Created 2026-09-24 Updated 2026-10-13
Here "finite" refers to the description: a short algorithm can perform arbitrarily many steps on increasingly large inputs. Solving a computational problem additionally requires termination and the specified output on every permitted input. State assumptions explicitly: binary search requires a sorted array.
An algorithm is an idea that can have implementations in different programming languages. Its explanation should make three things visible: the permitted inputs, the rule for each step, and the meaning of the returned output. Algorithm correctness then separates finding the right answer from eventually finishing; time complexity asks how much work finishing requires.
A particularly useful design question is: what knowledge survives each step? In binary search, it is the location of every possible match inside the remaining candidate range. Writing that fact as a loop invariant turns an intuitive shortcut into a procedure whose discarded candidates can be justified. This often helps discover the algorithm, rather than merely check it afterward.
Algorithm correctness Created 2026-10-13 Updated 2026-10-18
Partial correctness means that, if the algorithm terminates on a permitted input, its output meets the formal specification. Total correctness additionally requires algorithm termination on every permitted input.
A precondition describes permitted starting circumstances; a postcondition describes the required result. Partial correctness says that starting with and finishing implies . Total correctness also guarantees finishing. A loop invariant supplies the connection between these conditions during repeated steps.[ref]
Loop invariants. CS 2112 Fall 2019; Loop invariants, Using loop invariants to show code is correct: Establishment, Preservation, Postcondition, and Termination
Correctness is relative to a formal specification. Returning the first entry of an array correctly implements "return the first entry", but fails "return the maximum" on . A fast wrong answer does not acquire algorithm correctness from its time complexity. Numerical closeness matters only when the formal specification allows an approximation. Software testing and test coverage provide evidence about selected executions; they do not by themselves establish algorithm correctness for every permitted input.
All-subsequence embedding kernel 2026-10-31
Here counts increasing position embeddings of the word as a subsequence of . Counting embeddings retains repeated-letter multiplicities. The empty word has one embedding in every string. Prefix dynamic programming computes this positive-semidefinite kernel by with boundary values one. The time complexity is arithmetic operations, and rolling rows require integer cells. Counting pairs of position subsets bounds output bit length by .
Amortized time complexity 2026-10-31
An amortized analysis can bound the total time complexity of every allowed sequence of operations by , where is a size parameter and accounts for initialization or the specified initial state. The bound is then an amortized per-operation time complexity. Dividing the total bound by explains the averaging; it is a guarantee over every permitted sequence, without an assumed probability distribution on requests. Individual operations can cost more than .
Analysis of algorithms 2026-10-31
Studying an algorithm's resource use under a stated cost model. Time complexity, space complexity and amortized analysis answer different questions, so an operation count should specify the input-size parameter and what each primitive operation costs.
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.
AVL tree 2026-11-05
An AVL tree is a binary search tree in which the left and right subtree heights differ by at most one at every vertex. The ordering invariant supports directed search; the extra height condition prevents the long chains that make an unbalanced binary search tree slow. Tree rotations repair the shape while preserving key order.[ref]
Balanced binary trees in Cornell CS 2112. AVL Trees and Rotations
Inserting keys
3,2,1 into an ordinary binary search tree produces a chain. A right tree rotation at three makes two the root with children one and three. For a height proof, count edges and set the empty-tree height to . The minimum vertex count satisfiesThis Fibonacci sequence growth gives height of a binary tree , hence logarithmic worst-case search, insertion and deletion time complexity. Deletion may require repairs at several ancestors. Backtracking 2026-10-20
Build a candidate incrementally, abandoning a partial candidate as soon as no valid completion is possible. A depth-first search explores one choice, restores the previous state, and tries the next. Constraint propagation and bounds can greatly reduce the visited state space, although the worst-case time complexity may remain exponential.
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. Best-case maximum deletion in a binary heap 2026-10-31
In the implementation that exchanges the root with the final leaf and then applies heapify down, a max-heap of size at least four with distinct keys requires at least one downward exchange: the old final leaf's parent remains and has a larger key. One downward exchange can suffice, even for large heaps, by promoting the opposite root child and letting the moved key dominate that child's descendants. Thus the best case is two pairwise exchanges when the initial root/final-leaf exchange is counted. This is a convention about that implementation: a hole-moving implementation uses assignments rather than pairwise exchanges, and the worst case still has logarithmic time complexity.
Big O notation Created 2026-09-24 Updated 2026-10-14
The statement as means there are constants and such thatThe same constant must work for all sufficiently large inputs. Near a finite limit point , replace by within the domain. Absolute values allow signed or complex-valued functions; when discussing nonnegative operation counts they can be omitted.
The notation records an upper bound, not an exact leading coefficient or necessarily a tight growth order. For example, because for it is at most . It is also , a weaker statement. A tight comparison uses big theta notation; a ratio tending to one uses asymptotic equivalence. Formally denotes a class of functions, and writing is conventional shorthand for membership in that class. [ref]
https://live.ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/c6d8f06c6f11e3342633dec85498f551_MIT6_006S20_r01.pdf. MIT 6.006, Demaine, Ku and Solomon, Recitation 1, page 3: asymptotic upper and tight bounds
The first panel compares stipulated operation counts and . Although is linear and quadratic, for ; the ordering reverses beyond their crossing. These are mathematical cost models, not measured runtimes. The time complexity notation describes the growth of whichever cost function has been specified, whether that function represents a worst-case bound, an average, or another explicit quantity.
The middle panel gives a concrete eventual bound: for every . Its normalized ratio approaches one, but the threshold matters. The final panel shows the asymptotic comparison of exponential functions, with its geometrically shrinking relative difference.
Constants may depend on fixed parameters. For each fixed , is with ; one constant cannot cover every positive . A uniform big O bound makes this extra quantifier explicit.
The notation was already used in nineteenth-century number theory. In his 1976 paper, Donald E. Knuth reports Landau identifying Bachmann's 1894 book as the first appearance of known to him. Knuth's account gives the earlier mathematical setting of a notation now also common in time complexity analysis. [ref]
https://danluu.com/knuth-big-o.pdf. Knuth, Big Omicron and big Omega and big Theta, 1976, page 19
Binary array sum by recursion 2026-10-18
Keep an array unchanged, and sum entries in the half-open integer interval of array indices . The precondition requires integers and exact, terminating integer addition. An empty range returns the empty sum zero; a one-entry range returns that entry. Every longer range splits at its middle array index:For the original array , call . The left half returns , the right half returns , and the original invocation returns . The right half's left endpoint increases from zero to two: what decreases is range length , not every argument. Negative entries affect the answer but do not affect algorithm termination.
S(A, l, r):
require integer indices with 0 <= l <= r <= length(A)
size = r - l
if size == 0:
return 0
if size == 1:
return A[l]
middle = l + floor(size / 2)
left_sum = S(A, l, middle)
right_sum = S(A, middle, r)
return left_sum + right_sumSeven calls compute an array sum with only three frames active at once
. Original binary tree of invocations for , with integer intervals labeling ranges and upward arrows labeling returned sums. Small numbers give the order in which invocations begin when the left child runs first. The highlighted graph path contains the three active stack frames while the entry is read; the result from the completed left sibling is retained by its parent. Details.For range length , the children have lengths and , both positive and strictly less than . The floor function chooses the split; the ceiling function gives the other length. Algorithm termination follows by this natural number measure. For algorithm correctness, apply mathematical induction on : the two base cases return the specified sum; for a larger range, the two disjoint child ranges cover every original array index exactly once, so addition of their correct sums gives the required sum.
For , the invocation tree is a full binary tree with leaves, one per array entry. If is its number of nonleaf vertices, counting edges gives , so . Thus the total invocation count is , and there are combining additions. Here gives seven calls and three combining additions. For , there is one call and no combining addition; for , there is also one call and no combining addition, but no entry leaf, so the formula does not apply.
The call stack holds the active branch, rather than the entire invocation tree. Execute the left child completely before the right child, retaining the left result in the parent stack frame. The maximum number of active stack frames is for , and one for . Balanced splitting therefore needs frames for , compared with the frames of the factorial recursive process. Assuming constant-cost array access, index operations and addition, its time complexity is and its auxiliary space complexity is machine words for , excluding the stored input. Pass the same array with different endpoints, rather than copying slices. These bounds require all stored indices and partial sums to fit in a constant number of machine words; exact unbounded integer addition and storage require a separate bit cost analysis.
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 search 2026-10-13
Binary search finds a target in a sorted array by inspecting the middle of the remaining candidate range. If the middle entry is smaller than , every entry to its left is also too small; if larger, every entry to its right is too large. One comparison therefore rules out many entries. Equal entries are allowed; this version returns any matching index, without promising the first occurrence.
Use indices starting at zero and inclusive endpoints . Initially , , where is the array length. While , chooseThe brackets denote the floor function. Compare with : return on equality; set if ; otherwise set . If , report absence. The updates exclude the already inspected middle entry. This also handles an empty array, whose initial endpoints are . Sedgewick and Wayne specify a sorted array as input and return a matching index or for absence.[ref]
https://algs4.cs.princeton.edu/code/javadoc/edu/princeton/cs/algs4/BinarySearch.html. Sedgewick and Wayne: BinarySearch API
For , the first two steps agree. Next retains only index ; inspecting sets . Now , so the answer is "absent" after four comparisons.
Binary search retains only candidates compatible with every comparison
. Blue cells are current candidates, orange marks the middle entry, and green marks a match. Both searches use the same fifteen-entry sorted array. Details.The loop invariant is: the array stays sorted, , and every index containing lies between and . It holds initially. The sorted array property justifies each exclusion. Returning on equality gives a match; an empty candidate range implies absence. Crucially, this loop invariant allows to be absent from the beginning.
For a nonempty range of size , an unsuccessful comparison leaves at most candidates. Thus sizes satisfy after unsuccessful comparisons. This proves termination and, for , at most middle-entry comparisons. The final singleton still needs inspection: requires one comparison, not zero. For , the bound is four. This is the halving argument behind logarithmic time complexity.[ref]
https://www.cs.princeton.edu/courses/archive/fall24/cos126/static/lectures/42Algorithms.pdf. Princeton COS 126: binary search analysis
A decision tree with binary tests has at most leaves. Distinguishing possible matching positions therefore requires . This lower bound counts binary tests, whereas the bound above counts three-way comparisons.
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.
Bit cost of modular exponentiation 2026-10-14
The binary powering multiplication count counts arithmetic operations. The time complexity measured in operations on individual bits also depends on operand lengths. Put , the binary length of the modulus, and let be the positive exponent's binary length. Stored residues use at most bits, and an unreduced product uses at most bits.
With ordinary long multiplication and division with remainder, one modular product costs operations on bits. Combining that cost with modular products givesThis bound includes reductions in the loop, and assumes the base has already been reduced and the exponent is available as a binary expansion. Reading the exponent takes additional work; initial reduction of a very long base depends on its input length, and an inverse for a negative exponent adds further work. More generally, if a modular product costs operations on bits, the powering loop costs . Faster multiplication and reduction methods can improve the quadratic bound.[ref]
For ordinary integer powers with , the output itself has binary digits. Even writing it takes work proportional to that length. Consequently multiplications does not imply operations on bits: the operands grow during ordinary exponentiation by squaring, whereas modular exponentiation keeps them bounded by the modulus. A squaring or multiplication by a small fixed base can also cost less than a general product, so equal counts need not mean equal running times.
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.












