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. For example, let us consider k is 2, an element at index 7 in the sorted array, can be at indexes 5, 6, 7, 8, 9 in the given array.
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}
We can use Insertion Sort to sort the elements efficiently. Following is the C code for standard Insertion Sort.
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;
}
}
|
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. So overall complexity will be O(nk)
We can sort such arrays more efficiently with the help of Heap data structure. Following is the detailed process that uses Heap.
1) Create a Min Heap of size k+1 with first k+1 elements. This will take O(k) time (See this GFact)
2) One by one remove min element from heap, put it in result array, and add a new element to heap from remaining elements.
Removing an element and adding a new element to min heap will take log k time. So overall complexity will be O(k) + O((n-k) * log(k)).
C++
#include <bits/stdc++.h>
using namespace std;
int sortK( int arr[], int n, int k)
{
priority_queue< int , vector< int >, greater< int > > pq(arr, arr + k + 1);
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);
cout << "Following is sorted array" << endl;
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)
{
PriorityQueue<Integer> priorityQueue
= new PriorityQueue<>();
for ( int i = 0 ; i < k + 1 ; 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);
System.out.println( "Following is sorted array" );
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 ( 'Following is sorted array' )
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);
Console.WriteLine( "Following is sorted array" );
printArray(arr, n);
}
}
|
Output:
Following is sorted array
2 3 6 8 12 56
The Min Heap based method takes O(n log k) time and uses O(k) auxiliary space.
We can also use a Balanced Binary Search Tree instead of 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 root. Also, Heap doesn’t need extra space for left and right pointers.
Please write comments if you find any of the above codes/algorithms incorrect, or find other ways to solve the same problem.
Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.