5

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;
}
6
  • 4
    std::rotate Commented Nov 22, 2015 at 22:16
  • 2
    using namespace std; + variables named begin and end is bound for disaster. Commented Nov 22, 2015 at 22:20
  • 3
    If your code is already working correctly but you are seeking tips to improve it, you can also ask on Code Review. If you decide to do so, please delete the question here because double-posting is frowned upon. Commented Nov 22, 2015 at 22:20
  • 1
    Please pick one language. Commented Nov 22, 2015 at 22:20
  • 2
    @ltw did you ever care to look at his link? Commented Nov 22, 2015 at 22:25

2 Answers 2

11

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

Sign up to request clarification or add additional context in comments.

3 Comments

This is quite awesome, but it will probably get him in trouble as an answer to his homework assignment, because it is waaay too advanced.
It would be fast for lists, not for arrays. Here you have two traversals on whole array, while single traversal on rotation part is enough.
@Alexey, You're probably forgetting that reversing N elements in an array only takes N/2 swaps, so this takes N swaps altogether. If you have a faster way for arrays, I'd love to see it!
2

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;
}

2 Comments

Granted. N moves is faster than N swaps, even through a temporary, and this came out a lot cleaner than I though it would. I'll upvote now and test later.
N moves is not necessarily faster than N swaps. Locality of data access is important, and the swaps method in Matt's answer makes significantly fewer passes through the array (factor of M) -- even though every pass only rewrites 1/M of the elements, it still fetches all the elements through the cache controller.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.