In this lesson, we’ll learn about rotating matrices by 90 degrees in both clockwise and counterclockwise directions. To grasp the essence of matrix rotation, we’ll begin by visualizing the concept, allowing us to better comprehend the transformations involved. Subsequently, we’ll proceed to the implementation stage, where we’ll implement and understand the code for clockwise matrix rotation.

Here’s the exercise playground where you’ll write your implementation following the guidance provided after the playground.

Exercise playground

4

2 2
1 2 
4 5

2 3
1 2 3
4 5 4

2 2
1 2 
4 5

5 3 
4 6 5
3 3 4
5 8 9
4 5 3
7 2 3
Exercise playground

Implementation of the clockwise matrix rotation

Let’s discuss two implementations.

Implementation 1: Clockwise matrix rotation (using extra matrix and reordering it)

╔═══════════╦═══════════╗
║ Original ║ Rotated ║
╠═══════════╬═══════════╣
║ 1 2 3 ║ 7 4 1 ║
║ 4 5 6 ║ 8 5 2 ║
║ 7 8 9 ║ 9 6 3 ║
╚═══════════╩═══════════╝

Notice the following:

  • Each column becomes a row. For example, the first column is the first row, the second column is the second row, and so on.

  • Each column is in reverse order. So, for each element at the position (r, c) in the original matrix, it is placed at the position (c, Rows-1-r) in the rotated matrix.

Let’s look at the implementation:

Press + to interact
const Matrix Matrix::RotateCW()const // We have deliberately implemented RotateCW() in-place
{
Matrix cycle(this->cols, this->rows);
for (int r = 0; r <this->rows; r++)
{
for (int c = 0; c < this->cols; c++)
{
cycle.Vs[c][cycle.rows - 1 - r] = this->Vs[r][c];
}
}
return cycle;
}
const Matrix Matrix::RotateCWMulti(const int multiple)const
{
if (multiple % 90 != 0)
{
cout << "Not a multiple of 90 entered, returning the original matrix. Press any key to continue" << endl;
//getch();
return*this;
}
Matrix result = *this;
int cycles = multiple / 90;
for (int i = 1; i <=cycles; i++)
{
result = result.RotateCW();
}
return result;
}
  • Lines 1–11: The first function, Matrix::RotateCW(), rotates the matrix by 90 degrees in a clockwise direction. It creates a new matrix called cycle with swapped dimensions, representing the rotated matrix. Using nested loops, it iterates over each element of the original matrix and assigns the corresponding element to its rotated position in the cycle matrix. Finally, it returns the cycle (the rotated matrix).

  • Lines 13–28: The second function, Matrix::RotateCWMulti(const int multiple), allows rotating the matrix by a multiple of 90 degrees. It checks if the provided value for multiple is a multiple of 90 degrees. If not, it displays an error message and returns the original matrix. If multiple is a multiple of 90 degrees, it initializes the result matrix as a copy of the original matrix. Then, it determines the number of cycles needed for the rotation. Using a loop, it performs the rotation by repeatedly calling the RotateCW() function and updating the result matrix. After the loop, the final rotated matrix result is returned.

Implementation 2: Using transpose as a subroutine

To tackle this problem, we’ve broken it down into three distinct steps for better implementation:

  1. We initialize a 3×33 \times 3 matrix. This part is already implemented in the main() function.

  2. We reverse each column of the matrix individually.

  3. Finally, we obtain the transpose of the modified matrix.

Each step is visually depicted below to provide a clearer understanding of the concept at hand:

Press + to interact
90 degrees clockwise rotation
90 degrees clockwise rotation

Here’s our second implementation:

Press + to interact
int Matrix::reverseEveryColumn()
{
for (int c = 0; c < this->cols; c++) // for each column c
{
for (int r = 0; r <this->rows/2-1; r++) // for each element in the upper half column
{
swap(this->Vs[r][c], this->Vs[this->rows-1-r][c]); // swap with lower one
}
}
}
const Matrix Matrix::RotateCW()const
{
reverseEveryColumn();
*this = !(*this); // transpose
return *this; // We have deliberately implemented RotateCW() in-place
}

Includes two functions related to matrix operations.

  • Lines 1–10: The first function, Matrix::reverseEveryColumn(), reverses the elements in each column of the matrix. It iterates over each column c and, using a nested loop, swaps the elements in the upper half of the column with their corresponding elements in the lower half of the column.

  • Lines 11–16: The second function, Matrix::RotateCW(), rotates the matrix clockwise by 90 degrees. It first calls the reverseEveryColumn() function to reverse the elements in each column. Then, it performs a matrix transpose operation by using the overloaded ! operator on the matrix i.e., *this = !(*this). Finally, it returns the modified matrix. It is important to note that the implementation of the RotateCW() function is done in place, meaning that the original matrix is modified rather than creating a new matrix for the rotated result.

Exercise: Matrix rotation counterclockwise

This exercise is here to give you an opportunity to practice. Implement the code to reindex the population of a counterclockwise matrix.

Implementation 1: Counterclockwise matrix rotation

You need to create the following two functions:

  • The RotateACW() function that rotates the matrix counterclockwise by 90 degrees,

  • And the RotateACWMulti() function that extends this capability to rotate the matrix by a multiple of 90 degrees in a counterclockwise direction.

Write your own code in the Exercise playground. If you have trouble getting to the solution, you can click the “Show solution” button to see how to implement it.

Implementation 2: Using transpose

Similar to the second implementation done in the clockwise case, here’s the observation:

We’ve broken it down into three distinct steps for better understanding and implementation:

  1. We initialize a 3×33 \times 3 matrix. This part is already implemented in the main() function.

  2. Next, we reverse each row of the matrix individually.

  3. Finally, we obtain the transpose of the modified matrix.

Each step is visually depicted below to provide a clearer understanding of this concept.

Press + to interact
90 degrees counterclockwise rotation
90 degrees counterclockwise rotation

Assigning operators to clockwise/counterclockwise rotations

Now that we have implemented the two functions, we can easily make our own two user-defined operators for our Matrix class with the following two prototypes (defined in Matrix.h):

const Matrix operator>(int clockwiseAngle)const; // ClockwiseAngle: multiple of 90
const Matrix operator<(int counterClockwiseAngle)const; // counterClockwiseAngle: multiple of 90

Their implementation will be the following:

const Matrix Matrix::operator>(int clockwiseAngle)const // ClockwiseAngle: multiple of 90
{
return RotateCWMulti(clockwiseAngle);
}
const Matrix Matrix::operator<(int counterClockwiseAngle)const // counterClockwiseAngle: multiple of 90
{
return RotateACWMulti(counterClockwiseAngle);
}
Assigning operators to clockwise and counter clockwise rotations

Notice that we have already implemented the operator >() and operator <() functions, but these operators are different because the arguments passed to these operators are different from the ones we implemented in the previous lesson for adding comparison operators (for a matrix search as a subset).

Tip: Write these two operator Matrix.cpp and operator <(), in the Matrix.cpp file in the Exercise playground.