Saya ingin menambahkan sedikit lebih detail. Dalam jawaban ini, konsep-konsep kunci diulangi, langkahnya lambat dan sengaja berulang. Solusi yang diberikan di sini bukan yang paling kompak secara sintaksis, namun, ditujukan untuk mereka yang ingin mempelajari apa itu rotasi matriks dan implementasi yang dihasilkan.
Pertama, apa itu matriks? Untuk keperluan jawaban ini, sebuah matriks hanyalah sebuah kotak dengan lebar dan tinggi yang sama. Catatan, lebar dan tinggi matriks bisa berbeda, tetapi untuk kesederhanaan, tutorial ini hanya mempertimbangkan matriks dengan lebar dan tinggi yang sama ( matriks persegi ). Dan ya, matriks adalah bentuk jamak dari matriks.
Contoh matriks adalah: 2 × 2, 3 × 3 atau 5 × 5. Atau, lebih umum, N × N. Matriks 2 × 2 akan memiliki 4 kotak karena 2 × 2 = 4. Matriks 5 × 5 akan memiliki 25 kotak karena 5 × 5 = 25. Setiap kotak disebut elemen atau entri. Kami akan mewakili setiap elemen dengan tanda titik ( .
) pada diagram di bawah ini:
Matriks 2 × 2
. .
. .
Matriks 3 × 3
. . .
. . .
. . .
4 × 4 matriks
. . . .
. . . .
. . . .
. . . .
Jadi, apa artinya memutar matriks? Mari kita mengambil matriks 2 × 2 dan meletakkan beberapa angka di setiap elemen sehingga rotasi dapat diamati:
0 1
2 3
Memutar ini 90 derajat memberi kita:
2 0
3 1
Kami benar-benar mengubah seluruh matriks satu kali ke kanan seperti memutar setir mobil. Mungkin membantu untuk memikirkan “membalik” matriks ke sisi kanannya. Kami ingin menulis sebuah fungsi, dengan Python, yang mengambil matriks dan berputar sekali ke kanan. Tanda tangan fungsi adalah:
def rotate(matrix):
# Algorithm goes here.
Matriks akan didefinisikan menggunakan array dua dimensi:
matrix = [
[0,1],
[2,3]
]
Oleh karena itu posisi indeks pertama mengakses baris. Posisi indeks kedua mengakses kolom:
matrix[row][column]
Kami akan mendefinisikan fungsi utilitas untuk mencetak matriks.
def print_matrix(matrix):
for row in matrix:
print row
Salah satu metode memutar matriks adalah dengan melakukannya satu lapis pada satu waktu. Tapi apa itu layer? Pikirkan bawang. Sama seperti lapisan bawang, saat setiap lapisan dihilangkan, kami bergerak ke tengah. Analogi lainnya adalah boneka Matryoshka atau permainan pass-the-parcel.
Lebar dan tinggi matriks menentukan jumlah lapisan dalam matriks itu. Mari kita gunakan simbol yang berbeda untuk setiap layer:
Matriks 2 × 2 memiliki 1 lapisan
. .
. .
Matriks 3 × 3 memiliki 2 lapisan
. . .
. x .
. . .
Matriks 4 × 4 memiliki 2 lapisan
. . . .
. x x .
. x x .
. . . .
Matriks 5 × 5 memiliki 3 lapisan
. . . . .
. x x x .
. x O x .
. x x x .
. . . . .
Matriks 6 × 6 memiliki 3 lapisan
. . . . . .
. x x x x .
. x O O x .
. x O O x .
. x x x x .
. . . . . .
Matriks 7 × 7 memiliki 4 lapisan
. . . . . . .
. x x x x x .
. x O O O x .
. x O - O x .
. x O O O x .
. x x x x x .
. . . . . . .
Anda mungkin memperhatikan bahwa penambahan lebar dan tinggi matriks satu per satu, tidak selalu menambah jumlah lapisan. Mengambil matriks di atas dan mentabulasi lapisan dan dimensi, kita melihat jumlah lapisan meningkat satu kali untuk setiap dua penambahan lebar dan tinggi:
+-----+--------+
| N×N | Layers |
+-----+--------+
| 1×1 | 1 |
| 2×2 | 1 |
| 3×3 | 2 |
| 4×4 | 2 |
| 5×5 | 3 |
| 6×6 | 3 |
| 7×7 | 4 |
+-----+--------+
Namun, tidak semua lapisan perlu diputar. Matriks 1 × 1 adalah sama sebelum dan sesudah rotasi. Lapisan pusat 1 × 1 selalu sama sebelum dan sesudah rotasi tidak peduli seberapa besar keseluruhan matriks:
+-----+--------+------------------+
| N×N | Layers | Rotatable Layers |
+-----+--------+------------------+
| 1×1 | 1 | 0 |
| 2×2 | 1 | 1 |
| 3×3 | 2 | 1 |
| 4×4 | 2 | 2 |
| 5×5 | 3 | 2 |
| 6×6 | 3 | 3 |
| 7×7 | 4 | 3 |
+-----+--------+------------------+
Dengan matriks N × N, bagaimana kita dapat secara program menentukan jumlah lapisan yang perlu kita putar? Jika kita membagi lebar atau tinggi dengan dua dan mengabaikan sisanya kita mendapatkan hasil berikut.
+-----+--------+------------------+---------+
| N×N | Layers | Rotatable Layers | N/2 |
+-----+--------+------------------+---------+
| 1×1 | 1 | 0 | 1/2 = 0 |
| 2×2 | 1 | 1 | 2/2 = 1 |
| 3×3 | 2 | 1 | 3/2 = 1 |
| 4×4 | 2 | 2 | 4/2 = 2 |
| 5×5 | 3 | 2 | 5/2 = 2 |
| 6×6 | 3 | 3 | 6/2 = 3 |
| 7×7 | 4 | 3 | 7/2 = 3 |
+-----+--------+------------------+---------+
Perhatikan seberapa N/2
cocok dengan jumlah layer yang perlu diputar? Kadang-kadang jumlah lapisan yang dapat diputar adalah kurang dari jumlah total lapisan dalam matriks. Ini terjadi ketika lapisan terdalam hanya terbentuk dari satu elemen (yaitu matriks 1 × 1) dan karenanya tidak perlu diputar. Itu hanya diabaikan.
Kami pasti akan membutuhkan informasi ini dalam fungsi kami untuk memutar matriks, jadi mari kita tambahkan sekarang:
def rotate(matrix):
size = len(matrix)
# Rotatable layers only.
layer_count = size / 2
Sekarang kita tahu apa itu lapisan dan bagaimana menentukan jumlah lapisan yang sebenarnya perlu dirotasi, bagaimana kita mengisolasi satu lapisan sehingga kita bisa memutarnya? Pertama, kami memeriksa matriks dari lapisan terluar, ke dalam, ke lapisan terdalam. Matriks 5 × 5 memiliki tiga lapisan total dan dua lapisan yang perlu dirotasi:
. . . . .
. x x x .
. x O x .
. x x x .
. . . . .
Mari kita lihat kolom terlebih dahulu. Posisi kolom menentukan lapisan terluar, dengan asumsi kita menghitung dari 0, adalah 0 dan 4:
+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
| | . . . . . |
| | . x x x . |
| | . x O x . |
| | . x x x . |
| | . . . . . |
+--------+-----------+
0 dan 4 juga merupakan posisi baris untuk lapisan terluar.
+-----+-----------+
| Row | |
+-----+-----------+
| 0 | . . . . . |
| 1 | . x x x . |
| 2 | . x O x . |
| 3 | . x x x . |
| 4 | . . . . . |
+-----+-----------+
Ini akan selalu terjadi karena lebar dan tinggi adalah sama. Oleh karena itu kita dapat mendefinisikan posisi kolom dan baris pada layer hanya dengan dua nilai (bukan empat).
Pindah ke dalam ke lapisan kedua, posisi kolom adalah 1 dan 3. Dan, ya, Anda dapat menebaknya, itu sama untuk baris. Penting untuk dipahami bahwa kami harus menambah dan mengurangi posisi baris dan kolom saat bergerak ke dalam ke lapisan berikutnya.
+-----------+---------+---------+---------+
| Layer | Rows | Columns | Rotate? |
+-----------+---------+---------+---------+
| Outermost | 0 and 4 | 0 and 4 | Yes |
| Inner | 1 and 3 | 1 and 3 | Yes |
| Innermost | 2 | 2 | No |
+-----------+---------+---------+---------+
Jadi, untuk memeriksa setiap lapisan, kami ingin loop dengan penghitung yang meningkat dan menurun yang mewakili gerakan ke dalam, mulai dari lapisan terluar. Kami akan menyebutnya 'loop layer' kami.
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
print 'Layer %d: first: %d, last: %d' % (layer, first, last)
# 5x5 matrix
matrix = [
[ 0, 1, 2, 3, 4],
[ 5, 6, 6, 8, 9],
[10,11,12,13,14],
[15,16,17,18,19],
[20,21,22,23,24]
]
rotate(matrix)
Kode di atas memotong melalui posisi (baris dan kolom) dari setiap lapisan yang perlu dirotasi.
Layer 0: first: 0, last: 4
Layer 1: first: 1, last: 3
Kami sekarang memiliki lingkaran yang menyediakan posisi baris dan kolom dari setiap lapisan. Variabel first
dan last
mengidentifikasi posisi indeks dari baris dan kolom pertama dan terakhir. Mengacu kembali ke tabel baris dan kolom kami:
+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
| | . . . . . |
| | . x x x . |
| | . x O x . |
| | . x x x . |
| | . . . . . |
+--------+-----------+
+-----+-----------+
| Row | |
+-----+-----------+
| 0 | . . . . . |
| 1 | . x x x . |
| 2 | . x O x . |
| 3 | . x x x . |
| 4 | . . . . . |
+-----+-----------+
Jadi kita dapat menavigasi melalui lapisan-lapisan matriks. Sekarang kita membutuhkan cara menavigasi di dalam lapisan sehingga kita dapat memindahkan elemen di sekitar lapisan itu. Catatan, elemen tidak pernah 'melompat' dari satu layer ke layer lain, tetapi mereka bergerak di dalam layer masing-masing.
Memutar setiap elemen dalam suatu lapisan akan memutar seluruh lapisan. Memutar semua lapisan dalam matriks akan memutar seluruh matriks. Kalimat ini sangat penting, jadi cobalah yang terbaik untuk memahaminya sebelum melanjutkan.
Sekarang, kita membutuhkan cara untuk benar-benar memindahkan elemen, yaitu memutar setiap elemen, dan selanjutnya layer, dan akhirnya matriks. Untuk mempermudah, kami akan kembali ke matriks 3x3 - yang memiliki satu lapisan yang dapat diputar.
0 1 2
3 4 5
6 7 8
Lingkaran lapisan kami menyediakan indeks kolom pertama dan terakhir, serta baris pertama dan terakhir:
+-----+-------+
| Col | 0 1 2 |
+-----+-------+
| | 0 1 2 |
| | 3 4 5 |
| | 6 7 8 |
+-----+-------+
+-----+-------+
| Row | |
+-----+-------+
| 0 | 0 1 2 |
| 1 | 3 4 5 |
| 2 | 6 7 8 |
+-----+-------+
Karena matriks kita selalu kuadrat, kita hanya perlu dua variabel, first
dan last
, karena posisi indeks sama untuk baris dan kolom.
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
# Our layer loop i=0, i=1, i=2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
# We want to move within a layer here.
Variabel pertama dan terakhir dapat dengan mudah digunakan untuk merujuk empat sudut matriks. Ini karena sudut-sudut itu sendiri dapat didefinisikan menggunakan berbagai permutasi dari first
dan last
(tanpa pengurangan, penambahan atau offset variabel-variabel tersebut):
+---------------+-------------------+-------------+
| Corner | Position | 3x3 Values |
+---------------+-------------------+-------------+
| top left | (first, first) | (0,0) |
| top right | (first, last) | (0,2) |
| bottom right | (last, last) | (2,2) |
| bottom left | (last, first) | (2,0) |
+---------------+-------------------+-------------+
Untuk alasan ini, kami memulai rotasi kami di empat sudut terluar - kami akan memutarnya terlebih dahulu. Mari kita sorot dengan mereka *
.
* 1 *
3 4 5
* 7 *
Kami ingin bertukar masing *
- masing dengan di *
sebelah kanannya. Jadi mari kita lanjutkan mencetak sudut-sudut kita yang didefinisikan hanya menggunakan berbagai permutasi dari first
dan last
:
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
top_left = (first, first)
top_right = (first, last)
bottom_right = (last, last)
bottom_left = (last, first)
print 'top_left: %s' % (top_left)
print 'top_right: %s' % (top_right)
print 'bottom_right: %s' % (bottom_right)
print 'bottom_left: %s' % (bottom_left)
matrix = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]
rotate(matrix)
Output harus:
top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)
Sekarang kita bisa dengan mudah menukar masing-masing sudut dari dalam loop layer kita:
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
top_left = matrix[first][first]
top_right = matrix[first][last]
bottom_right = matrix[last][last]
bottom_left = matrix[last][first]
# bottom_left -> top_left
matrix[first][first] = bottom_left
# top_left -> top_right
matrix[first][last] = top_left
# top_right -> bottom_right
matrix[last][last] = top_right
# bottom_right -> bottom_left
matrix[last][first] = bottom_right
print_matrix(matrix)
print '---------'
rotate(matrix)
print_matrix(matrix)
Matriks sebelum memutar sudut:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
Matriks setelah sudut berputar:
[6, 1, 0]
[3, 4, 5]
[8, 7, 2]
Bagus! Kami telah berhasil memutar setiap sudut matriks. Namun, kami belum memutar elemen di tengah setiap lapisan. Jelas kita membutuhkan cara iterasi di dalam layer.
Masalahnya adalah, satu-satunya loop dalam fungsi kita sejauh ini (loop layer kita), bergerak ke lapisan berikutnya pada setiap iterasi. Karena matriks kami hanya memiliki satu lapisan yang dapat diputar, loop lapisan keluar setelah hanya memutar sudut-sudutnya. Mari kita lihat apa yang terjadi dengan matriks 5x5 yang lebih besar (di mana dua lapisan perlu diputar). Kode fungsi telah dihilangkan, tetapi tetap sama seperti di atas:
matrix = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]
]
print_matrix(matrix)
print '--------------------'
rotate(matrix)
print_matrix(matrix)
Outputnya adalah:
[20, 1, 2, 3, 0]
[ 5, 16, 7, 6, 9]
[10, 11, 12, 13, 14]
[15, 18, 17, 8, 19]
[24, 21, 22, 23, 4]
Seharusnya tidak mengherankan bahwa sudut-sudut lapisan terluar telah diputar, tetapi, Anda juga dapat melihat sudut-sudut lapisan berikutnya (ke dalam) juga telah diputar. Ini masuk akal. Kami telah menulis kode untuk menavigasi lapisan dan juga untuk memutar sudut setiap lapisan. Ini terasa seperti kemajuan, tetapi sayangnya kita harus mengambil langkah mundur. Tidak ada gunanya pindah ke lapisan berikutnya sampai lapisan (luar) sebelumnya telah diputar penuh. Yaitu, sampai setiap elemen dalam lapisan telah diputar. Hanya memutar sudut tidak akan berhasil!
Ambil napas dalam-dalam. Kami membutuhkan loop lain. Loop bersarang tidak kurang. Lingkaran bersarang yang baru, akan menggunakan variabel first
dan last
, ditambah offset untuk menavigasi dalam lapisan. Kami akan menyebut loop baru ini sebagai 'loop elemen'. Lingkaran elemen akan mengunjungi setiap elemen di sepanjang baris atas, setiap elemen di sisi kanan, setiap elemen di sepanjang baris bawah dan setiap elemen di sisi kiri.
- Bergerak maju sepanjang baris atas membutuhkan indeks kolom yang akan bertambah.
- Pindah ke sisi kanan membutuhkan indeks baris yang akan bertambah.
- Bergerak mundur di sepanjang bagian bawah membutuhkan indeks kolom harus dikurangi.
- Pindah ke sisi kiri membutuhkan indeks baris harus dikurangi.
Ini kedengarannya rumit, tetapi itu dibuat mudah karena berapa kali kita menambah dan mengurangi untuk mencapai hal di atas tetap sama di sepanjang keempat sisi matriks. Sebagai contoh:
- Pindahkan 1 elemen di baris atas.
- Pindahkan 1 elemen ke sisi kanan.
- Pindahkan 1 elemen ke belakang di sepanjang baris bawah.
- Pindahkan 1 elemen ke sisi kiri.
Ini berarti kita dapat menggunakan variabel tunggal dalam kombinasi dengan first
dan last
variabel untuk bergerak di dalam layer. Mungkin membantu untuk mencatat bahwa bergerak melintasi baris atas dan ke bawah di sisi kanan keduanya membutuhkan penambahan. Saat bergerak mundur di sepanjang bagian bawah dan di sisi kiri keduanya membutuhkan penurunan.
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
# Move through layers (i.e. layer loop).
for layer in range(0, layer_count):
first = layer
last = size - first - 1
# Move within a single layer (i.e. element loop).
for element in range(first, last):
offset = element - first
# 'element' increments column (across right)
top_element = (first, element)
# 'element' increments row (move down)
right_side = (element, last)
# 'last-offset' decrements column (across left)
bottom = (last, last-offset)
# 'last-offset' decrements row (move up)
left_side = (last-offset, first)
print 'top: %s' % (top)
print 'right_side: %s' % (right_side)
print 'bottom: %s' % (bottom)
print 'left_side: %s' % (left_side)
Sekarang kita hanya perlu menetapkan bagian atas ke sisi kanan, sisi kanan ke bawah, bawah ke sisi kiri, dan sisi kiri ke atas. Menyatukan semua ini kita dapatkan:
def rotate(matrix):
size = len(matrix)
layer_count = size / 2
for layer in range(0, layer_count):
first = layer
last = size - first - 1
for element in range(first, last):
offset = element - first
top = matrix[first][element]
right_side = matrix[element][last]
bottom = matrix[last][last-offset]
left_side = matrix[last-offset][first]
matrix[first][element] = left_side
matrix[element][last] = top
matrix[last][last-offset] = right_side
matrix[last-offset][first] = bottom
Mengingat matriks:
0, 1, 2
3, 4, 5
6, 7, 8
rotate
Fungsi kami menghasilkan:
6, 3, 0
7, 4, 1
8, 5, 2