データ構造 Part.2-2 「動的配列2」

はじめに

前回の記事では動的配列とリストについて解説をしました。
しかしまだ動的配列に関しては詳しく説明していないので、
この記事では、動的配列がどのようなアイデアで作られているかを説明します。

動的配列のアイデア

動的配列は、静的配列をつかってリストを実装したもの。
リストの長さ(size, length)以上の配列を保持する。
この時の配列長を特にcapacityなどと言う。

配列の末尾の方は使わずに無駄に確保している時もありますが、
配列長を気にしなくてもいいリストのメリットが得られます。

リストに要素が挿入されて配列長を超えてしまった場合は、
今より大きな配列を再確保してそちらに要素をコピーします。
新しい配列の長さは言語によって異なりますが、
古い配列の長さの1.5倍や2倍とすることが多いです。

List<Int> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList
 ┣━ size(int)       : 3
 ┣━ _array(int[])   : [1, 2, 3, 0]
 ┗━ _capacity(int)  : 4

 

想定される操作の実装と最悪時間計算量

 

参照( get(i)

参照は静的配列の参照をそのまま利用します。
そのため最悪時間計算量は O(1) となります。

 

挿入と削除( insert(e, i), delete(i)

挿入や削除を行う際は、配列の要素を詰めるため O(n) かかります。

arrayList: (size=3, _array=[1, 2, 3, 0])
↓
↓ insert(e=4, i=0)
↓
arrayList: (size=4, _array=[4, 1, 2, 3])
↓
↓ delete(i=0)
↓
arrayList: (size=3, _array=[1, 2, 3, 0])

末尾の要素の挿入や削除の場合は、詰める処理が必要ないため、
特別に O(1) で操作を完了することができます。

 

リストの想定される操作 時間計算量
参照 get(i) O(1)
挿入 insert(e, i) O(n) (末尾の要素は O(1)
削除 delete(i) O(n) (末尾の要素は O(1)

 

最後に

この記事では動的配列の紹介をしました。
動的配列のアイデアと、計算量などの性質が分かったのではないでしょうか。

さて、実はリストを実装したデータ構造には連結リストもあります。
次の記事では連結リストを紹介して比較します。