Wie andere gesagt haben, ist das Problem das Speichern des Speicherorts im Array : x[i][j]
. Hier ein kleiner Einblick, warum:
Sie haben ein zweidimensionales Array, aber der Speicher im Computer ist von Natur aus eindimensional. Während Sie sich Ihr Array so vorstellen:
0,0 | 0,1 | 0,2 | 0,3
----+-----+-----+----
1,0 | 1,1 | 1,2 | 1,3
----+-----+-----+----
2,0 | 2,1 | 2,2 | 2,3
Ihr Computer speichert es als einzelne Zeile im Speicher:
0,0 | 0,1 | 0,2 | 0,3 | 1,0 | 1,1 | 1,2 | 1,3 | 2,0 | 2,1 | 2,2 | 2,3
Im zweiten Beispiel greifen Sie auf das Array zu, indem Sie zuerst die zweite Nummer durchlaufen, dh:
x[0][0]
x[0][1]
x[0][2]
x[0][3]
x[1][0] etc...
Das bedeutet, dass Sie sie alle in der richtigen Reihenfolge treffen. Schauen Sie sich jetzt die 1. Version an. Sie gehen:
x[0][0]
x[1][0]
x[2][0]
x[0][1]
x[1][1] etc...
Aufgrund der Art und Weise, wie C das 2D-Array im Speicher angeordnet hat, bitten Sie es, überall hin zu springen. Aber jetzt zum Kicker: Warum ist das wichtig? Alle Speicherzugriffe sind gleich, oder?
Nein, wegen Caches. Daten aus Ihrem Speicher werden in kleinen Blöcken (als "Cache-Zeilen" bezeichnet), normalerweise 64 Byte, an die CPU übertragen. Wenn Sie 4-Byte-Ganzzahlen haben, bedeutet dies, dass Sie 16 aufeinanderfolgende Ganzzahlen in einem ordentlichen kleinen Bündel erhalten. Es ist eigentlich ziemlich langsam, diese Erinnerungsstücke abzurufen. Ihre CPU kann in der Zeit, die zum Laden einer einzelnen Cache-Zeile benötigt wird, viel Arbeit leisten.
Schauen Sie sich jetzt die Reihenfolge der Zugriffe noch einmal an: Das zweite Beispiel besteht darin, (1) einen Teil von 16 Zoll zu greifen, (2) alle zu ändern, (3) 4000 * 4000/16 Mal zu wiederholen. Das ist schön und schnell und die CPU hat immer etwas zu arbeiten.
Das erste Beispiel ist (1) einen Teil von 16 Zoll nehmen, (2) nur einen davon modifizieren, (3) 4000 * 4000 Mal wiederholen. Das erfordert die 16-fache Anzahl von "Abrufen" aus dem Speicher. Ihre CPU muss tatsächlich Zeit damit verbringen, herumzusitzen und darauf zu warten, dass dieser Speicher angezeigt wird, und während sie herumsteht, verschwenden Sie wertvolle Zeit.
Wichtige Notiz:
Nachdem Sie die Antwort erhalten haben, ist hier ein interessanter Hinweis: Es gibt keinen inhärenten Grund, warum Ihr zweites Beispiel das schnelle sein muss. In Fortran wäre beispielsweise das erste Beispiel schnell und das zweite langsam. Das liegt daran, dass Fortran die Dinge nicht wie C in konzeptionelle "Zeilen" erweitert, sondern in "Spalten", dh:
0,0 | 1,0 | 2,0 | 0,1 | 1,1 | 2,1 | 0,2 | 1,2 | 2,2 | 0,3 | 1,3 | 2,3
Das Layout von C heißt 'Zeilenmajor' und Fortrans heißt 'Spaltenmajor'. Wie Sie sehen, ist es sehr wichtig zu wissen, ob Ihre Programmiersprache Zeilen- oder Spaltenmajor ist! Hier ist ein Link für weitere Informationen: http://en.wikipedia.org/wiki/Row-major_order