patternjavaMinor
Produce a nearly sorted (or K sorted) array
Viewed 0 times
sortednearlyproducearray
Problem
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. I'm looking for code review, best practices, optimizations etc. Also for some reason I could not get assertarrayequals hooked up so tested arrays unconventionally. Please ignore that as part of feedback
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. I'm looking for code review, best practices, optimizations etc. Also for some reason I could not get assertarrayequals hooked up so tested arrays unconventionally. Please ignore that as part of feedback
public final class KSortedArray {
private KSortedArray() { }
/**
* Returns the sorted array provided the input array is k-sorted.
* If input array is not k-sorted, then results are unpredictable.
*
* @param arr The k-sorted array
* @param k the value of k, the deviation of placement.
* @return the sorted array
*/
public static int[] kSortDontModifyInput(int[] arr, int k) {
int[] n = new int[arr.length];
final Queue queue = new PriorityQueue(k + 1);
for (int i = 0; i queue = new PriorityQueue(k + 1);
for (int i = 0; i <= k; i++) {
queue.add(arr[i]);
}
int ctr = 0;
for (int i = k + 1; i < arr.length; i++) {
arr[ctr++] = queue.poll();
queue.add(arr[i]);
}
while (!queue.isEmpty()) {
arr[ctr++] = queue.poll();
}
}
public static void main(String[] args) {
int arr[] = {2, 6, 3, 12, 56, 8};
int[] expected = {2, 3, 6, 8, 12, 56};
int[] actual = kSortDontModifyInput(arr, 3);
kSortMoidifyInput(arr, 3);
for (int i = 0; i < expected.length; i++) {
Assert.assertEquals(expected[i], actual[i]);
Assert.assertEquals(expected[i], arr[i]);
}
}
}Solution
When you use a class in a 'hacky' way, like you do by using a PriorityQueue as a TreeSet, you should make sure that you document why the class is used, and what properties of the class are being leveraged.
Your code does not work in O(n log(k) ) time because it uses a PriorityQueue, which has O( log(n) ) time-complexity for add():
Implementation note: this implementation provides O(log(n)) time for the enqueing and dequeing methods (offer, poll, remove() and add); linear time for the remove(Object) and contains(Object) methods; and constant time for the retrieval methods (peek, element, and size)
Your algorithm is not correct for the requirements given:
-
For a start, it will fail for input where the input array is smaller than
-
Secondly, you are working in
Further, because you auto-box all your values to Integer, from int, you have a significant performance penalty. If you keep your data as primitives (and use an array of primitives rather than a PriorityQueue), you will have better results.
The algorithm you need you use is strongly hinted at by the complexity requirement...
O( n log(k) ) strongly implies that you need to iterate over each value once, and, with that element, there is an O(log(k)) way to sort it.
For the loop, think a for-loop. For the log(k), think a binary search....
Your code does not work in O(n log(k) ) time because it uses a PriorityQueue, which has O( log(n) ) time-complexity for add():
Implementation note: this implementation provides O(log(n)) time for the enqueing and dequeing methods (offer, poll, remove() and add); linear time for the remove(Object) and contains(Object) methods; and constant time for the retrieval methods (peek, element, and size)
Your algorithm is not correct for the requirements given:
-
For a start, it will fail for input where the input array is smaller than
k. It will throw an ArrayIndexOutOfBoundsException.-
Secondly, you are working in
k+1 space instead of k. Why? Where is the comment?Further, because you auto-box all your values to Integer, from int, you have a significant performance penalty. If you keep your data as primitives (and use an array of primitives rather than a PriorityQueue), you will have better results.
The algorithm you need you use is strongly hinted at by the complexity requirement...
O( n log(k) ) strongly implies that you need to iterate over each value once, and, with that element, there is an O(log(k)) way to sort it.
For the loop, think a for-loop. For the log(k), think a binary search....
for (int i = 0; i k ? i - k : 0;
int val = data[i];
int pos = Arrays.binarySearch(data, from, i, val);
if (pos < 0) {
pos = -pos - 1;
}
System.arraycopy(data, pos, data, pos+1, i - pos - 1);
data[pos] = val;
}Code Snippets
for (int i = 0; i < data.length; i++) {
int from = i > k ? i - k : 0;
int val = data[i];
int pos = Arrays.binarySearch(data, from, i, val);
if (pos < 0) {
pos = -pos - 1;
}
System.arraycopy(data, pos, data, pos+1, i - pos - 1);
data[pos] = val;
}Context
StackExchange Code Review Q#42328, answer score: 4
Revisions (0)
No revisions yet.