コンピュータは、データを処理する機械であり、その処理手順やデータ構造を示したものがプログラム。
処理の対象となるデータはメモリやディスクに格納されている。
プログラマは、メモリやディスクを自由自在に使いこなせなければならない。
そのために必要なことは、メモリやディスクの構造を物理的(ハードウェア)にも論理的(ソフトウェア)にもイメージできるようになること。
メモリの物理的な仕組みはシンプル
メモリの実態は「メモリIC」と呼ばれる装置。
メモリICには、RAMやROMなど、様々な種類があルガ、外部から見た基本的な仕組みはどれも同じ。
メモリICには、電源、アドレス信号、データ信号、制御信号を入出力するための多くのピンがあり、アドレスを指定して、データを読み書きするようになっている。
シンプルに考えると、メモリICの内部に8ビットのデータを収納できる入れ物がたくさんあり、その場所をアドレスで指定してデータの読み書きを行うだけ。
メモリの物理的なイメージはビルディング
ビルディングには、1フロアに1バイトのデータを格納でき、フロアの番号がアドレスを示すものとなる。
メモリの実体はメモリICだけど、プログラマから見れば個々のフロアにデータが格納されたビルディングだと思えば良い。メモリICの電源や制御信号のことまで意識する必要などない。1KBのメモリなら1024階建てのビルディングとして表せる。
ただしプログラマーから見たメモリーには、物理的なメモリーに存在しない概念がある。
それが「データ型」。プログラミング言語におけるデータ型とは、どのような種類のデータを格納するかを示すものであり、メモリにとってみれば占有するサイズ(ビルのフロア数)を意味するものとなる。
物理的には1バイトずつデータを読み書きするメモリであっても、プログラムでは型を指定して、特定のバイト数ずつまとめて読み書きできるようになっている。
メモリを工夫して使うための基本は配列
配列とは、同じデータ型(サイズ)の複数のデータがメモリ内に連続して並んだもの。配列の要素となる個々のデータは先頭から通し番号で区別され、この番号のことをインデックスと呼ぶ。インデックスを指定すると、それに対応するメモリ領域を読み書きすることができる。インデックスとメモリ・アドレスを変換する処理は、コンパイラによって自動的に生成される。
配列がメモリの使い方の基本となる理由は、配列がメモリの物理的な構造そのものだから。
多くのプログラムでは、様々な工夫を凝らして配列を使っている(スタック、キュー、リスト、2分探索木)。
スタックとキュー
スタックとキューは、どちらもアドレスやインデックスを指定せずに配列の要素を読み書きできるもの。計算の途中のデータや、コンピュータに接続された装置と入出力するデータなどを一時的に保存しておく場合に、これらの手法でメモリを使用する。
スタックとキューの違いは、データを出し入れする順序の違い。
スタックでは、後入れ先出し(LIFO)、キューでは先入れ先出し(FIFO)によって、メモリ内のデータを読み書きする。あらかじめメモリ内にスタックやキューのための領域を確保し、書き込みや読み出しの順序を決めておくことで、アドレスやインデックスの指定が不要になる。
スタックは、「干草を積んだ山」という意味。干草を積んで山を作ると、最後に積んだ干草が、最初に取り出される。家畜に食べさせる飼料を一時的に保存するためのもの。プログラムに置き換えても、一時的にデータを保存する目的で同じ仕組みが使えれば便利!!これをメモリ上で実現したものがスタック。スタックは、データを一時的に退避し、後で元通りに復元する場合などに使用する。git stashは、stackですね、、、
それに対してキューは、配列に格納された最初のデータが最初に取り出される。待ち行列とも呼ばれる。待ち行列とは、電車の切符を買うために自動券売機の前に並んで待っている人の列などのこと。待ち行列は、不定期に訪れる切符の購買者と、それを処理する自動券売機の処理タイミングが合わない場合の緩和剤となるもの。プログラムでも、データの入力と処理のタイミングを調整するために同じ仕組みが使えれば便利!!!これをメモリ上で実現したものがキュー。キューに不定期に格納されるデータをコツコツと処理していく手法は、通信で送られてくるデータを処理する場合や、同時に実行されている複数のプログラムから送られてくるデータを処理する場合などに使用される。
キューはリングバッファと呼ばれる形態で使われることが一般的。
リストは要素の追加や削除が容易
リストと2分探索木は、どちらもインデックスの順序とは無関係に配列の要素を読み書きしたもの。
リストを使用すれば、配列にデータを追加したり削除したりする処理を効率的に行える。
2分探索木を使用すれば、配列に格納されたデータを効率的に探索できる。
リストは、配列の個々の要素に、データの値だけではなく、次の要素のインデックスも付加することで実現できる。
リストでない通常の配列を使用した場合、途中の要素を削除したり、途中に追加したりするときに、その後ろにある要素を全て移動しなければならなくなる。これはとても時間がかかる。
2分探索木は効率的にデータを探せる
2分探索木はリストをさらに工夫し、配列に要素を追加するときに、その大小関係を考慮して左右2つの方向に分岐させるもの。2分探索木を実現させるためには、配列の個々の要素に、データの値と2つのインデックス情報を持たせれば良い。通常の配列を使用した場合には、配列の先頭からインデックスの順に要素を参照して目的のデータを見つける必要があるが、2分探索木なら、目的のデータが現在読み出しているデータより小さければリストの左側を、大きければリストの右側を辿れば良いので、目的のデータをより早く見つけることができる。