Array index 2026-10-18
An integer identifying a position in an array. With zero-based indexing and capacity , valid array indices are . An array index identifies the slot rather than its stored value.
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:
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_sum
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.
Figure 1.
Seven 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.
Circular buffer Created 2026-10-13 Updated 2026-10-18
A circular buffer stores a changing sequence in a fixed-capacity array, reusing slots by wrapping array indices through modular arithmetic. A front array index and an occupied count can represent a FIFO queue without shifting entries after removal. The physical array stays in place; the position at which its logical sequence begins moves. This makes a circular buffer useful when storage must remain bounded while successive items arrive and leave.
Capacity and overflow behavior are separate choices. A rejecting FIFO queue preserves all accepted items until removal and reports failure on a full insertion. An overwriting circular buffer deliberately discards its oldest item to retain the newest arrivals. These are different application programming interfaces. The existing representation independence example specifies the rejecting policy and gives its abstraction function and correctness argument against a shifting array implementation.
With front-plus-count storage, empty means and full means ; every allocated slot is usable. With only the two wrapped array indices , the equality describes both possibilities. Indeed , and the two allowed counts have the same remainder. Recovering the count as therefore loses the full state. A count, a separate full flag, or a different index representation must resolve that ambiguity.
Another convention reserves one slot: for a physical array of length , empty means and full means . Its usable capacity is , and now recovers its count because . A five-slot array then stores at most four items.
This is the convention of the kernel's documented CIRC_* helpers, which additionally require power-of-two array lengths. It is not a universal property of circular buffers; our capacity-five count-based example uses all five slots and does not use those helpers.[ref]
The smallest count-based case, , makes the issue vivid: both and are always zero, but still distinguishes one live item from none. Capacity zero is excluded from our formulas because remainder modulo zero is undefined.
Circular buffer indices 2026-10-18
Let the capacity be a positive integer , and allocate exactly array slots . Store the front array index and count . The representation invariant is
The logical sequence and next-write array index are
Here denotes the nonnegative remainder from modular arithmetic. The count determines which slots are live: leftover bits in other slots are not members of the FIFO queue. If , has no current front item; it identifies the position where the next successful insertion begins. If , points at a live item, so writing there requires an explicit overwrite policy.
For , enqueue(x) writes , then increments , leaving fixed. For , dequeue() saves and returns , then sets and . These are sequential updates, completed before the next call. A rejecting interface tests or first and returns full or empty, respectively, without changing state. peek returns only when ; size returns .
One can instead store and , recovering . On insertion, advance and increment ; on removal, keep fixed and decrement . Thus the next-write array index is not necessarily the front array index.
Names such as head and tail require checking the actual API: the kernel documentation calls the insertion position head and the removal position tail.[ref]
Figure 1.
A wrapped circular buffer has one logical sequence across the end of its physical array
. Capacity five, front , count , and next-write index . Follow physical slots to read . Slot 1 still shows the removed label , but it is outside the live sequence. Details.
The diagram is the state after step 8 of circular buffer operation trace. Reading the physical array from slot zero would give , which includes a removed label and puts first. Reading from for exactly items gives . The next insertion uses slot , not slot . This distinction also explains why the live sequence may need two contiguous pieces of the array: here slots through , followed by slot . No items need to move to make this wrap work.
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][ref]
Start with , , and immutable labels. Perform enqueue(A), enqueue(B), dequeue(), enqueue(C), enqueue(D), dequeue(), enqueue(E), enqueue(F), enqueue(G). The removals return and . The interleaved insertions and removals make the front advance before the array fills; slot reuse does not require waiting for the FIFO queue to become empty.
Figure 1.
An interleaved capacity-five FIFO queue trace branches at a full insertion
. The table follows completed sequential calls. At step 10, rejecting retains ; overwriting accepts and discards . Step 11 therefore returns different labels. The lower bars show membership lifetimes for and at operation boundaries, not elapsed times or programming-language object lifetimes. Details.
At step 7, occupies physical slot and the next-write array index wraps to . At step 8, reuses slot , giving the physical layout in the preceding diagram. At step 9, replaces the stale contents of slot : the physical array is but the logical sequence is . Now , yet makes the state full rather than empty.
The displayed values are related by after every call. They are shown together to explain the invariant; an implementation need store only two. For the rejecting FIFO queue, every successful removal returns the earliest accepted label not already removed. The representation independence example supplies the general proof through its abstraction function; this trace makes the wrapped physical storage visible.
Counting sort Created 2026-10-13 Updated 2026-10-18
Counting sort uses integer sort keys in directly as indices into an array of counts. Constant-cost counting and indexing give time complexity in Big O notation. To retain complete sorting records, cumulative counts locate their output ranges; filling each range from its end while scanning the input backwards gives stable sorting. Emitting bare sort keys from counts would discard associated data. The term matters when the key range is large.[ref]
For an original worked example, take complete sorting records and possible integer sort keys:
The letters label the associated data, and are never compared. Both input and output array indices start at zero, so their valid positions are ; the count array has array indices . Stable sorting must produce
The equal-sort key groups retain and in arrival order. Counting sort prefix ranges explain where those groups belong; stable record placement in counting sort explains how to fill them without losing that order or the complete sorting records.
For sorting records with integer sort keys in , where , let count the input occurrences of sort key . Define two prefix sums:
The empty sum gives . Here are counts of sorting records. Exactly sorting records have smaller sort keys, so the output positions for sort key form the half-open integer interval
Its right endpoint is excluded: the last occupied array index is when .[ref]
For the seven-sorting record example, the frequency array, inclusive cumulative count array, and start array are
Thus sort keys zero, one, two and three occupy the integer intervals , , and , respectively. In particular, the three sorting records with sort key two belong at array indices three, four and five. The inclusive cumulative count counts all six sorting records with sort keys at most two; six is the exclusive endpoint, not the final position of a sorting record with sort key two.
Figure 1.
Frequencies and prefix sums reserve disjoint counting sort output ranges
. Original seven-sorting record example with . The bar heights count sorting records. The table gives the start and exclusive endpoint for each sort key; the lower strip shows zero-based output array indices. The boundary seven lies just beyond the last slot six. Details.
These integer intervals fit together because for , and . Their lengths add to , so they partition all output positions without overlaps or gaps. An absent sort key contributes an empty integer interval: with frequencies , the endpoints are and sort key two has range . For empty input, every count and endpoint is zero; every reserved integer interval is empty. This makes the same formulas cover missing sort keys and the empty case.
Hash table probe 2026-10-18
One inspection of an array slot during an open addressing operation. Its array index follows the chosen probing rule; its contents determine whether to continue, return a matching hash table record, or establish absence.