Bubble sort
View on WikipediaThis article needs additional citations for verification. (November 2016) |
Static visualization of bubble sort[1] | |
| Class | Sorting algorithm |
|---|---|
| Data structure | Array |
| Worst-case performance | comparisons, swaps |
| Best-case performance | comparisons, swaps |
| Average performance | comparisons, swaps |
| Worst-case space complexity | total, auxiliary |
| Optimal | No |
Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the input list element by element, comparing the current element with the one after it, swapping their values if needed. These passes through the list are repeated until no swaps have to be performed during a pass, meaning that the list has become fully sorted. The algorithm, which is a comparison sort, is named for the way the larger elements "bubble" up to the top of the list.
It performs poorly in real-world use and is used primarily as an educational tool. More efficient algorithms such as quicksort, timsort, or merge sort are used by the sorting libraries built into popular programming languages such as Python and Java.[2][3]
History
[edit]The earliest description of the bubble sort algorithm was in a 1956 paper by mathematician and actuary Edward Harry Friend,[4] Sorting on electronic computer systems,[5] published in the third issue of the third volume of the Journal of the Association for Computing Machinery (ACM), as a "Sorting exchange algorithm." Friend described the fundamentals of the algorithm, and although initially his paper went unnoticed, some years later it was rediscovered by many computer scientists, including Kenneth E. Iverson, who coined its current name.
Analysis
[edit]
Performance
[edit]Bubble sort has a worst-case and average complexity of , where is the number of items being sorted. Most practical sorting algorithms have substantially better worst-case or average complexity, often . Even other sorting algorithms, such as insertion sort, generally run faster than bubble sort, and are no more complex. For this reason, bubble sort is rarely used in practice.
Like insertion sort, bubble sort is adaptive, which can give it an advantage over algorithms like quicksort. This means that it may outperform those algorithms in cases where the list is already mostly sorted (having a small number of inversions), despite the fact that it has worse average-case time complexity. For example, bubble sort is on a list that is already sorted, while quicksort would still perform its entire sorting process.
While any sorting algorithm can be made on a presorted list simply by checking the list before the algorithm runs, improved performance on almost-sorted lists is harder to replicate.
Rabbits and turtles
[edit]The distance and direction that elements must move during the sort determine bubble sort's performance because elements move in different directions at different speeds. An element that must move toward the end of the list can move quickly because it can take part in successive swaps. For example, the largest element in the list will win every swap, so it moves to its sorted position on the first pass even if it starts near the beginning. On the other hand, an element that must move toward the beginning of the list cannot move faster than one step per pass, so elements move toward the beginning very slowly. If the smallest element is at the end of the list, it will take passes to move it to the beginning. This has led to these types of elements being named rabbits and turtles, respectively, after the characters in Aesop's fable of The Tortoise and the Hare.
Various efforts have been made to eliminate turtles to improve the speed of bubble sort. Cocktail sort is a bi-directional bubble sort that goes from beginning to end, and then reverses itself, going end to beginning. It can move turtles fairly well, but it retains worst-case complexity. Comb sort compares elements separated by large gaps, and can move turtles extremely quickly before proceeding to smaller and smaller gaps to smooth out the list. Its average speed is comparable to faster algorithms like quicksort.
Step-by-step example
[edit]Take an array of numbers "5 1 4 2 8", and sort the array from lowest number to greatest number using bubble sort. In each step, elements written in bold are being compared. Three passes will be required:
- First pass
- ( 5 1 4 2 8 ) → ( 1 5 4 2 8 ), Here, algorithm compares the first two elements, and swaps since 5 > 1.
- ( 1 5 4 2 8 ) → ( 1 4 5 2 8 ), Swap since 5 > 4
- ( 1 4 5 2 8 ) → ( 1 4 2 5 8 ), Swap since 5 > 2
- ( 1 4 2 5 8 ) → ( 1 4 2 5 8 ), Now, since these elements are already in order (8 > 5), algorithm does not swap them.
- Second pass
- ( 1 4 2 5 8 ) → ( 1 4 2 5 8 )
- ( 1 4 2 5 8 ) → ( 1 2 4 5 8 ), Swap since 4 > 2
- ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
- ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
Now, the array is already sorted, but the algorithm does not know if it is completed. The algorithm needs one additional whole pass without any swap to know it is sorted.
- Third pass
- ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
- ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
- ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
- ( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
Implementation
[edit]Pseudocode implementation
[edit]In pseudocode the algorithm can be expressed as (0-based array):
procedure bubbleSort(A : list of sortable items)
n := length(A)
repeat
swapped := false
for i := 1 to n-1 inclusive do
{ if this pair is out of order }
if A[i-1] > A[i] then
{ swap them and remember something changed }
swap(A[i-1], A[i])
swapped := true
end if
end for
until not swapped
end procedure
Optimizing bubble sort
[edit]The bubble sort algorithm can be optimized by observing that the n-th pass finds the n-th largest element and puts it into its final place. So, the inner loop can avoid looking at the last n − 1 items when running for the n-th time:
procedure bubbleSort(A : list of sortable items)
n := length(A)
repeat
swapped := false
for i := 1 to n - 1 inclusive do
if A[i - 1] > A[i] then
swap(A[i - 1], A[i])
swapped := true
end if
end for
n := n - 1
until not swapped
end procedure
More generally, it can happen that more than one element is placed in its final position on a single pass. In particular, after every pass, all elements after the last swap are sorted, and do not need to be checked again. This allows us to skip over many elements, resulting in about a 50% improvement in the worst-case comparison count (though no improvement in swap counts), and adds very little complexity because the new code subsumes the swapped variable:
To accomplish this in pseudocode, the following can be written:
procedure bubbleSort(A : list of sortable items)
n := length(A)
repeat
newn := 0
for i := 1 to n - 1 inclusive do
if A[i - 1] > A[i] then
swap(A[i - 1], A[i])
newn := i
end if
end for
n := newn
until n ≤ 1
end procedure
Alternate modifications, such as the cocktail shaker sort attempt to improve on the bubble sort performance while keeping the same idea of repeatedly comparing and swapping adjacent items.
Use
[edit]
Although bubble sort is one of the simplest sorting algorithms to understand and implement, its O(n2) complexity means that its efficiency decreases dramatically on lists of more than a small number of elements. Even among simple O(n2) sorting algorithms, algorithms like insertion sort are usually considerably more efficient.
Due to its simplicity, bubble sort is often used to introduce the concept of an algorithm, or a sorting algorithm, to introductory computer science students. However, some educators such as Owen Astrachan have gone to great lengths to disparage bubble sort and its continued popularity in computer science education, recommending that it no longer even be taught.[6]
The Jargon File, which famously calls bogosort "the archetypical [sic] perversely awful algorithm", also calls bubble sort "the generic bad algorithm".[7] Donald Knuth, in The Art of Computer Programming, concluded that "the bubble sort seems to have nothing to recommend it, except a catchy name and the fact that it leads to some interesting theoretical problems", some of which he then discusses.[8]
Bubble sort is asymptotically equivalent in running time to insertion sort in the worst case, but the two algorithms differ greatly in the number of swaps necessary. Experimental results such as those of Astrachan have also shown that insertion sort performs considerably better even on random lists. For these reasons, many modern algorithm textbooks avoid using the bubble sort algorithm in favor of insertion sort.
Bubble sort also interacts poorly with modern CPU hardware. It produces at least twice as many writes as insertion sort, twice as many cache misses, and asymptotically more branch mispredictions.[citation needed] Experiments by Astrachan sorting strings in Java show bubble sort to be roughly one-fifth as fast as an insertion sort and 70% as fast as a selection sort.[6]
In computer graphics, bubble sort is popular for its capability to detect a very small error (like a swap of just two elements) in almost-sorted arrays and fix it with just linear complexity (2n). For example, it is used in a polygon filling algorithm, where bounding lines are sorted by their x coordinate at a specific scan line (a line parallel to the x axis), and with incrementing y, their order changes (two elements are swapped) only at intersections of two lines. Bubble sort is a stable sort algorithm, like insertion sort.
Variations
[edit]- Odd–even sort is a parallel version of bubble sort, for message-passing systems.
- Passes can be from right to left, rather than left to right. This is more efficient for lists with unsorted items added to the end.
- Cocktail shaker sort alternates leftwards and rightwards passes.
Debate over name
[edit]Bubble sort has been occasionally referred to as a "sinking sort".[9]
For example, Donald Knuth describes the insertion of values at or towards their desired location as letting "[the value] settle to its proper level", and that "this method of sorting has sometimes been called the sifting or sinking technique.[10]
This debate is perpetuated by the ease with which one may consider this algorithm from two different but equally valid perspectives:
- The larger values might be regarded as heavier and therefore be seen to progressively sink to the bottom of the list
- The smaller values might be regarded as lighter and therefore be seen to progressively bubble up to the top of the list.
In popular culture
[edit]In a 2007 interview, former Google CEO Eric Schmidt asked then-presidential candidate Barack Obama about the best way to sort one million integers; Obama paused for a moment and replied: "I think the bubble sort would be the wrong way to go."[11][12]
Notes
[edit]- ^ Cortesi, Aldo (27 April 2007). "Visualising Sorting Algorithms". Retrieved 16 March 2017.
- ^ "[JDK-6804124] (coll) Replace "modified mergesort" in java.util.Arrays.sort with timsort - Java Bug System". bugs.openjdk.java.net. Retrieved 2020-01-11.
- ^ Peters, Tim (2002-07-20). "[Python-Dev] Sorting". Retrieved 2020-01-11.
- ^ "EDWARD FRIEND Obituary (2019) - Washington, DC - The Washington Post". Legacy.com.
- ^ Friend, Edward H. (1956). "Sorting on Electronic Computer Systems". Journal of the ACM. 3 (3): 134–168. doi:10.1145/320831.320833. S2CID 16071355.
- ^ a b Astrachan, Owen (2003). "Bubble sort: an archaeological algorithmic analysis" (PDF). ACM SIGCSE Bulletin. 35 (1): 1–5. doi:10.1145/792548.611918. ISSN 0097-8418.
- ^ "jargon, node: bogo-sort". www.jargon.net.
- ^ Donald Knuth. The Art of Computer Programming, Volume 3: Sorting and Searching, Second Edition. Addison-Wesley, 1998. ISBN 0-201-89685-0. Pages 106–110 of section 5.2.2: Sorting by Exchanging. "[A]lthough the techniques used in the calculations [to analyze the bubble sort] are instructive, the results are disappointing since they tell us that the bubble sort isn't really very good at all. Compared to straight insertion […], bubble sorting requires a more complicated program and takes about twice as long!" (Quote from the first edition, 1973.)
- ^ Black, Paul E. (24 August 2009). "bubble sort". Dictionary of Algorithms and Data Structures. National Institute of Standards and Technology. Retrieved 1 October 2014.
- ^ Knuth, Donald (1997). The Art of Computer Programming: Volume 3: Searching and Sorting. Addison-Wesley. p. 80. ISBN 0201896850.
- ^ Lai Stirland, Sarah (2007-11-14). "Obama Passes His Google Interview". Wired. Retrieved 2020-10-27.
- ^ Barack Obama, Eric Schmidt (Nov 14, 2007). Barack Obama | Candidates at Google (Video) (YouTube). Mountain View, CA 94043 The Googleplex: Talks at Google. Event occurs at 23:20. Archived from the original on September 7, 2019. Retrieved Sep 18, 2019.
{{cite AV media}}: CS1 maint: location (link)
References
[edit]- Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest, and Clifford Stein. Introduction to Algorithms, Second Edition. MIT Press and McGraw-Hill, 2001. ISBN 0-262-03293-7. Problem 2-2, pg.40.
- Sorting in the Presence of Branch Prediction and Caches
- Fundamentals of Data Structures by Ellis Horowitz, Sartaj Sahni and Susan Anderson-Freed ISBN 81-7371-605-6
- Owen Astrachan. Bubble Sort: An Archaeological Algorithmic Analysis
External links
[edit]- Martin, David R. (2007). "Animated Sorting Algorithms: Bubble Sort". Archived from the original on 2015-03-03. – graphical demonstration
- "Lafore's Bubble Sort". Archived from the original on 2008-01-19. Retrieved 2006-02-25. (Java applet animation)
- OEIS sequence A008302 (Table (statistics) of the number of permutations of [n] that need k pair-swaps during the sorting)
Bubble sort
View on GrokipediaAlgorithm Description
Core Mechanism
Bubble sort is a simple comparison-based sorting algorithm that operates by repeatedly traversing a list of elements, comparing adjacent pairs, and swapping them if they are in the incorrect order relative to the desired sorting direction, such as ascending or descending.[8] This process ensures that misplaced elements gradually move toward their correct positions through successive iterations. The algorithm assumes the input is an array or list of comparable elements, such as integers or other data types that support a total ordering, and requires no prior knowledge of the data's sorted state.[11] The name "bubble sort" derives from the "bubbling" effect observed during execution, where the largest (in ascending sort) or smallest (in descending sort) elements progressively rise to the end of the list, akin to bubbles rising in a liquid.[12] In each traversal, an element that is out of place will be swapped multiple times with its neighbors until it reaches its appropriate position at the boundary of the unsorted portion, simulating this upward movement. This mechanism relies solely on pairwise comparisons and adjacent swaps, making it straightforward but inefficient for large datasets, with a quadratic time complexity that is explored in greater detail elsewhere.[11] The algorithm's structure involves an outer loop that controls the number of passes through the list, typically iterating n-1 times for a list of n elements, as each pass positions one more element correctly at the end.[13] Within each outer iteration, an inner loop performs the comparisons and swaps, starting from the beginning of the list and proceeding up to the last unsorted index, which decreases by one after each pass to avoid re-examining the already sorted suffix. This reduction in the inner loop's range ensures that only the unsorted portion is processed in subsequent passes, optimizing the comparisons without altering the core logic.[14]Step-by-Step Example
To illustrate the bubble sort algorithm, consider the following unsorted array of five elements: [5, 3, 8, 4, 2]. The process involves repeated passes over the array, where in each pass, adjacent elements are compared from left to right, and any pair that is out of order (with the larger element preceding the smaller one) is swapped. This "bubbling" action gradually moves larger elements toward the end of the array.[8] The table below shows the state of the array after each comparison and swap during the passes. For an array of n = 5 elements, the algorithm requires up to n-1 = 4 passes, though it can potentially terminate early if the array becomes fully sorted before completing all passes. In this example, swaps occur in every pass until the array is sorted.| Pass | Comparisons and Swaps | Array State After Pass |
|---|---|---|
| Initial | - | [5, 3, 8, 4, 2] |
| 1 (largest element bubbles to end) | - Compare indices 0-1: 5 > 3, swap → [3, 5, 8, 4, 2] - Compare indices 1-2: 5 < 8, no swap - Compare indices 2-3: 8 > 4, swap → [3, 5, 4, 8, 2] - Compare indices 3-4: 8 > 2, swap → [3, 5, 4, 2, 8] | [3, 5, 4, 2, 8] |
| 2 (second-largest bubbles to second-last position) | - Compare indices 0-1: 3 < 5, no swap - Compare indices 1-2: 5 > 4, swap → [3, 4, 5, 2, 8] - Compare indices 2-3: 5 > 2, swap → [3, 4, 2, 5, 8] | [3, 4, 2, 5, 8] |
| 3 (third-largest bubbles to third-last position) | - Compare indices 0-1: 3 < 4, no swap - Compare indices 1-2: 4 > 2, swap → [3, 2, 4, 5, 8] | [3, 2, 4, 5, 8] |
| 4 (remaining elements sorted) | - Compare indices 0-1: 3 > 2, swap → [2, 3, 4, 5, 8] | [2, 3, 4, 5, 8] (sorted) |
Analysis
Time and Space Complexity
Bubble sort exhibits a time complexity of in both the worst and average cases, where is the number of elements in the array, as it performs comparisons regardless of the input arrangement.[15] This arises from the nested loop structure: the outer loop iterates times (from to ), and the inner loop executes comparisons per iteration of the outer loop.[15] The total number of comparisons is thus given by the summationPerformance Behaviors
Bubble sort is a stable sorting algorithm, meaning it preserves the relative order of elements with equal keys in the input array. This property arises because the algorithm only performs swaps between adjacent elements that are out of order, ensuring that equal elements are never swapped unnecessarily.[16][3] The algorithm exhibits partial adaptivity in that it can complete fewer passes through nearly sorted data when implemented with an early termination flag that checks for swaps in each pass; however, the basic version without such a flag remains quadratic in time complexity regardless of input order.[16][17] As an in-place sorting method, bubble sort requires no additional memory proportional to the input size beyond a constant amount for variables like indices and flags, making it suitable for environments with limited memory availability.[3][18] Despite these traits, bubble sort suffers from significant drawbacks in efficiency, including a high number of unnecessary comparisons even when the input is already sorted, as it always performs a fixed number of passes without early stopping. Additionally, its repeated traversals can lead to suboptimal cache performance in modern hardware due to the pattern of accesses, though its adjacent swaps maintain some locality.[19][20]Rabbits and Turtles Effect
In bubble sort, the rabbits and turtles effect describes the asymmetric movement patterns of elements during sorting, particularly evident in random input permutations. Rabbits refer to large elements positioned near the beginning of the array, which rapidly "bubble" to the right toward their final positions through successive swaps in early passes. In contrast, turtles denote small elements located near the end, which advance leftward slowly, often requiring nearly as many passes as the array length to reach the front.[21] This phenomenon arises from the algorithm's pairwise adjacent comparisons and swaps, where each pass fixes the largest unsorted element at the end but only shifts smaller elements one position leftward per iteration. According to Donald E. Knuth's analysis in random permutations, large elements tend to travel far to the right early in the process, as they participate in multiple swaps during initial passes, while small elements lag behind, often remaining misplaced until later stages.[22] For instance, in a conceptual random array of length , the largest element starting at the beginning may undergo up to rightward swaps across the first pass alone if it is larger than all succeeding elements, yet smaller elements' progress remains gradual over subsequent passes. The rabbits and turtles effect contributes to bubble sort's inefficiency by elevating the total number of swaps beyond what might be expected from uniform element movement, as turtles necessitate additional full passes to resolve their positions. This pattern exacerbates the quadratic time complexity in average cases for random data, highlighting why variants like cocktail sort address turtles by incorporating reverse passes.[23]Implementation
Pseudocode
The standard pseudocode for the unoptimized bubble sort algorithm, which sorts an array of comparable elements in ascending order, is presented below. This formulation uses nested loops to iteratively compare and swap adjacent elements that are out of order, ensuring larger elements progressively "bubble" toward the end of the array.[24][25]procedure bubbleSort(arr: array of integers, n: integer)
for i from 0 to n-2 do
for j from 0 to n-i-2 do
if arr[j] > arr[j+1] then
swap arr[j] and arr[j+1]
end if
end for
end for
end procedure
The outer loop, indexed by i from 0 to n-2, represents the n-1 passes through the array, where each pass fixes the position of the next largest element at the end.[24] The inner loop, indexed by j from 0 to n-i-2, performs adjacent pairwise comparisons and potential swaps up to the unsorted portion of the array, reducing the comparison range by one element per outer iteration to avoid redundant work on already-sorted suffixes and to prevent accessing an out-of-bounds index when comparing arr[j] and arr[j+1].[25][26]
This pseudocode assumes 0-based indexing for the array and sorts elements in non-decreasing (ascending) order by using the strict greater-than (>) comparison, which only swaps when necessary.[24] It is stable, meaning that equal elements maintain their relative order since swaps occur only for strictly unequal adjacent pairs, preserving the original sequence of duplicates.[3] The algorithm can be adapted for descending order by replacing the > operator with < in the comparison.[27]
Language-Specific Examples
Bubble sort implementations in popular programming languages closely follow the abstract pseudocode structure, adapting to each language's syntax for data structures, loops, and element swapping. These examples demonstrate unoptimized versions that perform full passes regardless of early sorting, focusing on integer arrays or lists for clarity.Python
Python's dynamic typing and built-in list support enable concise implementations without explicit type declarations or size parameters beyond the list length. Swapping uses tuple assignment, which is efficient and readable.def bubble_sort(arr):
n = len(arr)
for i in range(n):
for j in range(0, n - i - 1):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
This function modifies the input list in place and returns nothing, aligning with Python's emphasis on mutable sequences.[10]
A common implementation mistake is using range(0, n - i) for the inner loop instead of range(0, n - i - 1). This causes the loop to iterate one too many times, resulting in an IndexError when attempting to access arr[j + 1] where j reaches n - i - 1 and j + 1 equals n - i, which is out of bounds. For example, with n=5 and i=0, j goes to 4, trying to compare arr[4] and arr[5], but index 5 does not exist.[26]
C++
In C++, arrays require explicit sizing and pointer handling, with the<algorithm> header providing std::swap for safe element exchange. The function operates on a fixed-size array passed by pointer, ensuring no bounds issues within the loops.
#include <algorithm> // for std::swap
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
std::swap(arr[j], arr[j + 1]);
}
}
}
}
Static typing in C++ demands careful array management, differing from dynamic languages, and the void return type indicates in-place modification.[28]
Java
Java's fixed-size arrays and object-oriented paradigm require length access via.length, with manual temporary variables for swapping to avoid built-in utilities in basic implementations. The static method suits utility classes for sorting.
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
Like C++, Java enforces static typing but includes automatic garbage collection, simplifying memory handling compared to manual allocation in C++.[11]
These examples illustrate key language differences: Python prioritizes simplicity with dynamic structures, while C++ and Java emphasize explicit control over static arrays, all achieving in-place sorting without additional space beyond the input.
Optimizations and Variations
Standard Optimizations
One common optimization to the basic bubble sort algorithm involves reducing the range of the inner loop in each pass. After the ith pass, the last i elements are guaranteed to be in their correct sorted positions, so subsequent passes need only compare and swap up to the unsorted portion of the array, specifically from index 0 to n-i-2. This adjustment halves the number of comparisons in the unoptimized version, changing the total from (n-1)^2 to n(n-1)/2 for the worst case.[29] The following pseudocode illustrates this reduced inner loop:for i from 0 to n-2:
for j from 0 to n-i-2:
if array[j] > array[j+1]:
swap array[j] and array[j+1]
This optimization is inherent to the standard formulation of bubble sort and focuses on eliminating redundant checks on already-sorted suffixes.[17]
A further enhancement introduces a boolean flag, often named "swapped," to enable early termination. At the start of each outer loop iteration, the flag is set to false; it is then set to true whenever a swap occurs in the inner loop. If the flag remains false after a full pass—indicating no swaps were needed—the array is fully sorted, and the algorithm can exit immediately. This prevents unnecessary passes over sorted data. The modified pseudocode incorporating both the reduced inner loop and the swapped flag is:
swapped = true
i = 0
while i < n-1 and swapped:
swapped = false
for j from 0 to n-i-2:
if array[j] > array[j+1]:
swap array[j] and array[j+1]
swapped = true
i = i + 1
This flag-based approach is widely adopted in educational and practical implementations to improve efficiency on partially sorted inputs.[17][29]
Another standard tweak is the cocktail shaker sort, a bidirectional variant that alternates passes from left-to-right and right-to-left to bubble both large and small elements toward their positions more quickly; however, its full mechanics are covered among notable variants.[5][30]
These optimizations yield a best-case time complexity of O(n) for already sorted arrays due to early termination after one pass, while the average- and worst-case complexities remain O(n²), offering only marginal improvements for random inputs. Space complexity stays O(1) as an in-place algorithm.[31][17]