Shell Sort Algorithm

Shell Sort is an in-place comparison-based sorting algorithm that generalizes the insertion sort algorithm to allow the exchange of items that are far apart. It is named after its inventor, Donald Shell, who introduced it in 1959. Shell Sort is more efficient than simple algorithms like bubble sort and insertion sort, particularly for larger lists, due to its improved time complexity.

How Shell Sort Works:

  1. Gap Sequence:
    • The core concept of Shell Sort involves using a gap sequence to determine which elements to compare and sort. Initially, elements that are far apart are compared and then the gap between elements is gradually reduced to perform a final insertion sort with a gap of 1.
  2. Gap Insertion Sort:
    • The algorithm starts with a large gap between compared elements, which allows elements to move quickly towards their final position.
    • In each pass, elements that are gap distance apart are compared and swapped if they are in the wrong order.
  3. Reduction of Gap:
    • The gap is progressively reduced according to a specific sequence until it becomes 1. Common gap sequences include:
      • Shell’s original sequence: gap=βŒŠπ‘›2βŒ‹,βŒŠπ‘›4βŒ‹,…,1gap=⌊2nβ€‹βŒ‹,⌊4nβ€‹βŒ‹,…,1
      • Hibbard’s sequence: 1,3,7,15,…,2π‘˜βˆ’11,3,7,15,…,2kβˆ’1
      • Knuth’s sequence: 1,4,13,40,…,3π‘˜βˆ’121,4,13,40,…,23kβˆ’1​
  4. Final Pass:
    • When the gap is finally reduced to 1, the algorithm performs a standard insertion sort. By this stage, most elements are already close to their final sorted position, making the final pass efficient.

Characteristics of Shell Sort:

  • Time Complexity:
    • The time complexity of Shell Sort depends on the chosen gap sequence. It can range from 𝑂(𝑛3/2)O(n3/2) to 𝑂(𝑛log⁑2𝑛)O(nlog2n) in practical implementations, but the worst-case time complexity can be 𝑂(𝑛2)O(n2) with some sequences.
    • Average Case: Typically 𝑂(𝑛3/2)O(n3/2) or better with optimal gap sequences.
    • Worst Case: 𝑂(𝑛2)O(n2), but rarely encountered with good gap sequences.
  • Space Complexity:
    • Shell Sort is an in-place sorting algorithm, requiring only a constant amount 𝑂(1)O(1) of additional memory space.
  • Stability:
    • Shell Sort is not a stable sorting algorithm. Stability refers to preserving the relative order of records with equal keys (i.e., values).
  • Usage:
    • Shell Sort is useful for medium-sized arrays or lists where more sophisticated algorithms like Quick Sort or Merge Sort are not necessary. Its efficiency makes it a good choice for systems with limited resources.

Code Example

def shell_sort(arr):
    n = len(arr)
    gap = n // 2

    # Start with a big gap, then reduce the gap
    while gap > 0:
        # Do a gapped insertion sort for this gap size.
        # The first gap elements arr[0..gap-1] are already in gapped order
        for i in range(gap, n):
            temp = arr[i]
            j = i
            # Shift earlier gap-sorted elements up until the correct location
            # for arr[i] is found
            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
            # Put temp (the original arr[i]) in its correct location
            arr[j] = temp
        gap //= 2
    return arr

# Example usage
arr = [12, 34, 54, 2, 3]
sorted_arr = shell_sort(arr)
print("Sorted array is:", sorted_arr)

Code Explanation

Function Definition

def shell_sort(arr):
  • The function shell_sort is defined to take a single list arr as its parameter.

Initialize Variables

    n = len(arr)
    gap = n // 2
  • The variable n holds the length of the array.
  • The variable gap is initialized to half the length of the array. The gap determines the intervals at which elements are compared and sorted.

Outer While Loop

    while gap > 0:
  • The while loop runs as long as gap is greater than 0. The gap is reduced in each iteration, performing gapped insertion sort for each gap size.

Inner For Loop

        for i in range(gap, n):
            temp = arr[i]
            j = i
  • The for loop starts from the element at index gap and runs to the end of the array.
  • The variable temp holds the value of the current element to be compared and inserted.
  • The variable j is initialized to the current index i.

Gapped Insertion Sort

            while j >= gap and arr[j - gap] > temp:
                arr[j] = arr[j - gap]
                j -= gap
  • The while loop compares the current element temp with the element at index j - gap. If temp is smaller, the element at j - gap is shifted to the right.
  • The index j is decremented by gap to continue comparing and shifting elements.

Inserting the Element

            arr[j] = temp
  • Once the correct position is found (when j is less than gap or temp is greater than or equal to arr[j - gap]), the value of temp is inserted at index j.

Reduce the Gap

        gap //= 2
  • The gap is reduced by half for the next iteration of the outer while loop.

Return Statement

    return arr
  • The sorted array arr is returned.

Example Usage

arr = [12, 34, 54, 2, 3]
sorted_arr = shell_sort(arr)
print("Sorted array is:", sorted_arr)
  • An example list arr is sorted using the shell_sort function, and the sorted list is printed.

Output

Sorted array is: [2, 3, 12, 34, 54]
  • The final output is the sorted array in ascending order.