Open In App

Introduction to Smooth Sort

Last Updated : 15 Apr, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Smooth sort is a sorting algorithm that was introduced by Edsger Dijkstra. It is another version of heapsort that is designed to minimize the number of comparisons performed during the sort. Like heapsort, smooth sort sorts an array by building a heap and repeatedly extracting the maximum element.

  • However, smooth sort uses a different data structure when compared to heap sort. Specifically, it uses a data structure called the Leonardo heap, which is a binary tree with the property that the root of each subtree has one fewer element than its parent. 
  • The shape of the Leonardo heap is determined by a sequence of numbers called the Leonardo.

Approach: Smooth sort approach is as follows:

  • Define the Leonardo numbers. 
  • Build the Leonardo heap by merging pairs of adjacent trees. 
    • Initialize p to the last index in the array. 
    •  Initialize q and r to p. 
    • While p > 0
         If the size of the subtree rooted at r is p, increment r. 
         Otherwise, decrement r, update q, and heapify the subtree rooted at r. 
         Swap the root element of the heap (at index 0) with the element at index p. 
         Decrement p. 
  • Convert the Leonardo heap back into an array.  For each pair of adjacent elements in the array: 
    • If the second element is smaller than the first, swap them. 
    • Iterate through the array in reverse order, swapping each pair of adjacent elements that are out of order.

Working of Smooth sort:

Using the Leonardo numbers, create initial Leonardo heaps by finding the largest Leonardo number that is less than or equal to n, and splitting the list into two sublists such that the first sublist has a length equal to the preceding Leonardo number and the second sublist has length equal to the preceding two Leonardo numbers.   
Sublist 1: [1, 7, 8]
Sublist 2: [2, 3, 5, 4, 6]
   
Iteration 1:
   Heap 1: [8]
   Heap 2: [7, 1]
   Heap 3: [6, 5, 4, 3, 2]

Iteration 2:
   Heap 1: [8, 7, 1]
   Heap 2: [6, 5, 4, 3, 2]

Iteration 3:
   Heap 1: [8, 7, 1, 6, 5, 4, 3, 2]

Sorted List: [8, 7, 6, 5, 4, 3, 2, 1]

Below is the implementation of the code:

C++




// C++ implementation
 
#include <iostream>
#include <vector>
 
using namespace std;
 
// Define the Leonardo numbers
int leonardo(int k)
{
    if (k < 2) {
        return 1;
    }
    return leonardo(k - 1) + leonardo(k - 2) + 1;
}
 
// Build the Leonardo heap by merging
// pairs of adjacent trees
void heapify(vector<int>& arr, int start, int end)
{
    int i = start;
    int j = 0;
    int k = 0;
 
    while (k < end - start + 1) {
        if (k & 0xAAAAAAAA) {
            j = j + i;
            i = i >> 1;
        }
        else {
            i = i + j;
            j = j >> 1;
        }
 
        k = k + 1;
    }
 
    while (i > 0) {
        j = j >> 1;
        k = i + j;
        while (k < end) {
            if (arr[k] > arr[k - i]) {
                break;
            }
            swap(arr[k], arr[k - i]);
            k = k + i;
        }
 
        i = j;
    }
}
 
// Smooth Sort function
vector<int> smooth_sort(vector<int>& arr)
{
    int n = arr.size();
 
    int p = n - 1;
    int q = p;
    int r = 0;
 
    // Build the Leonardo heap by merging
    // pairs of adjacent trees
    while (p > 0) {
        if ((r & 0x03) == 0) {
            heapify(arr, r, q);
        }
 
        if (leonardo(r) == p) {
            r = r + 1;
        }
        else {
            r = r - 1;
            q = q - leonardo(r);
            heapify(arr, r, q);
            q = r - 1;
            r = r + 1;
        }
 
        swap(arr[0], arr[p]);
        p = p - 1;
    }
 
    // Convert the Leonardo heap
    // back into an array
    for (int i = 0; i < n - 1; i++) {
        int j = i + 1;
        while (j > 0 && arr[j] < arr[j - 1]) {
            swap(arr[j], arr[j - 1]);
            j = j - 1;
        }
    }
 
    return arr;
}
 
