ArrayQueue
単純なQueueの実装をしていく.
この実装に関してはRing Bufferのような感じで実装をする.
以前にOSの動画で入力で使ったあの構造と同じだね.
まずデータを入れる箱と開始位置,そして現在あるデータのサイズを用意.
開始位置はリングバッファの開始位置で、ここから後にぐるっとなるようなデータ配置にするためのものである.
今までと同じ通りにまずデータサイズ的に問題ないかを判定する.
長さが足りてないなら再確保をする.
そして、データの追加.
剰余を取って、開始位置からサイズをぐるっと回るように配置していく.
最後にデータをカウントアップすれば終わり.
ここまでをまとめたのが以下である.
void Add(T x)
{
// 足りてないなら確保
if (m_size + 1 > m_data.m_length)
{
Resize();
}
// スタート位置を考慮しつつ、追加
// リングバッファのようなものなので、ずらしはしなくてよい
m_data[(m_start + m_size) % m_data.m_length] = x;
// データ数をCountUp
m_size++;
}
まずは現状の取り出す値を保持しておく.
Queueなので先頭を取ればいいね.
そしたらStartの位置を+1してずらす.
もし配列の最後尾まで来てる場合は先頭に戻るように剰余で調節する.
これがリングバッファだね.
ついでに削除もしたので、データ数も下げておく.
配列のサイズに関しても調節をしておく.
現状の配列のサイズよりも圧倒的にデータ数が少ない場合は縮める.
今回は3倍のデータ数にならないように適当に調整してる.
本にはなんで3倍なのかは書いてないけど、まあ
std::vectorとかも現状の2倍とかなので、3倍未満は縮めちゃうのも分かるね.最後に現状の消した値を返せばOK.
これをまとめたのが以下.
// 削除
T Remove()
{
T current = m_data[m_start];
// リングバッファであることを考慮しつつ、
// +1でずらすだけでOK
m_start = (m_start + 1) % m_data.m_length;
// データ数をCountDown
m_size--;
// 余りにも小さい場合は無駄を減らすためshrink
if (m_data.m_length >= 3 * m_size)
{
Resize();
}
// 消したものを返す
return current;
}
これは結構簡単.まずは2倍のデータを確保する.
サイズに関しては負にならないようにする.
そしたら、リングバッファを考慮しつつデータを移す.
startの位置からindexを足して、剰余で境界を注意するだけ.
データを突っ込むのは先頭.
なので、移した後は
start=0からまた始まるようになる.for (int i = 0; i < m_size; i++)
{
// リングバッファを考慮しつつ、先頭になるように入れる
temp[i] = m_data[(m_start + i) % m_data.m_length];
}
これをまとめたのが以下.
これで単純なQueueも完了.