Sort a nearly sorted (or K sorted) array
Last Updated :
12 Apr, 2023
Given an array of N elements, where each element is at most K away from its target position, devise an algorithm that sorts in O(N log K) time.
Examples:
Input: arr[] = {6, 5, 3, 2, 8, 10, 9}, K = 3
Output: arr[] = {2, 3, 5, 6, 8, 9, 10}
Input: arr[] = {10, 9, 8, 7, 4, 70, 60, 50}, k = 4
Output: arr[] = {4, 7, 8, 9, 10, 50, 60, 70}
Sort a nearly sorted (or K sorted) array using insertion sort:
To solve the problem follow the below idea:
We can use insertion sort to sort the array efficiently as index of every element can be changed by atmost K places, which will reduce the time complexity of this algorithm from O(N2) to O(NK).
Follow the below steps to solve the problem:
- Iterate from arr[1] to arr[N] over the array.
- Compare the current element (key) to its predecessor.
- If the key element is smaller than its predecessor, compare it to the elements before. Move the greater elements one position up to make space for the swapped element.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void insertionSort( int A[], int size)
{
int i, key, j;
for (i = 1; i < size; i++) {
key = A[i];
j = i - 1;
while (j >= 0 && A[j] > key) {
A[j + 1] = A[j];
j = j - 1;
}
A[j + 1] = key;
}
for ( int i=0; i<size; i++)
cout<<A[i]<< " " ;
cout<<endl;
}
int main()
{
int A[] = {6, 5, 3, 2, 8, 10, 9};
int size = 7;
insertionSort(A, size);
return 0;
}
|
C
void insertionSort( int A[], int size)
{
int i, key, j;
for (i = 1; i < size; i++) {
key = A[i];
j = i - 1;
while (j >= 0 && A[j] > key) {
A[j + 1] = A[j];
j = j - 1;
}
A[j + 1] = key;
}
}
|
Java
static void insertionSort( int A[], int size)
{
int i, key, j;
for (i = 1 ; i < size; i++) {
key = A[i];
j = i - 1 ;
while (j >= 0 && A[j] > key) {
A[j + 1 ] = A[j];
j = j - 1 ;
}
A[j + 1 ] = key;
}
}
|
Python3
def insertionSort(A, size):
i, key, j = 0 , 0 , 0
for i in range (size):
key = A[i]
j = i - 1
while j > = 0 and A[j] > key:
A[j + 1 ] = A[j]
j = j - 1
A[j + 1 ] = key
|
C#
static void insertionSort( int A[], int size)
{
int i, key, j;
for (i = 1; i < size; i++) {
key = A[i];
j = i - 1;
while (j >= 0 && A[j] > key) {
A[j + 1] = A[j];
j = j - 1;
}
A[j + 1] = key;
}
}
|
Javascript
function insertionSort(A, size)
{
var i, key, j;
for (i = 1; i < size; i++)
{
key = A[i];
j = i-1;
while (j >= 0 && A[j] > key)
{
A[j+1] = A[j];
j = j-1;
}
A[j+1] = key;
}
}
|
Time Complexity: O(N*K), The inner loop will run at most K times. To move every element to its correct place, at most K elements need to be moved.
Auxiliary Space: O(1)
Another Approach:
In this modified algorithm, we only shift elements to the right if the current element is more than k positions away from its correct position. This optimization takes advantage of the fact that the elements are already nearly sorted and reduces the number of operations performed, resulting in a faster sorting algorithm for nearly sorted arrays.
C++
#include <bits/stdc++.h>
using namespace std;
void sortNearlySortedArray( int A[], int size, int k)
{
int i, key, j;
for (i = 1; i < size; i++) {
key = A[i];
j = i - 1;
while (j >= max(0, i - k) && A[j] > key) {
A[j + 1] = A[j];
j--;
}
A[j + 1] = key;
}
for ( int i=0; i<size; i++)
cout<<A[i]<< " " ;
cout<<endl;
}
int main()
{
int A[] = {2, 6, 3, 12, 56, 8};
int size = 6;
int k = 3;
sortNearlySortedArray(A, size, k);
return 0;
}
|
Java
import java.util.Scanner;
class Main {
static void sortNearlySortedArray( int A[], int size, int k) {
int i, key, j;
for (i = 1 ; i < size; i++) {
key = A[i];
j = i - 1 ;
while (j >= Math.max( 0 , i - k) && A[j] > key) {
A[j + 1 ] = A[j];
j--;
}
A[j + 1 ] = key;
}
for (i= 0 ; i<size; i++)
System.out.print(A[i] + " " );
}
public static void main(String[] args) {
int A[] = { 2 , 6 , 3 , 12 , 56 , 8 };
int size = 6 ;
int k = 3 ;
sortNearlySortedArray(A, size, k);
}
}
|
Python3
def sortNearlySortedArray(A, size, k):
for i in range ( 1 , size):
key = A[i]
j = i - 1
while j > = max ( 0 , i - k) and A[j] > key:
A[j + 1 ] = A[j]
j - = 1
A[j + 1 ] = key
for i in range (size):
print (A[i], end = ' ' )
print ()
A = [ 2 , 6 , 3 , 12 , 56 , 8 ]
size = 6
k = 3
sortNearlySortedArray(A, size, k)
|
C#
using System;
public class GFG {
public static void
SortNearlySortedArray( int [] arr, int size, int k)
{
int i, key, j;
for (i = 1; i < size; i++) {
key = arr[i];
j = i - 1;
while (j >= Math.Max(0, i - k)
&& arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
for (i = 0; i < size; i++)
Console.Write(arr[i] + " " );
Console.WriteLine();
}
public static void Main( string [] args) {
int [] arr = { 10, 9, 8, 7, 4, 70, 60, 50 };
int size = 8;
int k = 4;
SortNearlySortedArray(arr, size, k);
}
}
|
Javascript
function sortNearlySortedArray(A, size, k) {
let i, key, j;
for (i = 1; i < size; i++) {
key = A[i];
j = i - 1;
while (j >= Math.max(0, i - k) && A[j] > key) {
A[j + 1] = A[j];
j--;
}
A[j + 1] = key;
}
console.log(A.join( " " ));
}
const A = [2, 6, 3, 12, 56, 8];
const size = 6;
const k = 3;
sortNearlySortedArray(A, size, k);
|
Time complexity: The time complexity of the sortNearlySortedArray function is O(nk) because in the worst case scenario, each element of the array may need to be compared to k elements on its left to find its correct position.
Auxiliary Space: The space complexity of this function is O(1), because only a constant amount of extra space is required, regardless of the size of the input array.
Sort a nearly sorted (or K sorted) array using heap:
Follow the below steps to solve the problem:
- Create a Min Heap of size K+1 with the first K+1 elements. We are creating a heap of size K as the element can be at most K distance from its index in a sorted array.
- One by one remove the min element from the heap, put it in the result array, and add a new element to the heap from the remaining elements.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
void sortK( int arr[], int n, int k)
{
int size;
size = (n == k) ? k : k + 1;
priority_queue< int , vector< int >, greater< int > > pq(
arr, arr + size);
int index = 0;
for ( int i = k + 1; i < n; i++) {
arr[index++] = pq.top();
pq.pop();
pq.push(arr[i]);
}
while (pq.empty() == false ) {
arr[index++] = pq.top();
pq.pop();
}
}
void printArray( int arr[], int size)
{
for ( int i = 0; i < size; i++)
cout << arr[i] << " " ;
cout << endl;
}
int main()
{
int k = 3;
int arr[] = { 2, 6, 3, 12, 56, 8 };
int n = sizeof (arr) / sizeof (arr[0]);
sortK(arr, n, k);
printArray(arr, n);
return 0;
}
|
Java
import java.util.Iterator;
import java.util.PriorityQueue;
class GFG {
private static void kSort( int [] arr, int n, int k)
{
if (arr == null || arr.length == 0 ) {
return ;
}
PriorityQueue<Integer> priorityQueue
= new PriorityQueue<>();
int minCount = Math.min(arr.length, k + 1 );
for ( int i = 0 ; i < minCount; i++) {
priorityQueue.add(arr[i]);
}
int index = 0 ;
for ( int i = k + 1 ; i < n; i++) {
arr[index++] = priorityQueue.peek();
priorityQueue.poll();
priorityQueue.add(arr[i]);
}
Iterator<Integer> itr = priorityQueue.iterator();
while (itr.hasNext()) {
arr[index++] = priorityQueue.peek();
priorityQueue.poll();
}
}
private static void printArray( int [] arr, int n)
{
for ( int i = 0 ; i < n; i++)
System.out.print(arr[i] + " " );
}
public static void main(String[] args)
{
int k = 3 ;
int arr[] = { 2 , 6 , 3 , 12 , 56 , 8 };
int n = arr.length;
kSort(arr, n, k);
printArray(arr, n);
}
}
|
Python3
from heapq import heappop, heappush, heapify
def print_array(arr: list ):
for elem in arr:
print (elem, end = ' ' )
def sort_k(arr: list , n: int , k: int ):
heap = arr[:k + 1 ]
heapify(heap)
target_index = 0
for rem_elmnts_index in range (k + 1 , n):
arr[target_index] = heappop(heap)
heappush(heap, arr[rem_elmnts_index])
target_index + = 1
while heap:
arr[target_index] = heappop(heap)
target_index + = 1
k = 3
arr = [ 2 , 6 , 3 , 12 , 56 , 8 ]
n = len (arr)
sort_k(arr, n, k)
print_array(arr)
|
C#
using System;
using System.Collections.Generic;
class GFG {
static void kSort( int [] arr, int n, int k)
{
List< int > priorityQueue = new List< int >();
for ( int i = 0; i < k + 1; i++) {
priorityQueue.Add(arr[i]);
}
priorityQueue.Sort();
int index = 0;
for ( int i = k + 1; i < n; i++) {
arr[index++] = priorityQueue[0];
priorityQueue.RemoveAt(0);
priorityQueue.Add(arr[i]);
priorityQueue.Sort();
}
int queue_size = priorityQueue.Count;
for ( int i = 0; i < queue_size; i++) {
arr[index++] = priorityQueue[0];
priorityQueue.RemoveAt(0);
}
}
static void printArray( int [] arr, int n)
{
for ( int i = 0; i < n; i++)
Console.Write(arr[i] + " " );
}
static void Main()
{
int k = 3;
int [] arr = { 2, 6, 3, 12, 56, 8 };
int n = arr.Length;
kSort(arr, n, k);
printArray(arr, n);
}
}
|
Javascript
<script>
function kSort(arr,n,k)
{
let priorityQueue=[];
for (let i = 0; i < k + 1; i++) {
priorityQueue.push(arr[i]);
}
priorityQueue.sort( function (a,b){ return a-b;});
let index = 0;
for (let i = k + 1; i < n; i++) {
arr[index++] = priorityQueue[0];
priorityQueue.shift();
priorityQueue.push(arr[i]);
priorityQueue.sort( function (a,b){ return a-b;});
}
while (priorityQueue.length != 0) {
arr[index++] = priorityQueue[0];
priorityQueue.shift();
}
}
function printArray(arr,n)
{
for (let i = 0; i < n; i++)
document.write(arr[i] + " " );
}
let k = 3;
let arr = [ 2, 6, 3, 12, 56, 8 ];
let n = arr.length;
kSort(arr, n, k);
printArray(arr, n);
</script>
|
Time Complexity: O(K) + O(m * log(k)) , where M = N – K
Auxiliary Space: O(K)
Note: We can also use a Balanced Binary Search Tree instead of a Heap to store k+1 elements. The insert and delete operations on Balanced BST also take O(log k) time. So Balanced BST-based method will also take O(n log k) time, but the Heap based method seems to be more efficient as the minimum element will always be at the root. Also, Heap doesn’t need extra space for left and right pointers.
Sort a nearly sorted (or K sorted) array using Quick-Sort:
To solve the problem follow the below idea:
The algorithm uses quick sort but changes the partition function in 2 ways.
- Selects the pivot element as the middle element instead of the first or last element.
- Scans the array from max(low, mid – k) to min(mid + k, high) instead of low to high.
The middle element is chosen as the pivot for diving the array into almost 2 halves for logarithmic time complexity
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
int sort(vector< int >& array, int l, int h, int k)
{
int mid
= l + (h - l) / 2;
int i = max(l, mid - k), j = i,
end = min(mid + k, h);
swap(array[mid],
array[end]);
while (j < end) {
if (array[j] < array[end]) {
swap(array[i++], array[j]);
}
j = j + 1;
}
swap(array[end], array[i]);
return i;
}
void ksorter(vector< int >& array, int l, int h, int k)
{
if (l < h) {
int q = sort(array, l, h, k);
ksorter(array, l, q - 1, k);
ksorter(array, q + 1, h, k);
}
}
int main()
{
vector< int > array(
{ 3, 3, 2, 1, 6, 4, 4, 5, 9, 7, 8, 11, 12 });
int k = 3;
cout << "Array before K sort\n" ;
for ( int & num : array)
cout << num << ' ' ;
cout << endl;
ksorter(array, 0, array.size() - 1, k);
cout << "Array after K sort\n" ;
for ( int & num : array)
cout << num << ' ' ;
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
public static int sort(ArrayList<Integer> arr, int l,
int h, int k)
{
int mid
= l
+ (h - l)
/ 2 ;
int i = Math.max(l, mid - k), j = i,
end = Math.min(mid + k,
h);
Collections.swap(
arr, end, mid);
while (j < end) {
if (arr.get(j) < arr.get(end)) {
Collections.swap(arr, j, i++);
}
j = j + 1 ;
}
Collections.swap(arr, end, i);
return i;
}
public static void ksorter(ArrayList<Integer> arr,
int l, int h, int k)
{
if (l < h) {
int q = sort(arr, l, h, k);
ksorter(arr, l, q - 1 , k);
ksorter(arr, q + 1 , h, k);
}
}
public static void main(String[] args)
{
ArrayList<Integer> arr = new ArrayList<>(List.of(
3 , 3 , 2 , 1 , 6 , 4 , 4 , 5 , 9 , 7 , 8 , 11 , 12 ));
int k = 3 ;
int N = arr.size();
System.out.println( "Array before K sort\n" );
System.out.println(arr);
System.out.println( "\n" );
ksorter(arr, 0 , N - 1 , k);
System.out.println( "Array after K sort\n" );
System.out.println(arr);
}
}
|
Python
def sort(array, l, h, k):
mid = l + (h - l) / / 2
i = max (l, mid - k)
j = i
end = min (mid + k, h)
array[mid], array[end] = array[end], array[mid]
while j < end:
if array[j] < array[end]:
array[i], array[j] = array[j], array[i]
i + = 1
j + = 1
array[end], array[i] = array[i], array[end]
return i
def ksorter(array, l, h, k):
if l < h:
q = sort(array, l, h, k)
ksorter(array, l, q - 1 , k)
ksorter(array, q + 1 , h, k)
array = [ 3 , 3 , 2 , 1 , 6 , 4 , 4 , 5 , 9 , 7 , 8 , 11 , 12 ]
k = 3
print ( "Array before K sort" )
print (array)
ksorter(array, 0 , len (array) - 1 , k)
print ( "Array after K sort" )
print (array)
|
C#
using System;
public class GFG {
public static void
swap( int [] array, int i,
int j)
{
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static int sort( int [] array, int l, int h, int k)
{
int mid
= l
+ (h - l)
/ 2;
int i = Math.Max(l, mid - k), j = i,
end = Math.Min(mid + k,
h);
swap(array, end,
mid);
while (j < end) {
if (array[j] < array[end]) {
swap(array, j, i++);
}
j = j + 1;
}
swap(array, end, i);
return i;
}
public static void ksorter( int [] array, int l, int h,
int k)
{
if (l < h) {
int q = sort(array, l, h, k);
ksorter(array, l, q - 1, k);
ksorter(array, q + 1, h, k);
}
}
public static void Main()
{
int [] array
= { 3, 3, 2, 1, 6, 4, 4, 5, 9, 7, 8, 11, 12 };
int k = 3;
int N = array.Length;
Console.WriteLine( "Array before K sort\n" );
for ( int i = 0; i < N; i++)
Console.Write(array[i] + " " );
Console.WriteLine( "\n" );
ksorter(array, 0, N - 1, k);
Console.WriteLine( "Array after K sort\n" );
for ( int i = 0; i < N; i++)
Console.Write(array[i] + " " );
Console.WriteLine( "\n" );
}
}
|
Javascript
function sort(array, l, h, k) {
let mid = Math.floor(l + (h - l) / 2);
let i = Math.max(l, mid - k);
let j = i;
let end = Math.min(mid + k, h);
[array[mid], array[end]] = [array[end], array[mid]];
while (j < end) {
if (array[j] < array[end]) {
[array[i++], array[j]] = [array[j], array[i]];
}
j = j + 1;
}
[array[end], array[i]] = [array[i], array[end]];
return i;
}
function ksorter(array, l, h, k) {
if (l < h) {
let q = sort(array, l, h, k);
ksorter(array, l, q - 1, k);
ksorter(array, q + 1, h, k);
}
}
let array = [3, 3, 2, 1, 6, 4, 4, 5, 9, 7, 8, 11, 12];
let k = 3;
console.log( "Array before K sort" );
console.log(array);
ksorter(array, 0, array.length - 1, k);
console.log( "Array after K sort" );
console.log(array);
|
Output
Array before K sort
3 3 2 1 6 4 4 5 9 7 8 11 12
Array after K sort
1 2 3 3 4 4 5 6 7 8 9 11 12
Time Complexity: O(N * Log N)
Auxiliary Space: O(Log N)
Please write comments if you find any of the above codes/algorithms incorrect, or find other ways to solve the same problem.
Please Login to comment...