Recent from talks
Contribute something
Nothing was collected or created yet.
Merge-insertion sort
View on WikipediaIn computer science, merge-insertion sort or the Ford–Johnson algorithm is a comparison sorting algorithm published in 1959 by L. R. Ford Jr. and Selmer M. Johnson.[1][2][3][4] It uses fewer comparisons in the worst case than the best previously known algorithms, binary insertion sort and merge sort,[1] and for 20 years it was the sorting algorithm with the fewest known comparisons.[5] Although not of practical significance, it remains of theoretical interest in connection with the problem of sorting with a minimum number of comparisons.[3] The same algorithm may have also been independently discovered by Stanisław Trybuła and Czen Ping.[4]

Algorithm
[edit]Merge-insertion sort performs the following steps, on an input of elements:[6]
- Group the elements of into pairs of elements, arbitrarily, leaving one element unpaired if there is an odd number of elements.
- Perform comparisons, one per pair, to determine the larger of the two elements in each pair.
- Recursively sort the larger elements from each pair, creating a sorted sequence of of the input elements, in ascending order, using the merge-insertion sort.
- Insert at the start of the element that was paired with the first and smallest element of .
- Insert the remaining elements of into , one at a time, with a specially chosen insertion ordering described below. Use binary search in subsequences of (as described below) to determine the position at which each element should be inserted.
The algorithm is designed to take advantage of the fact that the binary searches used to insert elements into are most efficient (from the point of view of worst case analysis) when the length of the subsequence that is searched is one less than a power of two. This is because, for those lengths, all outcomes of the search use the same number of comparisons as each other.[1] To choose an insertion ordering that produces these lengths, consider the sorted sequence after step 4 of the outline above (before inserting the remaining elements), and let denote the th element of this sorted sequence. Thus,
where each element with is paired with an element that has not yet been inserted. (There are no elements or because and were paired with each other.) If is odd, the remaining unpaired element should also be numbered as with larger than the indexes of the paired elements. Then, the final step of the outline above can be expanded into the following steps:[1][2][3][4]
- Partition the uninserted elements into groups with contiguous indexes. There are two elements and in the first group, and the sums of sizes of every two adjacent groups form a sequence of powers of two. Thus, the sizes of groups are: 2, 2, 6, 10, 22, 42, ...
- Order the uninserted elements by their groups (smaller indexes to larger indexes), but within each group order them from larger indexes to smaller indexes. Thus, the ordering becomes
- Use this ordering to insert the elements into . For each element , use a binary search from the start of up to but not including to determine where to insert .
Analysis
[edit]Let denote the number of comparisons that merge-insertion sort makes, in the worst case, when sorting elements. This number of comparisons can be broken down as the sum of three terms:
- comparisons among the pairs of items,
- comparisons for the recursive call, and
- some number of comparisons for the binary insertions used to insert the remaining elements.
In the third term, the worst-case number of comparisons for the elements in the first group is two, because each is inserted into a subsequence of of length at most three. First, is inserted into the three-element subsequence . Then, is inserted into some permutation of the three-element subsequence , or in some cases into the two-element subsequence . Similarly, the elements and of the second group are each inserted into a subsequence of length at most seven, using three comparisons. More generally, the worst-case number of comparisons for the elements in the th group is , because each is inserted into a subsequence of length at most .[1][2][3][4] By summing the number of comparisons used for all the elements and solving the resulting recurrence relation, this analysis can be used to compute the values of , giving the formula[7]
or, in closed form,[8]
For the numbers of comparisons are[1]
Relation to other comparison sorts
[edit]The algorithm is called merge-insertion sort because the initial comparisons that it performs before its recursive call (pairing up arbitrary items and comparing each pair) are the same as the initial comparisons of merge sort, while the comparisons that it performs after the recursive call (using binary search to insert elements one by one into a sorted list) follow the same principle as insertion sort. In this sense, it is a hybrid algorithm that combines both merge sort and insertion sort.[9]
For small inputs (up to ) its numbers of comparisons equal the lower bound on comparison sorting of . However, for larger inputs the number of comparisons made by the merge-insertion algorithm is bigger than this lower bound. Merge-insertion sort also performs fewer comparisons than the sorting numbers, which count the comparisons made by binary insertion sort or merge sort in the worst case. The sorting numbers fluctuate between and , with the same leading term but a worse constant factor in the lower-order linear term.[1]
Merge-insertion sort is the sorting algorithm with the minimum possible comparisons for items whenever , and it has the fewest comparisons known for .[10][11] For 20 years, merge-insertion sort was the sorting algorithm with the fewest comparisons known for all input lengths. However, in 1979 Glenn Manacher published another sorting algorithm that used even fewer comparisons, for large enough inputs.[3][5] It remains unknown exactly how many comparisons are needed for sorting, for all , but Manacher's algorithm and later record-breaking sorting algorithms have all used modifications of the merge-insertion sort ideas.[3]
References
[edit]- ^ a b c d e f g Ford, Lester R. Jr.; Johnson, Selmer M. (1959), "A tournament problem", American Mathematical Monthly, 66 (5): 387–389, doi:10.2307/2308750, JSTOR 2308750, MR 0103159
- ^ a b c Williamson, Stanley Gill (2002), "2.31 Merge insertion (Ford–Johnson)", Combinatorics for Computer Science, Dover books on mathematics, Courier Corporation, pp. 66–68, ISBN 9780486420769
- ^ a b c d e f Mahmoud, Hosam M. (2011), "12.3.1 The Ford–Johnson algorithm", Sorting: A Distribution Theory, Wiley Series in Discrete Mathematics and Optimization, vol. 54, John Wiley & Sons, pp. 286–288, ISBN 9781118031131
- ^ a b c d Knuth, Donald E. (1998), "Merge insertion", The Art of Computer Programming, Vol. 3: Sorting and Searching (2nd ed.), pp. 184–186
- ^ a b Manacher, Glenn K. (July 1979), "The Ford-Johnson Sorting Algorithm Is Not Optimal", Journal of the ACM, 26 (3): 441–456, doi:10.1145/322139.322145
- ^ The original description by Ford & Johnson (1959) sorted the elements in descending order. The steps listed here reverse the output, following the description in Knuth (1998). The resulting algorithm makes the same comparisons but produces ascending order instead.
- ^ Knuth (1998) credits the summation formula to the 1960 Ph.D. thesis of A. Hadian. The approximation formula was already given by Ford & Johnson (1959).
- ^ Guy, Richard K.; Nowakowski, Richard J. (December 1995), "Monthly Unsolved Problems, 1969-1995", American Mathematical Monthly, 102 (10): 921–926, doi:10.2307/2975272, JSTOR 2975272
- ^ Knuth (1998), p. 184: "Since it involves some aspects of merging and some aspects of insertion, we call it merge insertion."
- ^ Peczarski, Marcin (2004), "New results in minimum-comparison sorting", Algorithmica, 40 (2): 133–145, doi:10.1007/s00453-004-1100-7, MR 2072769
- ^ Peczarski, Marcin (2007), "The Ford-Johnson algorithm still unbeaten for less than 47 elements", Information Processing Letters, 101 (3): 126–128, doi:10.1016/j.ipl.2006.09.001, MR 2287331
Merge-insertion sort
View on GrokipediaIntroduction
Definition
Merge-insertion sort, also known as the Ford–Johnson algorithm, is a comparison-based sorting algorithm that combines elements of merge sort and insertion sort to sort a collection of n distinct elements.[2] It was developed as a method to minimize the number of comparisons required in the worst case, achieving a performance close to the information-theoretic lower bound of approximately comparisons for sorting n elements.[2] Published in 1959 by L. R. Ford Jr. and Selmer M. Johnson, the algorithm addresses the problem of finding the minimal number of pairwise comparisons to determine a total order among elements, framed originally as a tournament problem.[1] The core purpose of merge-insertion sort is to reduce the worst-case comparison count below that of standard merge sort by strategically pairing elements and inserting them efficiently into partially sorted sequences, making it particularly effective for small to moderate n where comparison minimization is critical.[2] Its hybrid nature arises from an initial phase of pairwise comparisons to create sorted pairs (similar to merge sort's divide step), followed by recursive application to the larger elements and careful insertion of the smaller ones using binary search to limit comparisons.[2] A key innovation in the algorithm is the use of binary insertion into sorted runs rather than full pairwise merges, which avoids unnecessary comparisons during the integration of sublists; this insertion strategy batches smaller elements and places each into the growing sorted list with at most k comparisons for elements in the k-th batch, optimizing the overall process.[2]History
The merge-insertion sort algorithm, also known as the Ford–Johnson algorithm, was developed in 1959 by L. R. Ford Jr. and Selmer M. Johnson while working at the RAND Corporation.[1] Their work addressed the problem of determining a complete ranking of elements using the minimal number of pairwise comparisons, framed as a "tournament problem" where elements compete to establish order.[1] This approach emerged during a period of intense interest in optimizing sorting algorithms, driven by information-theoretic considerations that set lower bounds on the number of comparisons required for sorting, as established by Claude Shannon's foundational work on entropy and communication in 1948. Ford and Johnson published their algorithm in a seminal paper titled "A Tournament Problem" in the American Mathematical Monthly, detailing a method that combines elements of merging sorted lists with careful insertion to minimize comparisons in the worst case. The algorithm was motivated by the desire to approach the theoretical minimum of approximately comparisons needed to sort elements, a bound derived from the number of possible permutations and Shannon's entropy principles. Their solution proved particularly effective for small to moderate input sizes, establishing a benchmark for comparison-based sorting efficiency. Subsequent analyses have refined and extended the algorithm's understanding, confirming that it remains unbeaten (best known) for small n (up to 46 elements) among split-and-merge algorithms, with optimality proven for n ≤ 15, and exploring its average-case performance. For instance, research in 2019 provided a detailed average-case analysis, showing that it remains competitive for many input sizes by achieving near-minimal comparisons.[4] Ongoing academic interest continues to highlight its theoretical significance, with recent implementations demonstrating its practical viability in specialized contexts.[5]Algorithm
Overview
Merge-insertion sort, also known as the Ford–Johnson algorithm, is a comparison-based sorting algorithm designed to minimize the number of element comparisons in the worst case, particularly effective for small to moderate input sizes.[6] Developed by Lester R. Ford Jr. and Selmer M. Johnson in 1959, it combines elements of merging and insertion techniques to achieve near-optimal comparison efficiency.[6] The algorithm processes the input list through three main phases, progressively refining sorted subsets known as "runs" while leveraging prior comparisons to reduce overall work. The first phase involves pairwise comparisons: the input elements are grouped into approximately n/2 disjoint pairs (with a singleton if n is odd), and each pair is sorted with a single comparison, producing larger "winner" elements and smaller "loser" elements. In the second phase, the winner elements are recursively sorted using the same algorithm, building a sorted list of these larger values and forming progressively larger runs from the initial pairs. The third phase inserts the loser elements back into this sorted winners list using binary insertion, processed in a specific order determined by the Jacobsthal sequence to exploit the structure of previous comparisons and minimize additional probes. This order involves batching insertions, such as starting with the third-last loser, then second-last, then first, then last for four losers, ensuring that each batch of k elements requires at most k comparisons in total.[2] This process creates a tournament-like structure, where initial pairwise "matches" advance winners to deeper levels of sorting, and losers are reintroduced with efficient placement searches that reuse tournament outcomes, thereby optimizing the total comparisons.[6] To illustrate, consider sorting a small list of four elements: [4, 2, 3, 1].- After phase 1 (pairwise comparisons): Pairs are (4 > 2) and (3 > 1), yielding winners [4, 3] and losers [2, 1]; initial runs are the sorted pairs [2, 4] and [1, 3].
- After phase 2 (recursive sort of winners): The winners [4, 3] are compared and sorted into [3, 4], forming a larger run from the high elements.
- After phase 3 (binary insertions of losers): For two losers, the order is the second (1), then first (2): loser 1 is inserted into [3, 4] at the beginning, yielding [1, 3, 4]; then loser 2 is inserted between 1 and 3, resulting in the fully sorted run [1, 2, 3, 4].
Detailed Steps
The merge-insertion sort algorithm consists of three distinct phases that systematically sort an array of elements through pairwise comparisons, sorting of selected elements, and targeted insertions. In Phase 1, the array elements are grouped into consecutive pairs, with the last element left unpaired if is odd. For each pair at indices and , the elements are compared, and swapped if the first is larger than the second to ensure the pair is in ascending order. The larger element (winner) from each pair is collected into a separate list of length , while the smaller elements (losers) remain in their positions or are collected into a list of length . If is odd, the final unpaired element is added to without any comparison. This phase requires exactly comparisons.[7] Phase 2 sorts the winners list using the same merge-insertion algorithm recursively, which builds larger sorted runs iteratively through repeated pairing and insertion on progressively smaller subsets until a base case of 1 or 0 elements is reached. Equivalently, this can be implemented iteratively by applying the pairwise phase to , collecting its sub-winners, and using binary search to insert sub-losers into growing sorted segments of previous runs, effectively merging them while minimizing shifts through position calculations. The result is a fully sorted list of the original winners, serving as the initial main sorted run.[2] In Phase 3, the elements from the losers list are inserted one by one into the sorted winners list using binary search to locate the precise insertion point, followed by shifting elements to accommodate the new one. The insertion order is determined by the Ford–Johnson schedule, derived from the Jacobsthal sequence, which batches insertions to bound the number of comparisons (e.g., for four losers b1 to b4, insert b3, then b2, then b1, then b4). To handle odd-length inputs efficiently, the unpaired element from Phase 1 (if any) is inserted according to the schedule. This ensures that insertions into lists of length between 2^k and 2^{k+1}-1 require at most k+1 comparisons each, optimizing the worst case. The final sorted list replaces the original array.[7][2]Pseudocode
The following recursive pseudocode illustrates the phases, with binary search for insertions (assuming an in-place array for simplicity, but using auxiliary lists for clarity). Thebinary_insert function performs a binary search to find the position and inserts the value, shifting elements as needed. Note that the insertion order in Phase 3 follows the Ford–Johnson sequence (Jacobsthal-derived) rather than reverse; the exact order can be precomputed as a permutation of the losers indices.
procedure merge_insertion_sort(A: array of size n)
if n <= 1:
return // Base case
m = floor(n / 2)
L = empty list // Losers
W = empty list // Winners
// Phase 1: Pairwise comparison and collection
for i = 0 to m-1:
if A[2*i] > A[2*i+1]:
swap A[2*i], A[2*i+1]
L.append(A[2*i])
W.append(A[2*i+1])
if n % 2 == 1:
L.append(A[n-1]) // Unpaired element as loser
// Phase 2: Recursively sort winners (iterative equivalent: repeat phases on W until sorted)
merge_insertion_sort(W) // W is now sorted
// Phase 3: Insert losers into sorted W using binary insertion in Ford-Johnson order
main = W // Start with sorted winners as main run
insertion_order = compute_fj_order(length(L)) // E.g., for 4: [2,1,0,3] (0-based indices for b3,b2,b1,b4)
for idx in insertion_order:
value = L[idx]
pos = binary_search_position(main, value) // Find insertion index
insert main at pos with value // Shift and place
// Copy back to original array
for i = 0 to n-1:
A[i] = main[i]
function binary_search_position(sorted_list, value):
low = 0
high = [length](/page/Length)(sorted_list)
while low < high:
mid = [floor](/page/Floor)((low + high) / 2)
if sorted_list[mid] < value:
low = mid + 1
else:
high = mid
return low // Insertion point
function compute_fj_order(m):
// Returns 0-based indices in Ford-Johnson insertion order (Jacobsthal-based)
// Implementation details: batch insertions starting from specific positions
// For example, for m=4: return [2,1,0,3]
// Full computation follows the sequence where batches are defined by t_k ≈ 2^{k+1} - 2^{k-1}/3 or equivalent
pass // Placeholder for the order computation
procedure merge_insertion_sort(A: array of size n)
if n <= 1:
return // Base case
m = floor(n / 2)
L = empty list // Losers
W = empty list // Winners
// Phase 1: Pairwise comparison and collection
for i = 0 to m-1:
if A[2*i] > A[2*i+1]:
swap A[2*i], A[2*i+1]
L.append(A[2*i])
W.append(A[2*i+1])
if n % 2 == 1:
L.append(A[n-1]) // Unpaired element as loser
// Phase 2: Recursively sort winners (iterative equivalent: repeat phases on W until sorted)
merge_insertion_sort(W) // W is now sorted
// Phase 3: Insert losers into sorted W using binary insertion in Ford-Johnson order
main = W // Start with sorted winners as main run
insertion_order = compute_fj_order(length(L)) // E.g., for 4: [2,1,0,3] (0-based indices for b3,b2,b1,b4)
for idx in insertion_order:
value = L[idx]
pos = binary_search_position(main, value) // Find insertion index
insert main at pos with value // Shift and place
// Copy back to original array
for i = 0 to n-1:
A[i] = main[i]
function binary_search_position(sorted_list, value):
low = 0
high = [length](/page/Length)(sorted_list)
while low < high:
mid = [floor](/page/Floor)((low + high) / 2)
if sorted_list[mid] < value:
low = mid + 1
else:
high = mid
return low // Insertion point
function compute_fj_order(m):
// Returns 0-based indices in Ford-Johnson insertion order (Jacobsthal-based)
// Implementation details: batch insertions starting from specific positions
// For example, for m=4: return [2,1,0,3]
// Full computation follows the sequence where batches are defined by t_k ≈ 2^{k+1} - 2^{k-1}/3 or equivalent
pass // Placeholder for the order computation
compute_fj_order function encapsulates the Jacobsthal-derived sequence, which for small m can be hardcoded or computed based on binary lengths to minimize worst-case probes.[2]
