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++ 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;
} |
# 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# 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();
}
} |
// 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 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));
}
} |
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.