Algorithms - Circular Array Rotation - c++

Is this linear complexity implementation of circular array rotation correct?
n = number of elements
k = number of rotations
int write_to = 0;
int copy_current = 0;
int copy_final = a[0];
int rotation = k;
int position = 0;
for (int i = 0; i < n; i++) {
write_to = (position + rotation) % n;
copy_current = a[write_to];
a[write_to] = copy_final;
position = write_to;
copy_final = copy_current;
}

No.
Consider this example.
#include <iostream>
int main(void) {
int n = 6;
int k = 2;
int a[] = {1, 2, 3, 4, 5, 6};
int write_to = 0;
int copy_current = 0;
int copy_final = a[0];
int rotation = k;
int position = 0;
for (int i = 0; i < n; i++) {
write_to = (position + rotation) % n;
copy_current = a[write_to];
a[write_to] = copy_final;
position = write_to;
copy_final = copy_current;
}
for (int i = 0; i < n; i++) {
std::cout << a[i] << (i + 1 < n ? ' ' : '\n');
}
return 0;
}
Expected result:
5 6 1 2 3 4
Actual result:
3 2 1 4 1 6

Using stl::rotate on std::array, you can left rotate by, say 2, as:
std::array<int, 6> a{1, 2, 3, 4, 5, 6};
std::rotate(begin(a), begin(a) + 2, end(a)); // left rotate by 2
to yield: 3 4 5 6 1 2, or right-rotate by, say 2, as:
std::rotate(begin(a), end(a) - 2, end(a)); // right rotate by 2
to yield: 5 6 1 2 3 4, with linear complexity.

Rotate an Array of length n for k times in left or right directions.
The code is in Java
I define a Direction Enum:
public enum Direction {
L, R
};
Rotation with times and direction:
public static final void rotate(int[] arr, int times, Direction direction) {
if (arr == null || times < 0) {
throw new IllegalArgumentException("The array must be non-null and the order must be non-negative");
}
int offset = arr.length - times % arr.length;
if (offset > 0) {
int[] copy = arr.clone();
for (int i = 0; i < arr.length; ++i) {
int j = (i + offset) % arr.length;
if (Direction.R.equals(direction)) {
arr[i] = copy[j];
} else {
arr[j] = copy[i];
}
}
}
}
Complexity: O(n).
Example:
Input: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Rotate 3 times left
Output: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
Input: [4, 5, 6, 7, 8, 9, 10, 1, 2, 3]
Rotate 3 times right
Output: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Related

Is there a way to sort a vector in segments?

If I have a vector with an odd number of elements and want to sort the vector in segments, how could I construct a loop that does this but doesn't access anything out of bounds?
Like an array like this:
[4, 5, 6, 3, 10, 2, 0] (size: 7)
And I want to sort in segments of 2, so it becomes like this:
[4, 5, 3, 6, 2, 10, 0]
I was thinking something like this, but then the vector would access arr[8] which is out of bounds.
for(int i = 0; i < arr.size(); i = i + 2) {
sort(arr.begin() + i, arr.begin() + i - 1);
}
Two options spring to mind:
First, you can constrain your loop:
const int SegmentLen = 2;
for (int i=0; i+SegmentLen-1 < arr.size(); i += SegmentLen)
std::sort(arr.begin()+i, arr.begin()+i+SegmentLen);
Second, you can loop a fixed number of times:
auto segments = arr.size() / SegmentLen;
for (int i=0; i < segments; ++i)
std::sort(arr.begin() + (i*SegmentLen), arr.begin() + (i*SegmentLen) + SegmentLen);
//Handle any leftovers
Just get the first even number less than or equal to the size of the array and then use that as the stop condition for the loop.
int main(){
std::array<int, 7> arr = {4, 5, 6, 3, 10, 2, 0};
auto size = arr.size() % 2 ? arr.size() - 1 : arr.size(); // if odd subtract one else use size
for (size_t i = 0; i < size - 2; i += 2)
std::sort(arr.begin() + i, arr.begin() + i + 2);
for (auto e : arr)
std::cout << e << " ";
}
Outputs:
4 5 3 6 10 2 0

Dividing a data set almost equally among worker threads

