C++ での並列配列データ構造
この記事では、C++ で並列配列データ構造を実装する方法を示します。
C++ でカスタム並列配列クラスを実装するために std::vector
コンテナを使う
並列配列は、複数のレコードの配列を実装する抽象データ構造であり、各レコードにはエンティティ全体としてアクセスできます。基本的に、対応する要素に並行してアクセスできる複数の同じサイズの配列を想像する必要があります。このデータ構造は、見つかった要素と同じインデックス上の対応する要素にアクセスできるため、配列の 1つが並べ替えられている場合、比較的高速な要素検索操作を提供できます。
並列配列は、さまざまな方法を使用して実装できます。この場合、概念をよりよく説明するための最も簡単なコンテナとして、std::vector
STL コンテナを選択しました。
実装を簡素化するために、具象型の 2つの配列(string
と int
)のみを格納する ParallelArray
クラスを定義します。このクラスには、データ構造の内容を格納する std::vector
タイプの 2つの private
データメンバーが含まれています。内部配列の予想サイズを受け入れ、std::vector::reserved
関数を呼び出して十分なメモリを事前に割り当てるように、単一のコンストラクターが定義されています。このパラメーターはオプションであり、デフォルト値は 20
であることに注意してください。
タイプ ParallelArray
のオブジェクトを初期化したら、push_back
メンバー関数を使用してデータをオブジェクトにプッシュする必要があります。この関数は、vector
メンバー(v1
と v2
)の両方に同じ名前の対応するメンバー関数を呼び出します。また、ParallelArray
オブジェクトの現在の要素数を取得するために、size
と呼ばれるメンバー関数を定義しました。
このクラスには、構造内に格納されている要素にアクセスするために定義された []
演算子もあります。ParallelArray
には固定データ型の配列があるため、operator[]
は std::pair<string, int>
値を返します。または、クラステンプレートを作成して、複数のジェネリック型を受け入れ、内部の vector
オブジェクトを初期化し、それに応じてメンバー関数を書き換えることもできます。クラスが 3つ以上の内部 vector
データメンバーを宣言している場合、operator[]
は STL の std::make_tuple
メソッドを使用して要素を返すことができます。
#include <iostream>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
class ParallelArray {
public:
explicit ParallelArray(size_t size = 20) {
v1.reserve(size);
v2.reserve(size);
};
void push_back(string &d1, int d2);
size_t size();
std::pair<string, int> operator[](size_t pos);
private:
vector<string> v1;
vector<int> v2;
};
void ParallelArray::push_back(string &d1, int d2) {
v1.push_back(d1);
v2.push_back(d2);
}
std::pair<string, int> ParallelArray::operator[](size_t pos) {
if (pos <= v1.size()) {
return std::make_pair(v1[pos], v2[pos]);
} else {
return std::make_pair("null", -1);
}
}
size_t ParallelArray::size() { return v1.size(); }
template <typename T1, typename T2>
void printPair(const std::pair<T1, T2> &pp) {
cout << "{" << pp.first << "," << pp.second << "}" << endl;
}
int main() {
ParallelArray pa1;
vector<string> data_set1 = {"Precise", "Quantal", "Saucy", "Raring"};
vector<int> data_set2 = {11, 22, 33, 44};
for (size_t i = 0; i < data_set1.size(); ++i) {
pa1.push_back(data_set1[i], data_set2[i]);
}
for (size_t i = 0; i < pa1.size(); ++i) {
printPair(pa1[i]);
}
return EXIT_SUCCESS;
}
出力:
{Precise,11}
{Quantal,22}
{Saucy,33}
{Raring,44}
どちらのコードスニペットでも、基本的なドライバーコードを main
関数の一部として実装して ParallelArray
オブジェクトを作成し、クラスのコンテンツを出力します。printPair
ヘルパー関数は、std::pair
オブジェクトの値をコンソールに表示するために使用されます。
さらに、pop_back
メンバー関数を追加して、各 vector
データメンバーの末尾から格納されている要素を削除できます。pop_back
関数はパラメーターを受け入れず、std::vector::pop_back
関数を呼び出します。後者の関数の使用法は、次のコード例に示されています。
#include <iostream>
#include <string>
#include <vector>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
class ParallelArray {
public:
explicit ParallelArray(size_t size = 20) {
v1.reserve(size);
v2.reserve(size);
};
void push_back(string &d1, int d2);
void pop_back();
size_t size();
std::pair<string, int> operator[](size_t pos);
private:
vector<string> v1;
vector<int> v2;
};
void ParallelArray::push_back(string &d1, int d2) {
v1.push_back(d1);
v2.push_back(d2);
}
std::pair<string, int> ParallelArray::operator[](size_t pos) {
if (pos <= v1.size()) {
return std::make_pair(v1[pos], v2[pos]);
} else {
return std::make_pair("null", -1);
}
}
size_t ParallelArray::size() { return v1.size(); }
void ParallelArray::pop_back() {
v1.pop_back();
v2.pop_back();
}
template <typename T1, typename T2>
void printPair(const std::pair<T1, T2> &pp) {
cout << "{" << pp.first << "," << pp.second << "}" << endl;
}
int main() {
ParallelArray pa1;
vector<string> data_set1 = {"Precise", "Quantal", "Saucy", "Raring"};
vector<int> data_set2 = {11, 22, 33, 44};
for (size_t i = 0; i < data_set1.size(); ++i) {
pa1.push_back(data_set1[i], data_set2[i]);
}
for (size_t i = 0; i < pa1.size(); ++i) {
printPair(pa1[i]);
}
pa1.pop_back();
pa1.pop_back();
cout << "------------------------" << endl;
for (size_t i = 0; i < pa1.size(); ++i) {
printPair(pa1[i]);
}
return EXIT_SUCCESS;
}
出力:
{Precise,11}
{Quantal,22}
{Saucy,33}
{Raring,44}
------------------------
{Precise,11}
{Quantal,22}