I have this existing code that I need to add a swap and compare counter for. So far I believe I have the counts correctly however I cannot get the output to no display a loop of each swap.
public void mergeSort(int[] a, int howMany) {
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
mergeSort(left,howMany);
mergeSort(right, howMany);
// merge the sorted halves into a sorted whole
merge(a, left, right);
}
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static void merge(int[] result, int[] left,
int[] right) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
int compCount = 0;
int swapCount = 0;
for (int i = 0; i < result.length; i++) {
compCount++;
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
swapCount++;
} else {
result[i] = right[i2]; // take from right
i2++;
swapCount++;
}
}
//figure this loop issue out System.out.println("merge sort " + compCount + " " + swapCount);
}
Make a global variable or a field within the class which holds the merge and merge sort methods. This will allow the methods to increment to the variable. If you declare inside the method it will stay as a local variable and each recursive call will produce different local variables of the same name but belonging to the different recursive method calls. Therefore your code should look like:
public class ClassWithMergeMethodInside
{
int swapCount;
int compCount;
public void mergeSort(int[] a, int howMany) {
//Since merge sort begins here you may initiliaze the variables here
swapCount = 0;
compCount = 0;
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
mergeSort(left,howMany);
mergeSort(right, howMany);
// merge the sorted halves into a sorted whole
merge(a, left, right);
}
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static void merge(int[] result, int[] left,
int[] right) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
//Will not declare counter variables here
for (int i = 0; i < result.length; i++) {
compCount++;
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
swapCount++;
} else {
result[i] = right[i2]; // take from right
i2++;
swapCount++;
}
}
//figure this loop issue out System.out.println("merge sort " + compCount + " " + swapCount);
}
}
I think the most elegant solution is to simulate pass-by-reference by using an int wrapper class. Everything in Java is pass-by-value, but if you don't change the reference that an Object reference points to, you can simulate pass-by-reference for recursive calls.
Here is an example:
import java.util.Arrays;
public class TestMain
{
public static void main(String[] args)
{
int[] array = new int[]{6, 2, 1, 4, 5, 3};
IntWrapper countCompare = new IntWrapper();
IntWrapper countSwap = new IntWrapper();
MergeSort mSort = new MergeSort();
mSort.mergeSort(array, countCompare, countSwap);
System.out.println("Compares: " + countCompare.val);
System.out.println("Swaps: " + countSwap.val);
for (int i = 0; i < array.length; i++){
System.out.print(String.format("%-3d", array[i]));
}
}
}
public class IntWrapper{
int val = 0;
}
public class MergeSort
{
public void mergeSort(int[] a, IntWrapper compares, IntWrapper swaps) {
if (a.length >= 2) {
// split array into two halves
int[] left = Arrays.copyOfRange(a, 0, a.length/2);
int[] right = Arrays.copyOfRange(a, a.length/2, a.length);
// sort the two halves
mergeSort(left, compares, swaps);
mergeSort(right, compares, swaps);
// merge the sorted halves into a sorted whole
merge(a, left, right, compares, swaps);
}
}
// Merges the left/right elements into a sorted result.
// Precondition: left/right are sorted
public static void merge(int[] result, int[] left, int[] right, IntWrapper compares, IntWrapper swaps) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
//int compCount = 0;
//int swapCount = 0;
for (int i = 0; i < result.length; i++) {
//compCount++;
compares.val++;
if (i2 >= right.length ||
(i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1]; // take from left
i1++;
//swapCount++;
swaps.val++;
} else {
result[i] = right[i2]; // take from right
i2++;
//swapCount++;
swaps.val++;
}
}
//figure this loop issue out System.out.println("merge sort " + compCount + " " + swapCount);
}
}
Output:
Compares: 16
Swaps: 16
1 2 3 4 5 6
Related
I've tried to write a Mergesort Algorithm in Java:
static void merge(int[] sort, int l, int m, int r) {
int[] cache_array = new int[r - l + 1];
int l_cache = l;
int _mid = m + 1;
for (int i = 0; i < r - l + 1; i++) {
if (l > m) {
cache_array[i] = sort[_mid];
_mid++;
} else { if (_mid > r) {
cache_array[i] = sort[l];
l++;
} else { if (sort[l] >= sort[_mid]) {
cache_array[i] = sort[l];
l++;
} else { if (sort[_mid] > sort[l]) {
cache_array[i] = sort[_mid];
_mid++;
}}}}
}
for (int i = 0; i < cache_array.length; i++) {
sort[i + l_cache] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (l < r) {
int mid = (int)Math.floor((l + r - 1) / 2);
mergeSort(sort, l, mid);
mergeSort(sort, mid + 1, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length - 1);
for (int i : a) {
System.out.println(i);
}
}
But it just sorts a part of the Array and replaces the rest of it with zeros. I tried to change the cache_array to a LinkedList but nothing changed and after I tried debugging I couldn't find out anything, too.
I'd appreciate it if you'd help me and/or show me another Mergesort Algorithm that works for Java.
(I used this Algorithm because it worked for Python and so I wanted to use similar code in Java)
The bug in your code is difficult to spot:
the loop in your merge function iterates for i from 0 to r - l + 1 excluded, which would be correct if r and l remained constant during the loop, but you increment l each time you copy from the left part, reducing the number of iterations. As a consequence, the loop exits early, leaving the remaining elements in cache_array with their default value 0.
There are multiple sources of confusion in the code:
the convention to include r in the slice is confusing: it requires +1/-1 adjustments to compute the slice lengths and the middle index.
using Math.floor() is useless: integer arithmetic uses integer division in java.
incrementing the l and m arguments is confusing as these lose their meaning if the value is changed. Use other index variables to iterate through the arrays.
adding a { between the else and if keywords introduces unnecessary indentation levels.
the last condition is the opposite of the previous one: you should just omit it. Note that if the array elements were floating point values, both conditions could be false for NaN values and some elements of cache_array would be left untouched. This last condition would cause errors in this case.
Here is a modified version:
// merge adjacent slices of the `sort` array.
// left slice has elements from `l` included to `m` excluded
// right slice has elements from `m` included to `r` excluded
static void merge(int[] sort, int l, int m, int r) {
int len = r - l;
int[] cache_array = new int[len];
for (int i = 0, ll = l, mm = m; i < len; i++) {
if (ll >= m) {
cache_array[i] = sort[mm];
mm++;
} else
if (mm >= r) {
cache_array[i] = sort[ll];
ll++;
} else
if (sort[ll] >= sort[mm]) {
cache_array[i] = sort[ll];
ll++;
} else {
cache_array[i] = sort[mm];
mm++;
}
}
for (int i = 0; i < len; i++) {
sort[l + i] = cache_array[i];
}
}
static void mergeSort(int[] sort, int l, int r) {
if (r - l > 1) {
int mid = l + (r - l) / 2;
mergeSort(sort, l, mid);
mergeSort(sort, mid, r);
merge(sort, l, mid, r);
}
}
public static void main(String[] args) {
int[] a = { 2, 1, 4, 5, 73, 74, 7, 5, 64, 2 };
mergeSort(a, 0, a.length);
for (int i : a) {
System.out.println(i);
}
}
This is how I write the mergesort algorithm.
public static int[] mergeSort(int[] sort) {
if(sort.length > 1) {
int mid = sort.length / 2;
int[] left = Arrays.copyOf(sort, mid);
int[] right = Arrays.copyOfRange(sort, mid, sort.length);
// sort the left and right arrays
mergeSort(left);
mergeSort(right);
// Merge the arrays
merge(sort, left, right);
}
}
private static void merge(int[] sort, int[] leftArray, int[] rightArray) {
// These values are just to keep track of our position in each of the 3
// arrays
int l = 0; // left array
int r = 0; // right array
int o = 0; // the actual array being sorted
while(l < leftArray.length && r < rightArray.length) {
if(leftArray[l] < righArray[r]) {
sort[o++] = leftArray[l++];
}
else {
sort[o++] = leftArray[r++];
}
}
// Now that we are out of the while loop we know that either the
// left or right array has all of its values in sort, so we just
// need to put the rest of the values in the array that doesn't have
// all of its elements in sort with the following code.
while(l < leftArray.length) {
sort[o++] = leftArray[l++];
}
while(r < rightArray.length) {
sort[o++] = rightArray[r++];
}
}
I usually implement it like this:
/// <summary>
/// Mergesort
/// best-case: O(n* log(n))
/// average-case: O(n* log(n))
/// worst-case: O(n* log(n))
/// </summary>
/// <returns>The sorted array.</returns>
/// <param name="array">array.</param>
public static int[] MergeSort(int[] array) {
// Exit condition for recursion
if (array.length <= 1) return array;
// Middle index of list to sort
int m = array.length / 2;
// Define left and right sub-listså
int[] left_array = new int[m];
int[] right_array = new int[array.length - m];
// Initialize left list
for (int i = 0; i < m; i++) left_array[i] = array[i];
// Initialize right list
for (int i = m, x = 0; i < array.length; i++, x++) right_array[x] = array[i];
// Recursively sort left half of the list
left_array = MergeSort(left_array);
// Recursively sort right half of the list
right_array = MergeSort(right_array);
// Merge sorted sub-lists
return Merge(left_array, right_array);
}
/// <summary>
/// Merge the specified left_array and right_array.
/// </summary>
/// <returns>The merge.</returns>
/// <param name="left_array">Left array.</param>
/// <param name="right_array">Right array.</param>
public static int[] Merge(int[] left_array, int[] right_array) {
int[] m = new int[left_array.length + right_array.length];
int index_l = 0;
int nl, nr;
nl = left_array.length - 1;
nr = right_array.length - 1;
for (int i = 0; i <= nl + nr + 1; i++) {
if (index_l > nl) {
m[i] = (right_array[i - index_l]);
continue;
}
if (index_l < i - nr) {
m[i] = (left_array[index_l]);
index_l++;
continue;
}
if (left_array[index_l] <= (right_array[i - index_l])) {
m[i] = (left_array[index_l]);
index_l++;
} else {
m[i] = (right_array[i - index_l]);
}
}
return m;
}
A few months ago I wrote all of the common sorting algorithms and this is what I got. A bit inaccurate but just to See how this implementation performs.
The other algorithms are here.
To achieve a descending order I think you just have to swap the comparison operators.
I was trying to sort two arrays with non sequential numbers into one array after I did with sequential numbers. Do I need to order the arrays separately or is there a more effective way?
If I run the code below my output will be 4,16,2,11,19.. and it should be 0,1,2,3,4..
int myFirstArray [] = { 16, 2, 11, 34, 77, 1, 0, 10, 3 };
int mySecondArray [] = { 4, 19, 6, 32, 8, 10, 66 };
int firstPos = 0, secondPos = 0;
int myThirdArray [] = new int[myFirstArray.length + mySecondArray.length];
for (int i = 0; i < myThirdArray.length; i++) {
if (firstPos < myFirstArray.length && secondPos < mySecondArray.length) {
if (mySecondArray[secondPos] < myFirstArray[firstPos]) {
myThirdArray[i] = mySecondArray[secondPos];
secondPos++;
}
else {
myThirdArray[i] = myFirstArray[firstPos];
firstPos++;
}
}
else if (secondPos < mySecondArray.length) {
myThirdArray[i] = mySecondArray[secondPos];
secondPos++;
}
else {
myThirdArray[i] = myFirstArray[firstPos];
firstPos++;
}
}
for(int i = 0; i < myThirdArray.length; i++) {
System.out.println(myThirdArray[i]);
}
If you had 2 sorted arrays and want to combine them into one sorted array then your code would be correct. But you are comparing the first 2 elements of your unsorted arrays and create a topically sorted array, meaning some elements of the array are sorted compared to others ie 4 < 16, 2 < 11 < 19.
Your logic is not far away from Mergesort. You split your array into halves and split them again and merges the 2 halves. You end up merging arrays of size 1, then merging arrays of size 2 and so on and so on. Your merging code is correct. You can see more details here.
// Merges two subarrays of arr[].
// First subarray is arr[l..m]
// Second subarray is arr[m+1..r]
void merge(int arr[], int l, int m, int r)
{
// Find sizes of two subarrays to be merged
int n1 = m - l + 1;
int n2 = r - m;
/* Create temp arrays */
int L[] = new int [n1];
int R[] = new int [n2];
/*Copy data to temp arrays*/
for (int i=0; i<n1; ++i)
L[i] = arr[l + i];
for (int j=0; j<n2; ++j)
R[j] = arr[m + 1+ j];
/* Merge the temp arrays */
// Initial indexes of first and second subarrays
int i = 0, j = 0;
// Initial index of merged subarry array
int k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
arr[k] = L[i];
i++;
}
else
{
arr[k] = R[j];
j++;
}
k++;
}
/* Copy remaining elements of L[] if any */
while (i < n1)
{
arr[k] = L[i];
i++;
k++;
}
/* Copy remaining elements of R[] if any */
while (j < n2)
{
arr[k] = R[j];
j++;
k++;
}
}
// Main function that sorts arr[l..r] using
// merge()
void sort(int arr[], int l, int r)
{
if (l < r)
{
// Find the middle point
int m = (l+r)/2;
// Sort first and second halves
sort(arr, l, m);
sort(arr , m+1, r);
// Merge the sorted halves
merge(arr, l, m, r);
}
}
It is always better to sort your both arrays first and then merge both the array in single array.
// Function to merge array in sorted order
// a[] will be the first unsorted array.
// b[] will be the second unsorted array.
public static int[] sortedMerge(int a[], int b[]){
int n = a.length;
int m = b.length;
int totalSize=n+m;
//result array
int[] res =new int[totalSize];
// Sorting a[] and b[]
Arrays.sort(a);
Arrays.sort(b);
// Merge two sorted arrays into res[]
int i = 0, j = 0, k = 0;
while (i < n && j < m) {
if (a[i] <= b[j]) {
res[k] = a[i];
i += 1;
k += 1;
} else {
res[k] = b[j];
j += 1;
k += 1;
}
}
while (i < n) { // Merging remaining
// elements of a[] (if any)
res[k] = a[i];
i += 1;
k += 1;
}
while (j < m) { // Merging remaining
// elements of b[] (if any)
res[k] = b[j];
j += 1;
k += 1;
}
return res;
}
This way the Time Complexity will be O(nlogn + mlogm + (n + m)) and
Space Complexity will be O ( (n + m) ). If you think to merge the array first and then sort the merged array then the space complexity will be the same but time complexity will change to O((n + m)(log(n + m))), which will be definitely higher than first one .
create a new array3 with size sum of array1.length and array2.length
use System.arrayCopy() to copy array1 to array3 starting at index 0
use System.arrayCopy() to copy array2 to array3 starting at index array1.length
sort array3 in the way you prefer e.g. Arrays.sort() or any other algorithm
Can anyone say what is the problem in the merging logic? If element of right array is less than element in left array then it works. Other wise gives wrong answer. I have divided the array properly. I am giving my merging logic here.
public static void main(String[] args) {
int[] list = { 32,14, 67, 76, 23, 41, 58, 85};
System.out.println("before: " + Arrays.toString(list));
mergeSort(list);
System.out.println("after: " + Arrays.toString(list));
}
public static void mergeSort(int[] array) {
if (array.length > 1) {
// split array into two halves
int[] left = leftHalf(array);
int[] right = rightHalf(array);
mergeSort(left);
mergeSort(right);
merge(array, left, right);
}
}
public static void merge(int[] result,
int[] left, int[] right) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
int j = 0;
int k = 0;
for (int i=0; i1 < left.length && i2 < right.length;i++) {
if (left[i1] < right[i2]) {
result[i] = left[i1];
// take from left
i1++;
} else {
result[i] = right[i2];
// take from right
i2++;
}
}
}
You've got two unused variables j and k in your code. Your logic is flawed because you copy into the array until one half is empty, so you never actually empty both halves.
public static void merge(int[] result, int[] left, int[] right) {
int i1 = 0; // index into left array
int i2 = 0; // index into right array
int i;
for (i = 0; i1 < left.length && i2 < right.length;i++) {
if (left[i1] < right[i2]) {
result[i] = left[i1++];
// take from left
} else {
result[i] = right[i2++];
// take from right
}
}
for (; i1 < left.length; i++) result[i] = left[i1++];
for (; i2 < right.length; i++) result[i] = right[i2++];
}
Only one of the two for loops will run at the end, and will process what's left of the other half.
I want to modify the 2 threaded merge sort to 4 threaded merge sort. First I want to divide the array into 4 equal subarrays(the last subarray might be larger) and assign them into separate threads to sort. Finally, merge 1 and 2 subarrays and 3 and 4 subarrays, then merge already sorted-merged 1 and 2 subarrays with sorted-merged 3 and 4 subarrays.
here is what i have as now:
How can I implement that? Thanks ver much!!!
package four_threaded;
import java.util.Random;
public class four_threaded_merge_sort {
public static void finalMerge(int[] a, int[] b) {
int[] result = new int[a.length + b.length];
int i=0;
int j=0;
int r=0;
while (i < a.length && j < b.length) {
if (a[i] <= b[j]) {
result[r]=a[i];
i++;
r++;
}
else {
result[r]=b[j];
j++;
r++;
}
if (i==a.length) {
while (j<b.length) {
result[r]=b[j];
r++;
j++;
}
}
if (j==b.length) {
while (i<a.length) {
result[r]=a[i];
r++;
i++;
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Random rand = new Random();
int[] original = new int[10];
for (int i=0; i<original.length; i++) {
original[i] = rand.nextInt(100);
}
long startTime = System.currentTimeMillis();
int s = original.length / 4 ;
int r = original.length % 4;
//first subarray
int[] subArr1 = new int[s];
System.arraycopy(original, 0, subArr1, 0, s);
//second subarray
int[] subArr2 = new int[s];
System.arraycopy(original, s, subArr2, 0, s);
//third subarray
int[] subArr3 = new int[s];
System.arraycopy(original, 2*s, subArr3, 0, s);
//fourth subarray
int[] subArr4 = new int[s+r];
System.arraycopy(original, 3*s, subArr4, 0, s+r);
Worker runner1 = new Worker(subArr1);
Worker runner2 = new Worker(subArr2);
Worker runner3 = new Worker(subArr3);
Worker runner4 = new Worker(subArr4);
runner1.start();
runner2.start();
runner3.start();
runner4.start();
runner1.join();
runner2.join();
runner3.join();
runner4.join();
finalMerge(runner1.getInternal(), runner2.getInternal());
long stopTime = System.currentTimeMillis();
long elapsedTime = stopTime - startTime;
System.out.println("4-thread MergeSort takes: " + (float)elapsedTime/1000 + " seconds");
}
}
class Worker extends Thread {
private int[] internal;
public int[] getInternal() {
return internal;
}
public void mergeSort(int[] array) {
if (array.length > 1) {
int[] left = leftHalf(array);
int[] right = rightHalf(array);
mergeSort(left);
mergeSort(right);
merge(array, left, right);
}
}
public int[] leftHalf(int[] array) {
int size1 = array.length / 2;
int[] left = new int[size1];
for (int i = 0; i < size1; i++) {
left[i] = array[i];
}
return left;
}
public int[] rightHalf(int[] array) {
int size1 = array.length / 2;
int size2 = array.length - size1;
int[] right = new int[size2];
for (int i = 0; i < size2; i++) {
right[i] = array[i + size1];
}
return right;
}
public void merge(int[] result, int[] left, int[] right) {
int i1 = 0;
int i2 = 0;
for (int i = 0; i < result.length; i++) {
if (i2 >= right.length || (i1 < left.length && left[i1] <= right[i2])) {
result[i] = left[i1];
i1++;
} else {
result[i] = right[i2];
i2++;
}
}
}
Worker(int[] arr) {
internal = arr;
}
public void run() {
mergeSort(internal);
}
}
After the 4 threads complete, you could use 2 threads to merge the 4 sub-arrays into 2 sub-arrays, although that probably won't help much since the merging of large arrays will be memory bandwidth limited. You could also use the main thread to do a 4 way merge. On processor with 16 registers, like a PC in 64 bit mode, there are enough registers to deal with 4 sub-arrays via pointers or indices.
If speed is the goal here, allocating a working array one time and using a bottom up merge sort would be faster than top down. To avoid copying, each merge sort alternates merging data between the original and the working array. Each merge sort can determine the number of passes needed, and if it's an odd number, then swap in place for the first pass instead of merging to the other buffer.
If the final pass will be a 4 way merge, then each merge sort thread should end up with the sorted data in the working array. In this case, if it's an even number of passes, then swap in place for the first pass. You may want to do an in place swap for more than 2 elements at a time. Using something like a sorting network, 4 elements can be swapped with 6 if / swap statements. I'm not sure about using other in place sort methods for small sets of elements helps.
So the goal is to rotate the elements in an array right a times.
As an example; if a==2, then array = {0,1,2,3,4} would become array = {3,4,0,1,2}
Here's what I have:
for (int x = 0; x <= array.length-1; x++){
array[x+a] = array[x];
}
However, this fails to account for when [x+a] is greater than the length of the array. I read that I should store the ones that are greater in a different Array but seeing as a is variable I'm not sure that's the best solution.
Thanks in advance.
Add a modulo array length to your code:
// create a newArray before of the same size as array
// copy
for(int x = 0; x <= array.length-1; x++){
newArray[(x+a) % array.length ] = array[x];
}
You should also create a new Array to copy to, so you do not overwrite values, that you'll need later on.
In case you don't want to reinvent the wheel (maybe it's an exercise but it can be good to know), you can use Collections.rotate.
Be aware that it requires an array of objects, not primitive data type (otherwise you'll swap arrays themselves in the list).
Integer[] arr = {0,1,2,3,4};
Collections.rotate(Arrays.asList(arr), 2);
System.out.println(Arrays.toString(arr)); //[3, 4, 0, 1, 2]
Arraycopy is an expensive operation, both time and memory wise.
Following would be an efficient way to rotate array without using extra space (unlike the accepted answer where a new array is created of the same size).
public void rotate(int[] nums, int k) { // k = 2
k %= nums.length;
// {0,1,2,3,4}
reverse(nums, 0, nums.length - 1); // Reverse the whole Array
// {4,3,2,1,0}
reverse(nums, 0, k - 1); // Reverse first part (4,3 -> 3,4)
// {3,4,2,1,0}
reverse(nums, k, nums.length - 1); //Reverse second part (2,1,0 -> 0,1,2)
// {3,4,0,1,2}
}
public void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
Another way is copying with System.arraycopy.
int[] temp = new int[array.length];
System.arraycopy(array, 0, temp, a, array.length - a);
System.arraycopy(array, array.length-a, temp, 0, a);
I think the fastest way would be using System.arrayCopy() which is native method:
int[] tmp = new int[a];
System.arraycopy(array, array.length - a, tmp, 0, a);
System.arraycopy(array, 0, array, a, array.length - a);
System.arraycopy(tmp, 0, array, 0, a);
It also reuses existing array. It may be beneficial in some cases.
And the last benefit is the temporary array size is less than original array. So you can reduce memory usage when a is small.
Time Complexity = O(n)
Space Complexity = O(1)
The algorithm starts with the first element of the array (newValue) and places it at its position after the rotation (newIndex). The element that was at the newIndex becomes oldValue. After that, oldValue and newValue are swapped.
This procedure repeats length times.
The algorithm basically bounces around the array placing each element at its new position.
unsigned int computeIndex(unsigned int len, unsigned int oldIndex, unsigned int times) {
unsigned int rot = times % len;
unsigned int forward = len - rot;
// return (oldIndex + rot) % len; // rotating to the right
return (oldIndex + forward) % len; // rotating to the left
}
void fastArrayRotation(unsigned short *arr, unsigned int len, unsigned int rotation) {
unsigned int times = rotation % len, oldIndex, newIndex, length = len;
unsigned int setIndex = 0;
unsigned short newValue, oldValue, tmp;
if (times == 0) {
return;
}
while (length > 0) {
oldIndex = setIndex;
newValue = arr[oldIndex];
while (1) {
newIndex = computeIndex(len, oldIndex, times);
oldValue = arr[newIndex];
arr[newIndex] = newValue;
length--;
if (newIndex == setIndex) { // if the set has ended (loop detected)
break;
}
tmp = newValue;
newValue = oldValue;
oldValue = tmp;
oldIndex = newIndex;
}
setIndex++;
}
}
int[] rotate(int[] array, int r) {
final int[] out = new int[array.length];
for (int i = 0; i < array.length; i++) {
out[i] = (i < r - 1) ? array[(i + r) % array.length] : array[(i + r) % array.length];
}
return out;
}
The following rotate method will behave exactly the same as the rotate method from the Collections class used in combination with the subList method from the List interface, i.e. rotate (n, fromIndex, toIndex, dist) where n is an array of ints will give the same result as Collections.rotate (Arrays.asList (n).subList (fromIndex, toIndex), dist) where n is an array of Integers.
First create a swap method:
public static void swap (int[] n, int i, int j){
int tmp = n[i];
n[i] = n[j];
n[j] = tmp;
}
Then create the rotate method:
public static void rotate (int[] n, int fromIndex, int toIndex,
int dist){
if(fromIndex > toIndex)
throw new IllegalArgumentException ("fromIndex (" +
fromIndex + ") > toIndex (" + toIndex + ")");
if (fromIndex < toIndex){
int region = toIndex - fromIndex;
int index;
for (int i = 0; i < dist % region + ((dist < 0) ? region : 0);
i++){
index = toIndex - 1;
while (index > fromIndex)
swap (n, index, --index);
}
}
}
Java solution wrapped in a method:
public static int[] rotate(final int[] array, final int rIndex) {
if (array == null || array.length <= 1) {
return new int[0];
}
final int[] result = new int[array.length];
final int arrayLength = array.length;
for (int i = 0; i < arrayLength; i++) {
int nIndex = (i + rIndex) % arrayLength;
result[nIndex] = array[i];
}
return result;
}
For Left Rotate its very simple
Take the difference between length of the array and number of position to shift.
For Example
int k = 2;
int n = 5;
int diff = n - k;
int[] array = {1, 2, 3, 4, 5};
int[] result = new int[array.length];
System.arraycopy(array, 0, result, diff, k);
System.arraycopy(array, k, result, 0, diff);
// print the output
Question : https://www.hackerrank.com/challenges/ctci-array-left-rotation
Solution :
This is how I tried arrayLeftRotation method with complexity o(n)
looping once from k index to (length-1 )
2nd time for 0 to kth index
public static int[] arrayLeftRotation(int[] a, int n, int k) {
int[] resultArray = new int[n];
int arrayIndex = 0;
//first n-k indexes will be populated in this loop
for(int i = k ; i
resultArray[arrayIndex] = a[i];
arrayIndex++;
}
// 2nd k indexes will be populated in this loop
for(int j=arrayIndex ; j<(arrayIndex+k); j++){
resultArray[j]=a[j-(n-k)];
}
return resultArray;
}
package com.array.orderstatistics;
import java.util.Scanner;
public class ArrayRotation {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int r = scan.nextInt();
int[] a = new int[n];
int[] b = new int[n];
for (int i = 0; i < n; i++) {
a[i] = scan.nextInt();
}
scan.close();
if (r % n == 0) {
printOriginalArray(a);
} else {
r = r % n;
for (int i = 0; i < n; i++) {
b[i] = a[(i + r) < n ? (i + r) : ((i + r) - n)];
System.out.print(b[i] + " ");
}
}
}
private static void printOriginalArray(int[] a) {
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
}
}
Following routine rotates an array in java:
public static int[] rotateArray(int[] array, int k){
int to_move = k % array.length;
if(to_move == 0)
return array;
for(int i=0; i< to_move; i++){
int temp = array[array.length-1];
int j=array.length-1;
while(j > 0){
array[j] = array[--j];
}
array[0] = temp;
}
return array;
}
You can do something like below
class Solution {
public void rotate(int[] nums, int k) {
if (k==0) return;
if (nums == null || nums.length == 0) return;
for(int i=0;i<k;i++){
int j=nums.length-1;
int temp = nums[j];
for(;j>0;j--){
nums[j] = nums[j-1];
}
nums[0] = temp;
}
}
}
In the above solution, k is the number of times you want your array to rotate from left to right.
Question : Rotate array given a specific distance .
Method 1 :
Turn the int array to ArrayList. Then use Collections.rotate(list,distance).
class test1 {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6 };
List<Integer> list = Arrays.stream(a).boxed().collect(Collectors.toList());
Collections.rotate(list, 3);
System.out.println(list);//[4, 5, 6, 1, 2, 3]
}// main
}
I use this, just loop it a times
public void rotate(int[] arr) {
int temp = arr[arr.length - 1];
for(int i = arr.length - 1; i > 0; i--) {
arr[i] = arr[i - 1];
}
arr[0] = temp;
}