I have n number of elements and p number of threads. I am trying to divide the elements as equally as possible among the threads.
For example:
If n = 8 and p = 1, then [8]
If n = 8 and p = 2, then [4, 4]
If n = 8 and p = 3, then [2, 3, 3]
If n = 8 and p = 4, then [2, 2, 2, 2]
If n = 8 and p = 5, then [1, 1, 2, 2, 2]
If n = 8 and p = 6, then [1, 1, 1, 1, 2, 2]
If n = 8 and p = 7, then [1, 1, 1, 1, 1, 1, 2]
If n = 8 and p = 8, then [1, 1, 1, 1, 1, 1, 1, 1]
I cooked up a solution that almost works but not quite.
#include <vector>
#include <stdio.h>
#include <cmath>
int main(int argc, char **argv)
{
int p = 5;
const int SIZE = 8;
int i = 0;
int num = 0;
std::vector<int> iter;
if (p == 1)
iter.push_back(SIZE);
else
{
if (SIZE % p == 0)
{
num = SIZE / p;
for (i = 0; i < p; ++i)
iter.push_back(num);
}
else
{
num = (int)floor((float)SIZE / (float)p);
for (i = 0; i < p - 1; ++i)
iter.push_back(num);
iter.push_back((SIZE - (num * (p - 1))));
}
}
for (unsigned int j = 0; j < iter.size(); ++j)
printf("[%d] = %d\n", j, (int)iter[j]);
return 0;
}
Results produced with my solution:
If n = 8 and p = 1, then [8]
If n = 8 and p = 2, then [4, 4]
If n = 8 and p = 3, then [2, 2, 4]
If n = 8 and p = 4, then [2, 2, 2, 2]
If n = 8 and p = 5, then [1, 1, 1, 1, 4]
If n = 8 and p = 6, then [1, 1, 1, 1, 1, 3]
If n = 8 and p = 7, then [1, 1, 1, 1, 1, 1, 2]
If n = 8 and p = 8, then [1, 1, 1, 1, 1, 1, 1, 1]
try to think about this. if you have less objects then threads then each thread will get one object. if you have more objects then threads (buckets) then think about how would you divide 100 tennis balls to 8 buckets.
you could take 1 ball at a time and put that in the next bucket, once you passed all buckets you start from first bucket, this will make sure that at most the difference between each bucket size will be 1.
#include <vector>
#include <stdio.h>
int main(int argc, char **argv)
{
int p = 5;
const int SIZE = 8;
int p_size = SIZE > p ? p : SIZE;
std::vector<int> iter(p_size);
for (int i = 0; i < SIZE; i++)
{
iter[i%p_size] += 1;
}
for (unsigned int j = 0; j < iter.size(); ++j)
printf("[%d] = %d\n", j, (int)iter[j]);
return 0;
}
You can try this:
std::vector<int> iter(p);
std::generate(iter.begin(), iter.end(), [&]()
{
num += 1;
return SIZE / p + (num <= SIZE % p ? 1 : 0);
});
The first line creates the required number of elements, and the second operator fills this vector with actual data. It is written without explicit loops to make code more expressive.
This is less an answer to your specific question/problem, but more an alternative approach to your intended problem.
your solution is way to complicate... this code does the same, except the additional tasks are put into the front...
#include <iostream>
#include <vector>
int main(int argc, char **argv)
{
int p = 5;
const int n = 8;
// calculate number of tasks every thread have to do...
int every = n / p;
// calculate rest
int rest = n % p;
// initialize the vector with the number of tasks every thread have to do
std::vector<int> lst(p, every);
// split rest on the threads
for(int i=0; i<rest; ++i)
lst[i]++;
// print out
for(auto it : lst)
std::cout << it << ",";
return 0;
}
The trick is integer truncation, there is no need for floating point arithmetics, as you probably see, the other answers also do...

Ribbon shape using for loop in C++