// Driver code
int main()
{
    vector<int> arr = { 1, 7, 8, 2, 3, 5, 4, 6 };
 
    // Original Array
    cout << "Input:   ";
    for (int i = 0; i < arr.size(); i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
 
    // Function call
    arr = smooth_sort(arr);
 
    // Sorted Array
    cout << "Output:  ";
    for (int i = 0; i < arr.size(); i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
 
    return 0;
}


Python3




# Python Implementation
 
 
def smooth_sort(arr):
    n = len(arr)
 
    # Define the Leonardo numbers
    def leonardo(k):
        if k < 2:
            return 1
        return leonardo(k - 1) + leonardo(k - 2) + 1
 
    # Build the Leonardo heap by merging
    # pairs of adjacent trees
    def heapify(start, end):
        i = start
        j = 0
        k = 0
 
        while k < end - start + 1:
            if k & 0xAAAAAAAA:
                j = j + i
                i = i >> 1
            else:
                i = i + j
                j = j >> 1
 
            k = k + 1
 
        while i > 0:
            j = j >> 1
            k = i + j
            while k < end:
                if arr[k] > arr[k - i]:
                    break
                arr[k], arr[k - i] = arr[k - i], arr[k]
                k = k + i
 
            i = j
 
    # Build the Leonardo heap by merging
    # pairs of adjacent trees
    p = n - 1
    q = p
    r = 0
    while p > 0:
        if (r & 0x03) == 0:
            heapify(r, q)
 
        if leonardo(r) == p:
            r = r + 1
        else:
            r = r - 1
            q = q - leonardo(r)
            heapify(r, q)
            q = r - 1
            r = r + 1
 
        arr[0], arr[p] = arr[p], arr[0]
        p = p - 1
 
    # Convert the Leonardo heap
    # back into an array
    for i in range(n - 1):
        j = i + 1
        while j > 0 and arr[j] < arr[j - 1]:
            arr[j], arr[j - 1] = arr[j - 1], arr[j]
            j = j - 1
 
    return arr
 
 
# Driver ccode
arr = [1, 7, 8, 2, 3, 5, 4, 6]
 
# Original Array
print('Input:   ', arr)
 
# Function call
print("Output:  ", smooth_sort(arr))


C#




// C# code for the approach
 
using System;
using System.Collections.Generic;
 
public class SmoothSort {
    // Define the Leonardo numbers
    private static int Leonardo(int k) {
        if (k < 2) {
            return 1;
        }
        return Leonardo(k - 1) + Leonardo(k - 2) + 1;
    }
 
    // Build the Leonardo heap by merging
    // pairs of adjacent trees
    private static void Heapify(List<int> arr, int start, int end) {
        int i = start;
        int j = 0;
        int k = 0;
 
        while (k < end - start + 1) {
            if ((k & 0xAAAAAAAA) == 0xAAAAAAAA) {
                j += i;
                i >>= 1;
            } else {
                i += j;
                j >>= 1;
            }
 
            k++;
        }
 
        while (i > 0) {
            j >>= 1;
            int l = i + j;
            while (l < end) {
                if (arr[l] > arr[l - i]) {
                    break;
                }
                int temp = arr[l];
                arr[l] = arr[l - i];
                arr[l - i] = temp;
                l += i;
            }
 
            i = j;
        }
    }
 
    // Smooth Sort function
    public static List<int> Sort(List<int> arr) {
        int n = arr.Count;
 
        int p = n - 1;
        int q = p;
        int r = 0;
 
        // Build the Leonardo heap by merging
        // pairs of adjacent trees
        while (p > 0) {
            if ((r & 0x03) == 0) {
                Heapify(arr, r, q);
            }
 
            if (Leonardo(r) == p) {
                r++;
            } else {
                r--;
                q -= Leonardo(r);
                Heapify(arr, r, q);
                q = r - 1;
                r++;
            }
 
            int temp = arr[0];
            arr[0] = arr[p];
            arr[p] = temp;
            p--;
        }
 
        // Convert the Leonardo heap
        // back into an array
        for (int i = 0; i < n - 1; i++) {
            int j = i + 1;
            while (j > 0 && arr[j] < arr[j - 1]) {
                int temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
                j--;
            }
        }
 
        return arr;
    }
 
    // Driver code
    public static void Main() {
        List<int> arr = new List<int> { 1, 7, 8, 2, 3, 5, 4, 6 };
 
        // Original Array
        Console.Write("Input:   ");
        foreach (int num in arr) {
            Console.Write(num + " ");
        }
        Console.WriteLine();
 
        // Function call
        arr = Sort(arr);
 
        // Sorted Array
        Console.Write("Output:  ");
        foreach (int num in arr) {
            Console.Write(num + " ");
        }
        Console.WriteLine();
    }
}


Javascript




// Define the Leonardo numbers
function leonardo(k) {
  if (k < 2) {
    return 1;
  }
  return leonardo(k - 1) + leonardo(k - 2) + 1;
}
 
// Build the Leonardo heap by merging
// pairs of adjacent trees
function heapify(arr, start, end) {
  let i = start;
  let j = 0;
  let k = 0;
 
  while (k < end - start + 1) {
    if (k & 0xAAAAAAAA) {
      j = j + i;
      i = i >> 1;
    } else {
      i = i + j;
      j = j >> 1;
    }
 
    k = k + 1;
  }
 
  while (i > 0) {
    j = j >> 1;
    k = i + j;
    while (k < end) {
      if (arr[k] > arr[k - i]) {
        break;
      }
      [arr[k], arr[k - i]] = [arr[k - i], arr[k]];
      k = k + i;
    }
 
    i = j;
  }
}
 
// Smooth Sort function
function smooth_sort(arr) {
  const n = arr.length;
 
  let p = n - 1;
  let q = p;
  let r = 0;
 
  // Build the Leonardo heap by merging
  // pairs of adjacent trees
  while (p > 0) {
    if ((r & 0x03) == 0) {
      heapify(arr, r, q);
    }
 
    if (leonardo(r) == p) {
      r = r + 1;
    } else {
      r = r - 1;
      q = q - leonardo(r);
      heapify(arr, r, q);
      q = r - 1;
      r = r + 1;
    }
 
    [arr[0], arr[p]] = [arr[p], arr[0]];
    p = p - 1;
  }
 
  // Convert the Leonardo heap
  // back into an array
  for (let i = 0; i < n - 1; i++) {
    let j = i + 1;
    while (j > 0 && arr[j] < arr[j - 1]) {
      [arr[j], arr[j - 1]] = [arr[j - 1], arr[j]];
      j = j - 1;
    }
  }
 
  return arr;
}
 
// Driver code
function main() {
  const arr = [1, 7, 8, 2, 3, 5, 4, 6];
 
  // Original Array
  console.log("Input:   " + arr.join(" "));
 
  // Function call
  const sortedArr = smooth_sort(arr);
 
  // Sorted Array
  console.log("Output:  " + sortedArr.join(" "));
}
 
main();


Java




// Java implementation
import java.util.Arrays;
 
public class SmoothSort {
 
    // Define the Leonardo numbers
    static int leonardo(int k)
    {
        if (k < 2) {
            return 1;
        }
        return leonardo(k - 1) + leonardo(k - 2) + 1;
    }
 
    // Build the Leonardo heap by merging
    // pairs of adjacent trees
    static void heapify(int[] arr, int start, int end)
    {
        int i = start;
        int j = 0;
        int k = 0;
 
        while (k < end - start + 1) {
            if ((k & 0xAAAAAAAA) != 0) {
                j = j + i;
                i = i >> 1;
            }
            else {
                i = i + j;
                j = j >> 1;
            }
 
            k = k + 1;
        }
 
        while (i > 0) {
            j = j >> 1;
            k = i + j;
            while (k < end) {
                if (arr[k] > arr[k - i]) {
                    break;
                }
                int temp = arr[k];
                arr[k] = arr[k - i];
                arr[k - i] = temp;
                k = k + i;
            }
 
            i = j;
        }
    }
 
    // Smooth Sort function
    static int[] smoothSort(int[] arr)
    {
        int n = arr.length;
 
        int p = n - 1;
        int q = p;
        int r = 0;
 
        // Build the Leonardo heap by merging
        // pairs of adjacent trees
        while (p > 0) {
            if ((r & 0x03) == 0) {
                heapify(arr, r, q);
            }
 
            if (leonardo(r) == p) {
                r = r + 1;
            }
            else {
                r = r - 1;
                q = q - leonardo(r);
                heapify(arr, r, q);
                q = r - 1;
                r = r + 1;
            }
 
            int temp = arr[0];
            arr[0] = arr[p];
            arr[p] = temp;
            p = p - 1;
        }
 
        // Convert the Leonardo heap
        // back into an array
        for (int i = 0; i < n - 1; i++) {
            int j = i + 1;
            while (j > 0 && arr[j] < arr[j - 1]) {
                int temp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = temp;
                j = j - 1;
            }
        }
 
        return arr;
    }
 
    // Driver code
    public static void main(String[] args)
    {
        int[] arr = { 1, 7, 8, 2, 3, 5, 4, 6 };
 
        // Original Array
        System.out.print("Input:   ");
        System.out.println(Arrays.toString(arr));
 
        // Function call
        arr = smoothSort(arr);
 
        // Sorted Array
        System.out.print("Output:  ");
        System.out.println(Arrays.toString(arr));
    }
}


Output

Input:    [1, 7, 8, 2, 3, 5, 4, 6]
Output:   [1, 2, 3, 4, 5, 6, 7, 8]

Time Complexity: O(nlogn), where n is the size of the input.
Auxiliary Space: O(1)

Advantages of Smooth Sort:

  • Smooth Sort is an adaptive sorting algorithm, meaning that it performs well on partially sorted lists.
  • The algorithm has a time complexity of O(n log n), which is the same as merge sort and heap sort.
  • Smooth Sort uses a small amount of extra memory and has a low memory overhead compared to other sorting algorithms, such as merge sort.
  • The algorithm is stable, meaning that it preserves the relative order of equal elements in the list.

Disadvantages of Smooth Sort:

  • Smooth Sort is a complex algorithm, and it is more difficult to implement than some other sorting algorithms, such as insertion sort.
  • The algorithm requires the use of Leonardo numbers, which are a less well-known mathematical concept, so the algorithm may not be as widely used or understood as other algorithms.

Why Smooth Sort Better Than Other Sorting Algorithms?

  • Smooth sort also has a low memory footprint compared to some other sorting algorithms. This can be important in situations where memory usage is a concern.
  • Overall, while smooth sorting may not be the best choice for all sorting scenarios, it can be a good choice in situations where data is partially sorted or contains a large number of duplicates.
  • Smooth sort is an adaptive sorting algorithm, meaning that it can adjust its behavior based on the characteristics of the input data. This allows smooth sorting to be more efficient than non-adaptive sorting algorithms in certain situations.


Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads