行優先、列優先におけるデータ格納順

2次元配列にデータを格納する場合、2種類の格納の仕方があります。

それは、縦からデータを格納するかor横からデータを格納するかです。

本記事では、縦からデータを格納する方法を列優先とし、

横からデータを格納する方法を行優先とよぶことにします。

データ格納順

プログラミング言語によって記法は異なりますが、2次元配列を用意する場合、

array(x,y)となり、xは縦(行)の大きさ、yは横(列)の大きさになります。

また2次元配列array(2,3)とした場合、以下のようになります。

array(0,0)array(0,1)array(0,2)
array(1,0)array(1,1)array(1,2)

この配列に対して、データがメモリ上から割り当てられるのですが、

ここで、データの格納の仕方が先ほど述べたように2種類になります。

1次元目から動くもの(列優先)

array(0,0)
array(1,0)
array(0,1)
array(1,1)
array(0,2)
array(1,2)

2次元目から動くもの(行優先)

array(0,0)
array(0,1)
array(0,2)
array(1,0)
array(1,1)
array(1,2)

arrayの値を1から6まで1ずつ増える場合、

1次元から動くもの(列優先)

135
246

2次元目から動くもの(行優先)

123
456

となります。

配列を行列としてみた場合、縦(行)と横(列)が同じ(正方行列)ときは、転置行列となります。

プログラミング言語の列優先と行優先

説明した列優先と行優先ですが、プログラミング言語によって違います。

データ格納順を可視化するプログラムを書き、実行してみましょう。

本記事では、インタプリタ言語であるPython、Julia、コンパイラ言語であるC++、Fortranで比較します。

データ格納順を可視化するプログラムですが、差1の等差数列である2×3の2次元配列にして、インデックスとともに値を出力しています。

Python

import numpy as np
if __name__ == '__main__':
    ivar = np.arange( 1,7, dtype='int') 
    ivar = ivar.reshape(2,3) 
    for i in range(2) :
        for j in range(3):
            print('ivar[%1d][%1d] is the %dth order' % (i, j, ivar[i][j] ))

実行例:

$ python rcm.py
ivar[0][0] is the 1th order
ivar[0][1] is the 2th order
ivar[0][2] is the 3th order
ivar[1][0] is the 4th order
ivar[1][1] is the 5th order
ivar[1][2] is the 6th order

2次元目から動いていることが分かると思います。

以上の事から行優先になります。

Julia

using Printf
ivar = reshape(1:6,(2,3))
for j = 1:3
    for i = 1:2
        @printf("ivar[%1d][%1d] is the %dth order\n",i-1,j-1,ivar[i,j])
    end
end

実行例:

$ julia rcm.jl
ivar[0][0] is the 1th order
ivar[1][0] is the 2th order
ivar[0][1] is the 3th order
ivar[1][1] is the 4th order
ivar[0][2] is the 5th order
ivar[1][2] is the 6th order

1次元目から動いていることが分かると思います。

以上の事から列優先になります。

C++

#include <bits/stdc++.h>
using namespace std;

int main(){
  vector<vector<int>> ivar =
    {
     {1,2,3},
     {4,5,6},
    };

  for (int i = 0; i < 2; i++){
    for (int j = 0; j < 3; j++){
      cout << "ivar["<< i << "][" << j \
           << "] is the " << ivar.at(i).at(j) << "th order" << endl;
    }
  }
  return 0;
}

実行例:

$ g++ rcm.cpp
$./a.out
ivar[0][0] is the 1th order
ivar[0][1] is the 2th order
ivar[0][2] is the 3th order
ivar[1][0] is the 4th order
ivar[1][1] is the 5th order
ivar[1][2] is the 6th order

2次元目から動いていることが分かると思います。

以上の事から行優先になります。

Fortran

implicit none
integer::ivar(2,3),i,j
ivar = reshape((/1,2,3,4,5,6/),(/2,3/))
do j=1,3
   do i =1,2
      write(*,'(a,i1,a,i1,a,i1,a)')"ivar[",i-1,"][",j-1,"] is the ",ivar(i,j),"th order"
   enddo
enddo
end program

実行例:

$ gfortran rcm.f90
$./a.out
ivar[0][0] is the 1th order
ivar[1][0] is the 2th order
ivar[0][1] is the 3th order
ivar[1][1] is the 4th order
ivar[0][2] is the 5th order
ivar[1][2] is the 6th order

1次元目から動いていることが分かると思います。

以上の事から列優先になります。

まとめ

データ格納順は、プログラミング言語によって異なる。

1次元目が先に動く(行変動、列固定)場合、列優先

Fortran、Juliaなどが該当

2次元目が先に動く(行固定、列変動)場合、行優先

Python、C、C++などが該当