I've been trying all day creating different for loop combinations in c++ and I can't seem to get the right one.
I want my output to look like this:
Ribbon
How can you display this without using arrays?
EDIT: I tried like this but I can't replicate it on the opposite end. This has been so far the closest output I've got.
for(int i = 0; i < 6; i++)
{
cout<<"*";
for(int j = 5; j > i; j--)
{
cout<<" ";
}
for(int k = 0; k <= i; k++)
{
cout<<"*";
}
cout<<endl;
}
OUTPUT:
Fail ribbon
You have nine lines; let's number them 0 to 8. Line number n contains:
1 + (4 - abs(4 - n)) asterisks (1, 2, 3, 4, 5, 4, 3, 2, 1)
2 * abs (4 - n) spaces (8, 6, 4, 2, 0, 2, 4, 6, 8)
1 + (4 - abs(4 - n)) asterisks (1, 2, 3, 4, 5, 4, 3, 2, 1)
One option is to increment the number of stars on each row, then go back down once you reached the midpoint.
void printChar(char c, int count)
{
for (int i = 0; i < count; i++)
std::cout << c;
}
int main()
{
const int len = 10;
int stars = 0;
while (++stars <= len / 2)
{
int spaces = len - stars * 2;
printChar('*', stars);
printChar(' ', spaces);
printChar('*', stars);
std::cout << "\n";
}
stars--;
while (--stars > 0)
{
int spaces = len - stars * 2;
printChar('*', stars);
printChar(' ', spaces);
printChar('*', stars);
std::cout << "\n";
}
return 0;
}

Merge sort - four sorted parts in one array

I have one array where are 4 sorted parts. For example
int array[20] = {1,4,7,8,10,2,3,6,8,11,1,2,7,8,9,3,4,9,10,13}
What I need to do is use merge sort on first 2 sorted parts (1,4,7,8,10 and 2,3,6,8,11) and then for second 2 sorted parts (1,2,7,8,9 and 3,4,9,10,13). Then I need to merge these 2 sorted parts into one sorted array.
I tried to use these piece of code, but there is something wrong.
void Merge(int *array, int *aux, int left, int right)
{
int middleIndex = (left + right) / 2;
int leftIndex = left;
int rightIndex = middleIndex + 1;
int auxIndex = left;
while (leftIndex <= middleIndex && rightIndex <= right)
{
if (array[leftIndex] >= array[rightIndex])
{
aux[auxIndex] = array[leftIndex++];
}
else
{
aux[auxIndex] = array[rightIndex++];
}
auxIndex++;
}
while (leftIndex <= middleIndex)
{
aux[auxIndex] = array[leftIndex++];
auxIndex++;
}
while (rightIndex <= right)
{
aux[auxIndex] = array[rightIndex++];
auxIndex++;
}
}
Any idea how to modify this, or write it better? Thanks
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] sortArr1 = merge(new int[] {1 , 4 , 7 , 8 , 10} , new int[] {2 , 3 , 6 , 8 , 11} );
System.out.println("Merging of sorted array " +Arrays.toString(sortArr1));
int[] sortArr2 = merge(new int[] {1 , 2 , 7 , 8 , 9} , new int[] {3 , 4 , 9 , 10 , 13} );
System.out.println("Merging of sorted array " +Arrays.toString(sortArr2));
int[] finalSort = merge(sortArr1 , sortArr2);
System.out.println("Merging of sorted array " +Arrays.toString(finalSort));
}
public static int[] merge(int[] arr1 , int[] arr2) {
int[] sort = new int[arr1.length + arr2.length];
int j = 0;
int k = 0;
for(int i = 0 ; i < sort.length ; i++ ) {
if(j <= (arr1.length - 1) && k <= (arr2.length - 1)) {
if(arr1[j] > arr2[k]) {
sort[i] = arr2[k++];
}else {
sort[i] = arr1[j++];
}
}else if(j <= (arr1.length - 1)) {
sort[i] = arr1[j++];
}else if(k <= (arr2.length - 1)){
sort[i] = arr2[k++];
}
}
return sort;
}
}
Output of the program is :
Merging of sorted array [1, 2, 3, 4, 6, 7, 8, 8, 10, 11]
Merging of sorted array [1, 2, 3, 4, 7, 8, 9, 9, 10, 13]
Merging of sorted array [1, 1, 2, 2, 3, 3, 4, 4, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 11, 13]
Any idea how to modify this, or write it better? Thanks
Since the ranges are already sorted, and you know where the ranges start and end, use std::inplace_merge:
#include <algorithm>
#include <iostream>
#include <iterator>
int array[20] = {1,4,7,8,10,2,3,6,8,11,1,2,7,8,9,3,4,9,10,13};
using namespace std;
void MergeSort(int *arr, int start1, int start2, int start3,
int start4, int size)
{
std::inplace_merge(arr + start1, arr + start2, arr + start3);
std::inplace_merge(arr + start3, arr + start4, arr + size);
std::inplace_merge(array, array + start3, arr + size);
}
int main()
{
MergeSort(array, 0, 5, 10, 15, 20);
std::copy(array, array + 20, ostream_iterator<int>(cout, " "));
}
Live Example

