Introduction to Smooth Sort
Last Updated :
15 Apr, 2023
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));
}
}
OutputInput: [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.
Similar Reads
Introduction to Block Sort
Block sort is a sorting algorithm that sorts an array by dividing it into blocks of fixed size, sorting each block individually, and then merging the sorted blocks back into a single sorted array. Block sort is a good choice for sorting large datasets that do not fit in memory. It can efficiently so
10 min read
Introduction to Grail Sort
In this article, we will discuss the grail sort. Grail sort is a sorting algorithm that was introduced by Vladimir Yaroslavskiy. It is an efficient sorting algorithm for large data sets that have a lot of duplicate values. The name "grail" refers to the fact that the algorithm is based on the idea o
10 min read
Introduction to Exchange Sort Algorithm
Exchange sort is an algorithm used to sort in ascending as well as descending order. It compares the first element with every element if any element seems out of order it swaps. Example: Input: arr[] = {5, 1, 4, 2, 8}Output: {1, 2, 4, 5, 8}Explanation: Working of exchange sort: 1st Pass: Exchange so
10 min read
Python sorted containers | An Introduction
Sorted Containers is a powerful Python library that provides fast and easy-to-use implementations of SortedList, SortedDict and SortedSet data types. Unlike Pythonâs built-in types, these containers maintain their elements in sorted order automatically as elements are added or removed. To use this l
3 min read
Insertion sort using C++ STL
Implementation of Insertion Sort using STL functions. Pre-requisites : Insertion Sort, std::rotate, std::upper_bound, C++ Iterators. The idea is to use std::upper_bound to find an element making the array unsorted. Then we can rotate the unsorted part so that it ends up sorted. We can traverse the a
1 min read
Python sorted() Function
sorted() function returns a new sorted list from the elements of any iterable like (e.g., list, tuples, strings ). It creates and returns a new sorted list and leaves the original iterable unchanged. Let's start with a basic example of sorting a list of numbers using the sorted() function.Pythona =
3 min read
Introsort - C++âs Sorting Weapon
We have discussed sorting weapons used by different languages in previous article. In this article, C++âs Sorting Weapon, Introsort is discussed. What is Introsort? Simply putting, it is the best sorting algorithm around. It is a hybrid sorting algorithm, which means that it uses more than one sorti
7 min read
Counting Sort - Python
Counting Sort is a non-comparison-based sorting algorithm. It is particularly efficient when the range of input values is small compared to the number of elements to be sorted. The basic idea behind Counting Sort is to count the frequency of each distinct element in the input array and use that info
6 min read
Top Sorting Interview Questions and Problems
Here is the collection of the Top 50 list of frequently asked interview questions on Sorting. Problems in this article are divided into three Levels so that readers can practice according to the difficulty level step by step. Easy Problems Duplicates within k distanceMaximum Perimeter TriangleMaximi
5 min read
Bucket Sort vs Quick Sort
Bucket Sort and Quick Sort are two different sorting algorithms, each with its own characteristics, advantages, and disadvantages. In this article, we will provide a detailed overview of all the differences between Bucket Sort and Quick Sort. Bucket Sort:Bucket Sort is a non-comparison sorting algor
3 min read