顺序表在前边已经实现过很多次了,在这里就不多做介绍了,本文主要讲解如果利用模板类的方式实现顺序表和一个顺序从另一个顺序表拷贝内容时的一些注意事项。
PS:本文统一采用的是利用for循环一个一个赋值的形式。
直接来看代码:
头文件和函数声明 Vector.h 部分
#include <iostream>
using namespace std;
#include <assert.h>
template <class T>
class Vector
{
public:
Vector()//构造
: _start(0)
, _finish(0)
, _endOfStorage(0)
{}
Vector(const T* array, size_t size)//带参数构造
: _start(new T[size])
, _finish(_start + size)
, _endOfStorage(_start+size)
{
assert(NULL != array);
//memcpy(_start, array, size*sizeof(T));//效率高,易出错
for (size_t i = 0; i < size; ++i)//效率低,不易出错
{
_start[i] = array[i];
}
}
Vector(const Vector& v);//拷贝构造
Vector<T>& operator=(const Vector<T>& s);//重载=
~Vector()//析构
{
if (_start)
{
delete[] _start;
_start = _finish = _endOfStorage = NULL;
}
}
void PushBack(const T& data);//后插
void PopBack();//后删
void Insert(size_t pos, const T& data);//任意位置插
void Erase(size_t pos);//任意位置删
size_t Size()const;//求大小
size_t Capacity()const;//求容量
bool Empty()const;//判空
void Resize(size_t newSize, const T& data = T());//改变个数
T& operator[](size_t index);//实现下标访问
const T& operator[](size_t index)const;//
T& Front();//返回第一个元素
const T& Front()const;//
T& Back();//返回最后一个元素
const T& Back()const;//
void Clear();//清空
void Display();//打印
private:
void _CheckCapacity();//检查容量,不够则增容
private:
T* _start;
T* _finish;
T* _endOfStorage;
};
函数具体实现和函数测试 Test.cpp部分
#include "Vector.h"
template <class T>
Vector<T>::Vector(const Vector& v)
{
//开辟空间,将_start指向新空间,拷贝v的内容,
size_t size = v.Size();
T* tmp = new T[size];
_start = tmp;
_finish = _start + size;
_endOfStorage = _start + size;
for (size_t i = 0; i < size; ++i)
{
_start[i] = v._start[i];
}
}
template <class T>
Vector<T>& Vector<T>::operator=(const Vector& s)
{
if (this != &s)
{
//开辟新空间,拷贝s的内容,释放旧空间,更新类成员指针
size_t size = s.Size();
size_t capacity = s.Capacity();
T* tmp = new T[capacity];
for (size_t i = 0; i < size; ++i)
{
tmp[i] = s._start[i];
}
delete[] _start;
_start = tmp;
_finish = _start+size;
_endOfStorage = _start + capacity;
}
return *this;
}
template <class T>
void Vector<T>::PushBack(const T& data)
{
//插入前判断容量,不够则先增容,再插入
_CheckCapacity();
*_finish = data;
_finish++;
}
template <class T>
void Vector<T>::PopBack()
{
//顺序表存在且顺序表不为为空时才删
if (NULL != _start&&_start != _finish)
{
_finish--;
}
}
template <class T>
void Vector<T>::Insert(size_t pos, const T& data)
{
//判断容量,插入点是否合理,再插入
_CheckCapacity();
size_t oldsize = Size();
size_t oldcapacity = Capacity();
if (pos <= oldsize)
{
//插入点及后边元素往后依次挪一下,空出一个位置,插入元素
for (size_t i = oldsize; i>pos; --i)
{
_start[i] = _start[i - 1];
}
_start[pos] = data;
_finish++;
}
}
template <class T>
void Vector<T>::Erase(size_t pos)
{
//删除点后边的元素依次往前挪,进行覆盖
size_t size = Size();
if (pos < size)
{
for (size_t i = pos; i < size - 1; ++i)
{
_start[i] = _start[i + 1];
}
_finish--;
}
}
template <class T>
size_t Vector<T>::Size()const
{
return _finish - _start;
}
template <class T>
size_t Vector<T>::Capacity()const
{
return _endOfStorage - _start;
}
template <class T>
bool Vector<T>::Empty()const
{
if (_start == _finish)
{
return true;
}
else
{
return false;
}
}
template <class T>
void Vector<T>::Resize(size_t newSize, const T& data = T())
{
size_t oldsize = Size();
size_t oldcapacity = Capacity();
//分三种情况
//变小或不变
if (newSize <= oldsize)
{
_finish = _start + newSize;
}
//变大但不超过总容量
else if ((newSize > oldsize) && (newSize <= oldcapacity))
{
_finish = _start + newSize;
for (size_t i = oldsize; i < newSize; ++i)
{
_start[i] = data;
}
}
//超过总容量,先增容,再填充
else if (newSize > oldcapacity)
{
T* tmp = new T[newSize];
for (size_t i = 0; i < oldsize; ++i)
{
tmp[i] = _start[i];
}
for (size_t i = oldsize; i < newSize; ++i)
{
tmp[i] = data;
}
delete[] _start;
_start = tmp;
_finish = _start + newSize;
_endOfStorage = _start + newSize;
}
}
template <class T>
T& Vector<T>::operator[](size_t index)
{
assert(NULL != _start);
return *(_start + index);
}
template <class T>
const T& Vector<T>::operator[](size_t index)const
{
arrert(NULL != _start);
return *(_start + index);
}
template <class T>
T& Vector<T>::Front()
{
assert(NULL != _start);
return *_start;
}
template <class T>
const T& Vector<T>::Front()const
{
assert(NULL != _start);
return *_start;
}
template <class T>
T& Vector<T>::Back()
{
assert(NULL != _start);
return *(_finish - 1);
}
template <class T>
const T& Vector<T>::Back()const
{
assert(NULL != _start);
return *(_finish - 1);
}
template <class T>
void Vector<T>::Clear()
{
_finish = _start;
}
template <class T>
void Vector<T>::_CheckCapacity()
{
//判断是否达最大容量,若已达则增容
size_t size = Size();
int oldcapacity = Capacity();
int newcapacity = oldcapacity ? oldcapacity * 2 : 3;
//若已达,开辟足够大新空间,拷贝旧空间内容,释放旧空间
if (_finish == _endOfStorage)
{
T* tmp = new T[newcapacity];
for (size_t i = 0; i < size; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = _start + size;
_endOfStorage = _start + newcapacity;
}
}
template <class T>
void Vector<T>::Display()
{
//只要不为空顺序表,将元素逐个输出
if (NULL != _start)
{
size_t size = Size();
size_t capacity = Capacity();
for (size_t i = 0; i < size; ++i)
{
cout << _start[i] << ' ';
}
cout << endl;
cout << "size = " << size << endl;
cout << "capacity = " << capacity << endl;
cout << endl;
}
}
void FunTest1()
{
int arr[] = { 1, 2, 3, 4, 5, 6 };
int sz = sizeof(arr) / sizeof(arr[0]);
Vector<int> v1(arr,sz);//带参数构造
v1.Display();//打印
Vector<int> v2(v1);//拷贝构造
v2.Display();
v2.PushBack(7);//后插
v2.Display();
v1 = v2;//赋值运算符重载
v1.Display();
v2.Resize(9, 8);
v2.Display();
v2.Resize(14, 8);
v2.Display();
v2.Resize(3, 8);
v2.Display();
}
void FunTest2()
{
Vector<int> v3;//普通构造
v3.PushBack(1);//后插
v3.PushBack(2);
v3.PushBack(3);
v3.PushBack(4);
v3.Display();
v3.PopBack();//后删
v3.Display();
v3.Insert(0, 0);//任意位置插
v3.Insert(4, 5);
v3.Insert(5, 6);
v3.Insert(6, 7);
v3.Display();
v3.Erase(6);//任意位置删
v3.Erase(0);
v3.Display();
}
void FunTest3()
{
int arr[] = { 1,2,3,4,5};
size_t sz = sizeof(arr) / sizeof(arr[0]);
Vector<int> v4(arr, sz);
v4.Display();
int data = 0;
data= v4[2];//下标访问
cout << "v4[2]=" << data<<endl;
data = v4.Front();
cout << "first element is :" << data<<endl;
data = v4.Back();
cout << "last element is :" << data << endl;
v4.Clear();//清空
cout << "cleard" << endl;
data = v4.Empty();//判空
if (data)
{
cout << "Is empty" << endl;
}
else
{
cout << "Not empty" << endl;
}
}
int main()
{
FunTest1();
//FunTest2();
//FunTest3();
while (1);
return 0;
}
三个测试函数的运行结果如下:
现在来看看一个顺序从另一个顺序表拷贝内容时的注意事项。
在本文中,CheckCapacity()这个函数用的比较多,我就以这个函数为例来讲解一下
template <class T>
void Vector<T>::_CheckCapacity()
{
//判断是否达最大容量,若已达则增容
size_t size = Size();
int oldcapacity = Capacity();
int newcapacity = oldcapacity ? oldcapacity * 2 : 3;
//若已达,开辟足够大新空间,拷贝旧空间内容,释放旧空间
if (_finish == _endOfStorage)
{
T* tmp = new T[newcapacity];
//memcpy(tmp,_start,size*sizeof(T));
for (size_t i = 0; i < size; ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
_start = tmp;
_finish = _start + size;
_endOfStorage = _start + newcapacity;
}
}
首先来对比一下两种方法的实现方式及其对比
上边说了用 memcpy( )函数实现容易出错,那么它在哪种情况下会出错呢?当元素不是整型,而是字符串或者其他存放的不是内容本身而是内容的地址的情况。
分析一下:
那么用 for 循环 为什么不会发生这种错误呢?因为for循环是采用一个一个赋值的方式,而我们已经对赋值运算符进行了重载,赋值的过程中,新旧空间的元素都有自己的空间,不会指向同一块空间。也就是深拷贝的方式。
PS:欢迎提出宝贵建议哦~