一个线性表(linearList)可以用一个抽象数据类型(ADT)来说明。
抽象数据类型linearList{
实例
有限个元素的有序集合
操作
empty():若表空,返回true
size():返回表中元素的个数
get(index):返回线性表中索引为index的元素
indexOf(x):返回线性表中第一次出现的x的索引。若x不存在,则返回-1
erase(index):删除表中索引为index的元素 索引大于index的元素其索引-1
insert(index,x):把x插入线性表中索引为index的位置,索引大于等于index的元素其索引加1
output():从左到右输出表元素
}
用C++的抽象类来表示linearList:
//========================线性表的抽象描述========================
template
class myLinearList {
public:
virtual ~myLinearList(){ }
virtual bool empty()const = 0;//是否为空线性表
virtual size_t get_size()const = 0;//返回线性表的元素个数
virtual T get_element(size_t index)const = 0;//返回索引处的元素值
virtual size_t index_of(const T& element)const = 0;//返回该元素第一次出现的索引
virtual void insert(const T&,size_t index) = 0;//在指定索引处位置插入元素
virtual void erase(size_t index) = 0;//删除指定索引位置的元素
virtual void output(std::ostream& os=cout) const= 0;//遍历输出线性表
};
此章我们用数组描述(array representation)来表示线性表,用数组/vector来存储线性表的元素。所有元素存储在连续的内存区域中。
用线性表的数组表示:
#include
#include
#include
#include
#include
#include
using std::cout; using std::cerr; using std::cin; using std::ends; using std::endl;
using std::string;
using std::vector;
//========================自定义的参数异常类==========================
class illegalParameterValue {
public:
illegalParameterValue() :message("Illegal parameter value!"){ }
illegalParameterValue(const string& _message):message(_message){ }
string what() const{ return message; }
void output()const { cout << message << endl; }
private:
string message;
};
//========================数组线性表的复制、变长时用到的工具模板函数========================
template <typename T>
void change_array_length1D(T*& a,size_t oldLength,size_t newLength) {
if (newLength < 0) throw illegalParameterValue("new length must be >=0");
T* new_arr = new T[newLength];
size_t new_size = std::min(oldLength, newLength);
for (size_t i = 0; i < new_size; ++i) {//拷贝数据
new_arr[i] = a[i];
}
//std::copy(a, a + new_size,new_arr);//使用STL::copy来拷贝数据
delete[] a;//释放原内存
a = new_arr;//更新指针
}
//========================自实现类arrayList的双向迭代器========================
//五类迭代器,所有迭代器都支持==、!=和解引用*
//输入迭代器:只读 不写(*解引用只会出现在赋值运算符=的右侧) 单遍扫描 只能递增
//输出迭代器:只写 不读(*解引用只会出现在赋值运算符=的左侧) 单遍扫描 只能递增(向一个已经解引用的输出迭代器赋值,就是将值写入它所指向的元素)
//前向迭代器:可读写 多遍扫描 只能递增
//双向迭代器:可读写 多遍扫描 可递增递减
//随机迭代器:可读写 多遍扫描 支持全部迭代器运算
//符合STL及泛型标准的各类型迭代器实现应该继承自std::iterator接口:https://zh.cppreference.com/w/cpp/iterator/iterator
//自实现类arrayList的简易迭代器
template <typename T>
class my_iterator {
public:
//公有成员
typedef std::bidirectional_iterator_tag iterator_category;//迭代器类型标签
typedef T value_type;//值类型
typedef std::ptrdiff_t difference_type;//标识迭代器之间的距离 C++17 弃用
typedef T* pointer;//指向被迭代的类型(T)的指针
typedef T& reference;//被迭代类型(T)的引用
//构造函数
my_iterator(T* _ptr = 0) :position(_ptr) { }
//解引用操作
T operator*() const { return *position; }
T* operator->() const { return &(*position); }
//递增递减
my_iterator& operator++() { ++position; return *this; }
my_iterator& operator--() { --position; return *this; }
my_iterator operator++(int) { my_iterator ret = *this; ++(*this); return ret; }
my_iterator operator--(int) { my_iterator ret = *this; --(*this); return ret; }
//相等
bool operator==(const my_iterator& rhs)const { return position == rhs.position; }
bool operator!=(const my_iterator& rhs)const { return position != rhs.position; }
protected:
T* position;//指向元素的指针
};
//========================线性表的抽象描述========================
template <typename T>
class myLinearList {
public:
myLinearList() = default;
virtual ~myLinearList(){ }
virtual bool empty()const = 0;//是否为空线性表
virtual size_t get_size()const = 0;//返回线性表的元素个数
virtual size_t get_capacity()const = 0;//返回线性表当前的容器长度
virtual T get_element(size_t index)const = 0;//返回索引处的元素值
virtual size_t index_of(const T& element)const = 0;//返回该元素第一次出现的索引
virtual void insert(const T&,size_t index) = 0;//在指定索引处位置插入元素
virtual void erase(size_t index) = 0;//删除指定索引位置的元素
virtual void output(std::ostream& os=cout) const= 0;//遍历输出线性表
};
//========================数组描述的线性表========================
//.h
template <typename T>
class myArrayList :public myLinearList<T> {
public:
myArrayList(size_t _capacity = 10);//默认容器容量为10
myArrayList(const myArrayList& mal);//拷贝构造函数
myArrayList(myArrayList&& mal);//移动构造函数
~myArrayList() { delete[] arr; }
bool empty()const { return size == 0; }
size_t get_size()const { return size; }
size_t get_capacity()const { return capacity; }
T get_element(size_t index)const;
size_t index_of(const T& element)const;
void insert(const T& element, size_t index);
void erase(size_t index);
void output(std::ostream& os = cout)const;
void resize(size_t newsize);
void set(size_t _index,const T& _element);
void clear();
my_iterator<T> begin()const { return my_iterator<T>(arr); }
my_iterator<T> end()const { return my_iterator<T>(arr + size); }
protected:
T* arr;//存储元素的一维数组
size_t size;//数组元素的数目
size_t capacity;//数组的容量
void check_index(size_t index) const;//arrayList检查索引的私有工具函数
};
//.cpp
template <typename T>
myArrayList<T>::myArrayList(size_t _capacity) {
if (_capacity < 1) {//初始容量必须大于等于1
std::ostringstream oss;
oss << "Initial capacity of array list must be > 0";
throw illegalParameterValue(oss.str());
}
capacity = _capacity;
arr = new T[capacity];
size = 0;
}
template <typename T>
myArrayList<T>::myArrayList(const myArrayList& mal) {
size = mal.size;
capacity = mal.capacity;
arr = new T[capacity];
for (size_t i = 0; i < size; ++i) {
arr[i] = mal.arr[i];
}
//std::copy(mal.arr,mal.arr+size,arr);//利用std::来拷贝
return *this;
}
template <typename T>
myArrayList<T>::myArrayList(myArrayList&& mal):size(mal.size),capacity(mal.capacity),arr(mal.arr) {//移动构造函数
//直接接管资源 并将被移动对象置为可析构状态
mal.size = mal.capacity = 0;
mal.arr = nullptr;
}
template <typename T>
void myArrayList<T>::output(std::ostream& os) const {
if (size > 0)
std::copy(arr, arr + size, std::ostream_iterator<T>(os, " "));//ostream_iterator 一般搭配泛型算法使用
else cout << "empty array list!" << endl;;
}
template<typename T>
std::ostream& operator<<(std::ostream& os, const myArrayList<T>& mal) {
mal.output(os);
return os;
}
template <typename T>
void myArrayList<T>::check_index(size_t index) const {
if (index < 0 || index >= size) {
std::ostringstream oss;
oss << "index must be >=0 and << index << "is illegal" << endl;
throw illegalParameterValue(oss.str());
}
}
template <typename T>
T myArrayList<T>::get_element(size_t index) const {
check_index(index);
return arr[index];
}
template <typename T>
size_t myArrayList<T>::index_of(const T& element) const {
size_t pos;
pos = std::find(arr, arr + size, element) - arr;//利用std::find查找
if (pos == size)
return -1;
return pos;
}
template <typename T>
void myArrayList<T>::erase(size_t index) {
check_index(index);
//std::copy(arr+index+1,arr+size,arr+index);//利用std::copy拷贝
for (size_t i = index + 1; i < size; ++i) {
arr[i - 1] = arr[i];
}
arr[--size].~T();//调用析构函数对最后尾元素析构
}
template <typename T>
void myArrayList<T>::insert(const T& element, size_t index) {
if (index < 0 || index > size) {
std::ostringstream oss;
oss << "insert index must be >=0 and <=size, while" << index << "is illegal" << endl;
throw illegalParameterValue(oss.str());
}
if (size == capacity) {//容器已满
change_array_length1D(arr, capacity, 2 * capacity);
capacity *= 2;
}
//元素右移一个单位
size_t i;
for (i = size; i > index; --i) {
arr[i] = arr[i - 1];
}
//std::copy_backward(arr+index,arr+size,arr+size+1);//利用std::backward把元素右移一个单位,可能的实现见后面
arr[i] = element;
++size;
}
template <typename T>
void myArrayList<T>::resize(size_t newsize) {
if (newsize < 0) throw illegalParameterValue("new size must be >=0!");
if (newsize < size) {//小于当前size则进行缩减
while (size > newsize) {
arr[--size].~T();
}
}
else if (newsize<=capacity) {
while (size < newsize) {
arr[size++] = T();//以T默认构造函数填充
}
}
else{//需要分配新空间
change_array_length1D(arr, capacity, 2 * newsize);//得到新的大空间的数组
while (size < newsize) {
arr[size++] = T();
}
capacity = 2*newsize;
}
}
template <typename T>
void myArrayList<T>::set(size_t _index,const T& _element) {
check_index(_index);
arr[_index] = _element;
}
template <typename T>
void myArrayList<T>::clear() {
while (size>0) {
arr[--size].~T();
}
}
//========================std::copy_backward可能的实现========================
//std::copy_backward(start,end,dest)
//复制[start,end)的元素到终于dest的位置即[dest-(end-start),dest) 逆序拷贝(首先拷贝end-1的元素到dest-1)
template <typename BidirIter1,typename BidirIter2>//双向迭代器Bidirectional iterator
BidirIter2 my_copy_backward(BidirIter1 begin,BidirIter1 end,BidirIter2 dest_end) {
while (end!=begin) {
*(--dest_end) = *(--end);
}
return dest_end;
}
//test
int main() {
//test for i/ostream_iter
//std::istringstream str("0.05");
//std::istream_iterator initer(str);//可以在输入流中将string转为double 等价于std::atoi(str);
//cout << *initer + *initer << endl;
//test for my_copy_backward
//vector vec{ 0,1,2,3,4,5,6,7,8,9};
//for (const auto& i : vec) cout << i << ends;
//cout << endl;
std::copy_backward(vec.begin(),vec.begin()+4,vec.begin()+10);
//my_copy_backward(vec.begin(),vec.begin()+4,vec.begin()+10);
//for (const auto& i : vec) cout << i << ends;
//test for my_iterator
//int num []{ 0,1,2,3,4,5,6,7,8,9 };
//my_iterator myIter(num);
//my_iterator myEndIter(num+10);
//for (; myIter != myEndIter;++myIter) {//++和!=操作
// cout << *myIter << ends;//*操作
//}
//test for myArraList
myArrayList<int> mylist;
cout << "capacity:" << mylist.get_capacity() << ends << "size:" << mylist.get_size() << endl;
if(mylist.empty())
mylist.output();
mylist.insert(20,0);
mylist.insert(21,1);
mylist.insert(22,2);
mylist.insert(23,3);
if (!mylist.empty())
cout << mylist;
cout << endl;
cout << "element at index 3:"<<mylist.get_element(3) << endl;
mylist.erase(mylist.index_of(22));
cout << "erased 22" << endl;
cout << "now 23 is at index:" << mylist.index_of(23) << endl;
if (mylist.index_of(22) == -1) cout << "22 is not in the array list !" << endl;
for (my_iterator<int> myIter = mylist.begin();myIter!=mylist.end(); ++myIter) {
cout << *myIter << ends;
}
return 0;
}
基于vector的线性表描述,与数组描述相差无几:
//========================基于vector的线性表描述myVectorList========================
//.h
template <typename T>
class myVectorList :public myLinearList<T> {
public:
myVectorList(size_t _capacity = 10);
myVectorList(const myVectorList& mvl);
~myVectorList() { delete v_ptr; }
bool empty()const { return v_ptr->empty(); }
size_t get_size()const { return v_ptr->size(); }
size_t get_capacity()const { return v_ptr->capacity(); }
T get_element(size_t index)const;
size_t index_of(const T& element)const;
void insert(const T& element,size_t index);
void erase(size_t index);
void output(std::ostream& os=cout)const;
typename vector<T>::iterator begin()const { return v_ptr->begin(); }
typename vector<T>::iterator end()const { return v_ptr->end(); }
protected:
void check_index(size_t index) const;
vector<T>* v_ptr;//存储线性表元素的向量
};
//.cpp
template <typename T>
myVectorList<T>::myVectorList(size_t _capacity){
if (_capacity < 1) {
std::ostringstream oss;
oss << "initial capacity must be >=1, while given is: " << _capacity;
throw illegalParameterValue(oss.str());
}
v_ptr = new vector<T>(_capacity);
}
template <typename T>
myVectorList<T>::myVectorList(const myVectorList& mvl):v_ptr(new vector<T>(*mvl.v_ptr)) {
}
template <typename T>
void myVectorList<T>::check_index(size_t index) const {
if (index >= v_ptr->size() || index < 0) {
std::ostringstream oss;
oss << "index must be >=0 and << index << "is illegal" << endl;
throw illegalParameterValue(oss.str());
}
}
template <typename T>
T myVectorList<T>::get_element(size_t index)const {
check_index(index);
return v_ptr->at(index);
}
template <typename T>
size_t myVectorList<T>::index_of(const T& element)const {
size_t pos = std::find(v_ptr->begin(),v_ptr->end(),element) - v_ptr->begin();
if (pos == v_ptr->size()) return -1;
return pos;
}
template <typename T>
void myVectorList<T>::erase(size_t index) {
check_index(index);
v_ptr->erase(v_ptr->begin()+index);//vector::erase(vector::iterator)
}
template <typename T>
void myVectorList<T>::insert(const T& element,size_t index) {
if (index > v_ptr->size() || index < 0) {
std::ostringstream oss;
oss << "index must be >=0 and <=size, while" << index << "is illegal" << endl;
throw illegalParameterValue(oss.str());
}
v_ptr->insert(v_ptr->begin()+index,element);//vector::insert(itertor,value)
}
template <typename T>
void myVectorList<T>::output(std::ostream& os) const{
if (v_ptr->size() > 0) {
std::copy(v_ptr->begin(),v_ptr->end(),std::ostream_iterator<T>(os," "));
}
else *std::ostream_iterator<string>(os) = "empty vector list!";
}
template <typename T>
std::ostream& operator<<(std::ostream& os,const myVectorList<T>& mvl) {
mvl.output(os);
return os;
}
//test
int main() {
myVectorList<int> mylist;
cout << "capacity:" << mylist.get_capacity() << ends << "size:" << mylist.get_size() << endl;
if (mylist.empty())
mylist.output();
mylist.insert(20, 0);
mylist.insert(21, 1);
mylist.insert(22, 2);
mylist.insert(23, 3);
if (!mylist.empty())
cout << mylist;
cout << endl;
cout << "element at index 3:" << mylist.get_element(3) << endl;
mylist.erase(mylist.index_of(22));
cout << "erased 22" << endl;
cout << "now 23 is at index:" << mylist.index_of(23) << endl;
if (mylist.index_of(22) == -1) cout << "22 is not in the array list !" << endl;
for (auto myIter = mylist.begin(); myIter != mylist.end(); ++myIter) {
cout << *myIter << ends;
}
return 0;
}