Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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;
}
like image 903
ltw Avatar asked Dec 18 '22 22:12

ltw


2 Answers

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

like image 109
Matt Timmermans Avatar answered Dec 24 '22 01:12

Matt Timmermans


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;
}
like image 22
Alexey Birukov Avatar answered Dec 24 '22 03:12

Alexey Birukov