C/C++ - efficient method of rotating an array without using build-in functions (homework)

The task is to rotate left or rotate right a subarray of an array given number of times.
Let me explain this on an example:
lets data be an array.
data = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
a sub array is determined by parameters begin and end.
if begin = 3 and end = 7, then subarray is {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
if begin = 7 and end = 3, then subarray is {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
let's rotate it right two times
if begin = 3 and end = 7, then the result is {0, 1, 2, 6, 7, 3, 4, 5, 8, 9};
if begin = 7 and end = 3, then the result is {8, 9, 0, 1,, 4, 5, 6, 2, 3, 7};
I've written code that performs this task but it's to slow.
Can someone give me a hint how to make it quicker?
Important: I'm not allowed to use other arrays than data, subprograms and build-in functions.
#include <iostream>
using namespace std;
int main(){
int dataLength;
cin >> dataLength;
int data [ dataLength ];
for (int i = 0; i < dataLength; i++){
cin >> data [ i ];
}
int begin;
int end;
int rotation;
int forLoopLength;
int tempBefore;
int tempAfter;
cin >> begin;
cin >> end;
cin >> rotation;
if (end > begin)
forLoopLength = (end - begin) + 1;
else
forLoopLength = (end - begin) + 1 + dataLength;
if (rotation < 0)
rotation = forLoopLength + (rotation % forLoopLength);
else
rotation = rotation % forLoopLength;
for (int i = 0; i < rotation; i++) {
tempBefore = data [ end ];
for (int i = 0; i < forLoopLength; i++) {
tempAfter = data [ (begin + i) % dataLength ];
data [ (begin + i) % dataLength ] = tempBefore;
tempBefore = tempAfter;
}
}
for (int i = 0; i < dataLength; i ++ ) {
cout << data [ i ] << " ";
}
return 0;
}
There's a trick to this. It's pretty weird that you'd get this for homework if the trick wasn't mentioned in class. Anyway...
To rotate a sequence of N elements left by M:
reverse the whole sequence
reverse the last M elements
reverse the first N-M elements
done
e.g. left by 2:
1234567
->
7654321
->
7654312
->
3456712
Here is my code, it makes exactly n reads and n writes, where n is subarray size.
#include<iostream>
int arr[]= { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// replacing 'addr( pos, from, size )' with just 'pos' mean rotation the whole array
int addr( int ptr, int from, int size)
{
return (ptr + from ) % size;
}
void rotate( int* arr, int shift, int from, int count, int size)
{
int i;
int pos= 0;
int cycle= 0;
int c= 0;
int c_old= 0;
// exactly count steps
for ( i=0; i< count; i++ ){
// rotation of arrays part is essentially a permutation.
// every permutation can be decomposed on cycles
// here cycle processing begins
c= arr[ addr( pos, from, size ) ];
while (1){
// one step inside the cycle
pos= (pos + shift) % count;
if ( pos == cycle )
break;
c_old= c;
c= arr[ addr( pos, from, size ) ];
arr[ addr( pos, from, size ) ]= c_old;
i++;
}
// here cycle processing ends
arr[ addr( pos, from, size ) ]= c;
pos= (pos + 1) % count;
cycle= (cycle + 1) % count;
}
}
int main()
{
rotate( arr, 4, 6, 6, 11 );
int i;
for ( i=0; i<11; i++){
std::cout << arr[i] << " ";
}
std::cout << std::endl;
return 0;
}