मैं थोड़ा और विस्तार जोड़ना चाहूंगा। इस उत्तर में, प्रमुख अवधारणाओं को दोहराया जाता है, गति धीमी और जानबूझकर दोहरावदार होती है। यहां प्रदान किया गया समाधान सबसे अधिक सघन रूप से कॉम्पैक्ट नहीं है, हालांकि, यह उन लोगों के लिए है जो सीखना चाहते हैं कि मैट्रिक्स रोटेशन क्या है और परिणामस्वरूप कार्यान्वयन।
सबसे पहले, एक मैट्रिक्स क्या है? इस उत्तर के प्रयोजनों के लिए, एक मैट्रिक्स सिर्फ एक ग्रिड है जहां चौड़ाई और ऊंचाई समान होती है। ध्यान दें, एक मैट्रिक्स की चौड़ाई और ऊंचाई अलग-अलग हो सकती है, लेकिन सादगी के लिए, यह ट्यूटोरियल केवल समान चौड़ाई और ऊंचाई ( वर्ग मैट्रिसेस ) के साथ मैट्रिसेस को मानता है । और हाँ, मैट्रिक्स मैट्रिक्स का बहुवचन है।
उदाहरण मैट्रीस हैं: 2 × 2, 3 × 3 या 5 × 5। या, अधिक सामान्यतः, एन × एन। 2 × 2 मैट्रिक्स में 4 वर्ग होंगे क्योंकि 2 × 2 = 4। 5 × 5 मैट्रिक्स में 25 वर्ग होंगे क्योंकि 5 × 5 = 25। प्रत्येक वर्ग को एक तत्व या प्रविष्टि कहा जाता है। हम .
नीचे दिए गए चित्र में एक अवधि के साथ प्रत्येक तत्व का प्रतिनिधित्व करेंगे :
2 × 2 मैट्रिक्स
. .
. .
3 × 3 मैट्रिक्स
. . .
. . .
. . .
4 × 4 मैट्रिक्स
. . . .
. . . .
. . . .
. . . .
तो, मैट्रिक्स को घुमाने का क्या मतलब है? आइए 2 × 2 मैट्रिक्स लें और प्रत्येक तत्व में कुछ संख्याएं डालें ताकि रोटेशन को देखा जा सके:
0 1
2 3
इसे 90 डिग्री से घुमाकर हमें देता है:
2 0
3 1
हमने कार की स्टीयरिंग व्हील को मोड़ने की तरह ही पूरे मैट्रिक्स को एक बार दाईं ओर मोड़ दिया। यह मैट्रिक्स को उसके दाईं ओर "टिपिंग" के बारे में सोचने में मदद कर सकता है। हम पायथन में एक फ़ंक्शन लिखना चाहते हैं, जो एक मैट्रिक्स लेता है और एक बार दाईं ओर घूमता है। समारोह हस्ताक्षर होंगे:
def rotate(matrix):
# Algorithm goes here.
मैट्रिक्स को द्वि-आयामी सरणी का उपयोग करके परिभाषित किया जाएगा:
matrix = [
[0,1],
[2,3]
]
इसलिए पहली इंडेक्स स्थिति पंक्ति तक पहुंचती है। दूसरी अनुक्रमणिका स्थिति स्तंभ तक पहुँचती है:
matrix[row][column]
हम मैट्रिक्स प्रिंट करने के लिए एक उपयोगिता फ़ंक्शन को परिभाषित करेंगे।
def print_matrix(matrix):
for row in matrix:
print row
मैट्रिक्स को घुमाने का एक तरीका यह है कि इसे एक बार में एक परत किया जाए। लेकिन एक परत क्या है? एक प्याज के बारे में सोचो। प्याज की परतों की तरह, प्रत्येक परत को हटाने के बाद, हम केंद्र की ओर बढ़ते हैं। अन्य उपमाएँ ए मैट्रीशोका गुड़िया या पास-द-पार्सल का खेल है।
एक मैट्रिक्स की चौड़ाई और ऊंचाई उस मैट्रिक्स में परतों की संख्या निर्धारित करती है। आइए प्रत्येक परत के लिए अलग-अलग प्रतीकों का उपयोग करें:
2 × 2 मैट्रिक्स में 1 परत होती है
. .
. .
एक 3 × 3 मैट्रिक्स में 2 परतें होती हैं
. . .
. x .
. . .
4 × 4 मैट्रिक्स में 2 परतें होती हैं
. . . .
. x x .
. x x .
. . . .
5 × 5 मैट्रिक्स में 3 परतें होती हैं
. . . . .
. x x x .
. x O x .
. x x x .
. . . . .
एक 6 × 6 मैट्रिक्स में 3 परतें होती हैं
. . . . . .
. x x x x .
. x O O x .
. x O O x .
. x x x x .
. . . . . .
7 × 7 मैट्रिक्स में 4 परतें होती हैं
. . . . . . .
. x x x x x .
. x O O O x .
. x O - O x .
. x O O O x .
. x x x x x .
. . . . . . .
आप देख सकते हैं कि मैट्रिक्स की चौड़ाई और ऊंचाई को एक-एक करके बढ़ाते हुए, हमेशा परतों की संख्या में वृद्धि नहीं होती है। उपरोक्त मैट्रिसेस को लेते हुए और परतों और आयामों को सारणीबद्ध करते हुए, हम देखते हैं कि चौड़ाई की प्रत्येक दो वृद्धि के लिए परतों की संख्या एक बार बढ़ जाती है:
+-----+--------+
| N×N | Layers |
+-----+--------+
| 1×1 | 1 |
| 2×2 | 1 |
| 3×3 | 2 |
| 4×4 | 2 |
| 5×5 | 3 |
| 6×6 | 3 |
| 7×7 | 4 |
+-----+--------+
हालांकि, सभी परतों को घूर्णन की आवश्यकता नहीं है। रोटेशन से पहले और बाद में एक 1 × 1 मैट्रिक्स समान है। केंद्रीय 1 × 1 परत हमेशा रोटेशन से पहले और बाद में एक ही होती है, चाहे समग्र मैट्रिक्स कितना भी बड़ा क्यों न हो:
+-----+--------+------------------+
| 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 |
+-----+--------+------------------+
N × N मैट्रिक्स को देखते हुए, हम प्रोग्राम को उन परतों की संख्या कैसे निर्धारित कर सकते हैं जिन्हें हमें घुमाने की आवश्यकता है? यदि हम चौड़ाई या ऊँचाई को दो से विभाजित करते हैं और शेष को अनदेखा करते हैं तो हमें निम्नलिखित परिणाम मिलते हैं।
+-----+--------+------------------+---------+
| 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 |
+-----+--------+------------------+---------+
नोटिस कैसे N/2
परतों की संख्या से मेल खाती है जिन्हें घुमाए जाने की आवश्यकता है? कभी-कभी रोटेटेबल परतों की संख्या मैट्रिक्स में परतों की कुल संख्या से एक कम होती है। यह तब होता है जब अंतरतम परत केवल एक तत्व (यानी 1 × 1 मैट्रिक्स) से बनती है और इसलिए इसे घुमाने की आवश्यकता नहीं होती है। इसे बस नजरअंदाज कर दिया जाता है।
हमें मैट्रिक्स को घुमाने के लिए निस्संदेह इस जानकारी की आवश्यकता होगी, तो चलिए अब इसे जोड़ते हैं:
def rotate(matrix):
size = len(matrix)
# Rotatable layers only.
layer_count = size / 2
अब हम जानते हैं कि परतें क्या हैं और उन परतों की संख्या का निर्धारण कैसे किया जाता है जिन्हें वास्तव में घूर्णन की आवश्यकता होती है, हम एक परत को कैसे अलग करते हैं ताकि हम इसे घुमा सकें? सबसे पहले, हम बाहरी परत से एक मैट्रिक्स का निरीक्षण करते हैं, अंदर की तरफ, सबसे भीतरी परत तक। 5 × 5 मैट्रिक्स में कुल तीन परतें होती हैं और दो परतों को घूमने की आवश्यकता होती है:
. . . . .
. x x x .
. x O x .
. x x x .
. . . . .
पहले कॉलम को देखें। सबसे बाहरी परत को परिभाषित करने वाले स्तंभों की स्थिति, मान लें कि हम 0 से गिनते हैं, 0 और 4 हैं:
+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
| | . . . . . |
| | . x x x . |
| | . x O x . |
| | . x x x . |
| | . . . . . |
+--------+-----------+
0 और 4 सबसे बाहरी परत के लिए पंक्तियों की स्थिति भी हैं।
+-----+-----------+
| Row | |
+-----+-----------+
| 0 | . . . . . |
| 1 | . x x x . |
| 2 | . x O x . |
| 3 | . x x x . |
| 4 | . . . . . |
+-----+-----------+
चौड़ाई और ऊंचाई समान होने के बाद से हमेशा यही स्थिति रहेगी। इसलिए हम एक लेयर के कॉलम और रो पोज़िशन्स को सिर्फ दो वैल्यूज़ (चार के बजाय) से परिभाषित कर सकते हैं।
दूसरी परत की ओर बढ़ते हुए, स्तंभों की स्थिति 1 और 3 है। और, हां, आपने अनुमान लगाया है, यह पंक्तियों के लिए समान है। यह समझना महत्वपूर्ण है कि अगली पंक्ति में अंदर की ओर बढ़ने पर हमें पंक्ति और स्तंभ स्थिति दोनों को बढ़ाना और घटाना पड़ता है।
+-----------+---------+---------+---------+
| Layer | Rows | Columns | Rotate? |
+-----------+---------+---------+---------+
| Outermost | 0 and 4 | 0 and 4 | Yes |
| Inner | 1 and 3 | 1 and 3 | Yes |
| Innermost | 2 | 2 | No |
+-----------+---------+---------+---------+
इसलिए, प्रत्येक परत का निरीक्षण करने के लिए, हम बढ़ते हुए और घटते हुए काउंटरों के साथ एक लूप चाहते हैं जो बाहरी परत से शुरू होकर अंदर की ओर जाने का प्रतिनिधित्व करते हैं। हम इसे 'लेयर लूप' कहेंगे।
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)
किसी भी परतों की पंक्ति (पंक्ति और स्तंभ) के माध्यम से छोरों के ऊपर का कोड जिसे घूर्णन की आवश्यकता होती है।
Layer 0: first: 0, last: 4
Layer 1: first: 1, last: 3
अब हमारे पास एक लूप है जो प्रत्येक परत की पंक्तियों और स्तंभों की स्थिति प्रदान करता है। चर first
और last
पहली और आखिरी पंक्तियों और स्तंभों की सूचकांक स्थिति की पहचान करें। हमारी पंक्ति और स्तंभ तालिका पर वापस जाएं:
+--------+-----------+
| 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 | . . . . . |
+-----+-----------+
तो हम एक मैट्रिक्स की परतों के माध्यम से नेविगेट कर सकते हैं। अब हमें एक परत के भीतर नेविगेट करने के तरीके की आवश्यकता है ताकि हम उस परत के चारों ओर तत्वों को स्थानांतरित कर सकें। ध्यान दें, तत्व कभी भी एक परत से दूसरी परत पर 'कूदते' नहीं हैं, लेकिन वे अपनी संबंधित परतों में चलते हैं।
एक परत में प्रत्येक तत्व को घुमाने से पूरी परत घूम जाती है। मैट्रिक्स में सभी परतों को घुमाने से पूरी मैट्रिक्स घूम जाती है। यह वाक्य बहुत महत्वपूर्ण है, इसलिए कृपया आगे बढ़ने से पहले इसे समझने की पूरी कोशिश करें।
अब, हमें वास्तव में बढ़ते तत्वों का एक तरीका चाहिए, अर्थात प्रत्येक तत्व को घुमाएं, और बाद में परत, और अंततः मैट्रिक्स। सादगी के लिए, हम एक 3x3 मैट्रिक्स में वापस लौटेंगे - जिसमें एक सड़ने योग्य परत है।
0 1 2
3 4 5
6 7 8
हमारा लेयर लूप पहले और आखिरी कॉलम के इंडेक्स प्रदान करता है, साथ ही पहली और आखिरी पंक्तियाँ:
+-----+-------+
| 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 |
+-----+-------+
चूँकि हमारे मैट्रेस हमेशा चौकोर होते हैं, हमें सिर्फ दो वेरिएबल्स की जरूरत होती है, first
और last
, चूंकि इंडेक्स पोज़िशन रो और कॉलम के लिए समान होती हैं।
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.
पहले और आखिरी चर आसानी से एक मैट्रिक्स के चार कोनों को संदर्भित करने के लिए इस्तेमाल किया जा सकता है। इसका कारण यह है कोनों खुद को के विभिन्न क्रमपरिवर्तन का उपयोग कर परिभाषित किया जा सकता first
है और last
(कोई घटाव, इसके अलावा के साथ या उन चर के ऑफसेट):
+---------------+-------------------+-------------+
| 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) |
+---------------+-------------------+-------------+
इस कारण से, हम बाहरी चार कोनों पर अपना रोटेशन शुरू करते हैं - हम पहले उन परिक्रमा करेंगे। आइए उनके साथ प्रकाश डालें *
।
* 1 *
3 4 5
* 7 *
हम इसके अधिकार के *
साथ प्रत्येक को स्वैप करना चाहते हैं *
। तो चलिए आगे बढ़ते हैं कि हमारे विभिन्न कोनों का उपयोग करके परिभाषित हमारे कोनों का एक प्रिंट आउट first
और 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)
आउटपुट होना चाहिए:
top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)
अब हम अपने लेयर लूप में से प्रत्येक कोने को आसानी से स्वैप कर सकते हैं:
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)
कोनों को घुमाने से पहले मैट्रिक्स:
[0, 1, 2]
[3, 4, 5]
[6, 7, 8]
कोनों को घुमाने के बाद मैट्रिक्स:
[6, 1, 0]
[3, 4, 5]
[8, 7, 2]
महान! हमने मैट्रिक्स के प्रत्येक कोने को सफलतापूर्वक घुमाया है। लेकिन, हमने तत्वों को प्रत्येक परत के बीच में नहीं घुमाया है। स्पष्ट रूप से हमें एक परत के भीतर पुनरावृति के तरीके की आवश्यकता है।
समस्या यह है कि हमारे फ़ंक्शन में अब तक का एकमात्र लूप (हमारा लेयर लूप) है, जो प्रत्येक पुनरावृत्ति पर अगली परत पर जाता है। चूँकि हमारी मैट्रिक्स में केवल एक घूर्णन योग्य परत होती है, इसलिए लेयर लूप केवल कोनों को घुमाने के बाद बाहर निकल जाता है। आइए देखें कि बड़े, 5 × 5 मैट्रिक्स (जहां दो परतों को घुमाने की आवश्यकता होती है) के साथ क्या होता है। फ़ंक्शन कोड को छोड़ दिया गया है, लेकिन यह ऊपर जैसा है:
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)
आउटपुट है:
[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]
यह आश्चर्य की बात नहीं होनी चाहिए कि सबसे बाहरी परत के कोनों को घुमाया गया है, लेकिन, आप अगली परत के कोनों को भी नोटिस कर सकते हैं (अंदर की ओर) भी घुमाया गया है। यह समझ में आता है। हमने परतों के माध्यम से नेविगेट करने और प्रत्येक परत के कोनों को घुमाने के लिए कोड लिखा है। यह प्रगति की तरह लगता है, लेकिन दुर्भाग्य से हमें एक कदम वापस लेना चाहिए। जब तक पिछली (बाहरी) परत को पूरी तरह से घुमाया नहीं गया है, तब तक यह अगली परत पर अच्छा नहीं है। यही है, जब तक कि परत में प्रत्येक तत्व को घुमाया नहीं गया है। केवल कोनों को घुमाने से कुछ नहीं होगा!
एक गहरी सास लो। हमें एक और लूप चाहिए। एक नेस्टेड लूप कम नहीं। नया, नेस्टेड लूप, first
और last
चर का उपयोग करेगा , साथ ही एक परत के भीतर नेविगेट करने के लिए एक ऑफसेट। हम इस नए लूप को 'एलिमेंट लूप' कहेंगे। तत्व लूप शीर्ष पंक्ति के साथ प्रत्येक तत्व, दाईं ओर नीचे प्रत्येक तत्व, नीचे पंक्ति के साथ प्रत्येक तत्व और बाईं ओर प्रत्येक तत्व पर जाएगा।
- शीर्ष पंक्ति के साथ आगे की ओर बढ़ने पर कॉलम इंडेक्स को बढ़ाना पड़ता है।
- दाईं ओर नीचे जाने पर पंक्ति सूचकांक को बढ़ाना पड़ता है।
- नीचे की ओर पीछे की ओर बढ़ने के लिए कॉलम इंडेक्स को घटाया जाना आवश्यक है।
- बाईं ओर ऊपर ले जाने के लिए पंक्ति सूचकांक को घटाना आवश्यक है।
यह जटिल लगता है, लेकिन यह आसान है क्योंकि जितनी बार हम वृद्धि और वृद्धि को प्राप्त करते हैं उतनी बार मैट्रिक्स के सभी चार पक्षों के साथ समान रहता है। उदाहरण के लिए:
- शीर्ष पंक्ति में 1 तत्व ले जाएँ।
- दाईं ओर नीचे 1 तत्व ले जाएँ।
- नीचे पंक्ति के साथ 1 तत्व पीछे की ओर ले जाएं।
- बाईं ओर ऊपर 1 तत्व ले जाएँ।
इसका अर्थ है कि हम एक चर के साथ संयोजन में एक चर का उपयोग कर सकते हैं first
और last
एक परत के भीतर स्थानांतरित करने के लिए। यह नोट करने में मदद कर सकता है कि शीर्ष पंक्ति के नीचे और दाईं ओर नीचे बढ़ने पर दोनों को इंक्रीमेंट की आवश्यकता होती है। पीछे की ओर नीचे की ओर और बाईं ओर ऊपर की ओर ले जाने पर दोनों को घटने की आवश्यकता होती है।
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)
अब हमें बस ऊपर से दाईं ओर, नीचे से दाईं ओर, नीचे से बाईं ओर, और बाईं ओर से ऊपर की ओर असाइन करने की आवश्यकता है। यह सब हम एक साथ लाना:
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
मैट्रिक्स को देखते हुए:
0, 1, 2
3, 4, 5
6, 7, 8
हमारे rotate
समारोह में परिणाम:
6, 3, 0
7, 4, 1
8, 5, 2