まず、抽象クラスLinearListを使用して、線形リストを定義します
template<class T>
class LinearList {
public:
virtual ~LinearList() {
};
virtual bool empty()const = 0;
virtual int size()const = 0;
virtual T &Getelement(int index)const = 0;//返回index下标处元素
virtual int ElementPos(const T &Element)const = 0;//返回Element第一次出现位置
virtual void earse(int Index) = 0;//删除Index下标处元素
virtual void insert(int Index, const T &Element) = 0;//插入Element至Index下标处
virtual void ouput(ostream &out)const = 0;//输出流对象
};
便宜上、例外クラスをカスタマイズして、必要に応じて添え字の範囲外の例外をスローします
class illegalIndexValue {
public:
illegalIndexValue() : message("Illegal index value") {
}
private:
string message;
};
次は、LinearListから継承されたカスタム配列クラスArrayListで、仮想関数の実装に基づいて必要な関数を追加します。
template<class T>
class ArrayList :public LinearList<T> {
public:
ArrayList(int x = 10);
ArrayList(const ArrayList &p);//复制构造函数
~ArrayList();
bool empty()const;
int size()const;
T &Getelement(int Index);//返回index下标处元素
int ElementPos(const T &Element);//返回Element第一次出现位置
void earse(int Index);//删除Index下标处元素
void insert(int Index, const T &Element);//插入Element至Index下标处
void ouput(ostream &out)const;//输出流对象
int Getcapacity()const;//返回数组容量
void ChangeLength(int OldL, int NewL);//改变数组长度
friend ostream &operator<<(ostream &out, const ArrayList<T>&x);
void CheckIndex(int index)const;//检查check是否越界
protected:
T *element;//存储一维数组
int ArrayLength;//一维数组容量
int ListSize;//当前元素个数
};
1つ目は、コンストラクタ、コピーコンストラクタ、デストラクタの関数実現です。コンストラクターでは、テストデータと合理性に基づいて動的割り当てが実行されます。コピーコンストラクタでは、最初にディープコピーの割り当てが必要です。デストラクタで動的に割り当てられたメモリを解放します。
template<class T>
ArrayList<T>::ArrayList(int x) {
if (x < 0) {
throw illegalIndexValue();
}
ArrayLength = x;
ListSize = 0;
element = new T[ArrayLength];
}
template<class T>
ArrayList<T>::ArrayList(const ArrayList &p) {
ArrayLength = p.ArrayLength;
ListSize = p.ListSize;
//深拷贝数组元素
element = new T[ArrayLength];
copy(p.element, p.element + ArrayLength, element);
}
template<class T>
ArrayList<T>::~ArrayList() {
delete[]element;
}
1次元配列では、配列の長さを変更する必要があることがよくあります。このとき、最初に新しい配列を作成し、次にcopy関数を使用して要素をコピーし、最後に古い配列メモリを解放する必要があります。
template<class T>
void ArrayList<T>::ChangeLength(int OldL, int NewL) {
T *temp = new T[NewL];
int Number = min(OldL, NewL);
copy(element, element + Number, temp);//将数组成员赋值到新数组中去
delete[]element;
element = temp;
}
次に、2つの主要な関数earse()とinsert()があります。earse()のアイデアは、インデックスがindexである要素を削除してから、index + 1、index + 2、...、ListSizeの要素を移動することです。 -1左に1位置、最後の要素を解放します。insert()のアイデアは、最初に配列の長さが要件を満たしているかどうかを確認することです。次に、copy_backward()を使用して、インデックスインデックスを持つ要素を右のListSize-1に移動し、インデックスインデックスを持つ要素を挿入します。
template<class T>
void ArrayList<T>::earse(int Index) {
CheckIndex(Index);
copy(element + Index + 1, element + ListSize, element + Index);
element[--ListSize].~T();
}
template<class T>
void ArrayList<T>::insert(int Index, const T &Element) {
CheckIndex(Index);
if (ListSize == ArrayLength) {
ChangeLength(ArrayLength, ArrayLength + 1);
}
copy_backward(element + Index, element + ListSize, element + ListSize + 1);//第三个参数是目的序列的结束迭代器
element[Index] = Element;
}
最後に、他の関数の準備なので、説明はせず、コードを直接追加します。
template<class T>
void ArrayList<T>::CheckIndex(int index)const
{
if (index < 0 || index >= ListSize) {
throw illegalIndexValue();
}
}
template<class T>
bool ArrayList<T>::empty()const {
return ListSize == 0;
}
template<class T>
int ArrayList<T>::size()const {
return ListSize;
}
template<class T>
T &ArrayList<T>::Getelement(int Index) {
CheckIndex(Index);
return element[Index];
}
template<class T>
int ArrayList<T>::ElementPos(const T &Element) {
int Index = (int)(find(element, element + ListSize, Element) - element);
if (Index == ListSize)
return -1;
else
return Index;
}
template<class T>
int ArrayList<T>::Getcapacity()const {
return ArrayLength;
}
template<class T>
void ArrayList<T>::ouput(ostream &out)const {
copy(element, element + ListSize, ostream_iterator<T>(cout, " "));
}
template<class T>
ostream &operator<<(ostream &out, const ArrayList<T>&x) {
x.ouput(out);
return out;
}