大作业vector:
1、完成vector数据结构的基本功能
2、内嵌类iterator
和const_iterator
(iterator
是可以访问和修改的迭代器,const_iterator
是只可访问,不可修改)
3、对于某些变量类型,并没有默认的构造函数。请尝试用指针存储。(意思是你在开空间的时候不要同时构造!!!)
代码如下:
version 1:使用了malloc和free
#ifndef SJTU_VECTOR_HPP
#define SJTU_VECTOR_HPP
#include "exceptions.hpp"
#include <climits>
#include <cstddef>
namespace sjtu {
// a data container like std::vector
// store data in a successive memory and support random access.
template<typename T>
class vector {
private:
T *data;
int len;
size_t cpct;
public:
class iterator;
class const_iterator;
class const_iterator {
friend class iterator;
friend class vector;
private:
const vector *vecname;
int idx;
public:
const_iterator(vector *vecn,int index){
vecname = vecn;
idx = index;
}
const_iterator(const vector *vecn,int index){
vecname = vecn;
idx = index;
}
const_iterator operator+(const int &n) const {
const_iterator tmp(vecname,idx+n);
return tmp;
}
const_iterator operator-(const int &n) const {
const_iterator tmp(vecname,idx-n);
return tmp;
}
// return the distance between two iterators,
// if these two iterators point to different vectors, throw invalid_iterator.
int operator-(const iterator &rhs) const {
if(vecname != rhs.vecname ) throw invalid_iterator();
if(idx > rhs.idx ) return idx-rhs.idx ;
else return rhs.idx-idx;
}
T operator*() const{
return vecname->data[idx];
}
const_iterator operator++(int) {//iter++
iterator tmp(vecname,idx);
idx++;
return tmp;
}
const_iterator& operator++() {// ++iter
idx++;
return *this;
}
const_iterator operator--(int) {// iter--
iterator tmp(vecname,idx);
idx--;
return tmp;
}
const_iterator& operator--() {//--iter
idx--;
return *this;
}
// a operator to check whether two iterators are same
//(pointing to the same memory address).
bool operator==(const iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator==(const const_iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator!=(const iterator &rhs) const {// some other operator for iterator.
return !(*this == rhs);
}
bool operator!=(const const_iterator &rhs) const {
return !(*this == rhs);
}
};
class iterator {
friend class const_iterator;
friend class vector;
private:
vector<T> *vecname;
int idx;
public:
iterator(vector<T> *vecn,int index){
vecname = vecn;
idx = index;
}
iterator(const vector<T> *vecn,int index){
vecname = vecn;
idx = index;
}
//return a new iterator which pointer n-next elements
//as well as operator-
iterator operator+(const int &n) const {
iterator tmp(vecname,idx+n);
return tmp;
}
iterator operator-(const int &n) const {
iterator tmp(vecname,idx-n);
return tmp;
}
// return the distance between two iterators,
// if these two iterators point to different vectors, throw invalid_iterator.
int operator-(const iterator &rhs) const {
if(vecname != rhs.vecname ) throw invalid_iterator();
if(idx > rhs.idx ) return idx-rhs.idx ;
else return rhs.idx-idx;
}
iterator& operator+=(const int &n) {
idx += n;
return *this;
}
iterator& operator-=(const int &n) {
idx -= n;
return *this;
}
iterator operator++(int) {//iter++
iterator tmp(vecname,idx);
idx++;
return tmp;
}
iterator& operator++() {// ++iter
idx++;
return *this;
}
iterator operator--(int) {// iter--
iterator tmp(vecname,idx);
idx--;
return tmp;
}
iterator& operator--() {//--iter
idx--;
return *this;
}
T& operator*() const{//*it 0-base的吧
return *((vecname->data)+idx);
}
// a operator to check whether two iterators are same
//(pointing to the same memory address).
bool operator==(const iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator==(const const_iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator!=(const iterator &rhs) const {// some other operator for iterator.
return !(*this == rhs);
}
bool operator!=(const const_iterator &rhs) const {
return !(*this == rhs);
}
};
//TODO Constructs
// Atleast two: default constructor, copy constructor
vector() {
len = 0;
data = NULL;
cpct = 0;
}
vector(const vector &other) {
len = other.len;
cpct = other.cpct;
data = (T*) malloc(sizeof(T)*cpct);//分配空间,多搞点……??
for(int i=0;i<len;i++){
new(data+i)T(other.data[i]); //存进去数据
}
}
~vector() {// TODO Destructor
for(int i=0;i<len;i++)
data[i].~T();
free(data);
len = 0;
data = NULL;
cpct = 0;
}
void doublespace(){
if(cpct == 0){
data = (T*) malloc(sizeof(T));
cpct = 1;
return ;
}
cpct *= 2;
T* data2 = (T*) malloc(sizeof(T)*cpct);
for(int i=0;i<len;i++)
new(data2+i)T(data[i]);
for(int i=0;i<len;i++)
data[i].~T();
// operator delete(data,sizeof(T)*(cpct/2));
free(data);
data = data2;
}
vector &operator=(const vector &other) {// TODO Assignment operator赋值运算符
if(this == &other) return *this;//return 自己
if(cpct < other.cpct) {
for(int i=0;i<len;i++)//记得删除的时候~T()
data[i].~T();
// operator delete(data,sizeof(T)*cpct);
free(data);
cpct = other.cpct;
len = other.len;
data = (T*) malloc(sizeof(T)*cpct);
for(int i=0;i<len;i++)
new(data+i)T(other.data[i]);
}
else{//完了呀这里写的有问题呀!!已经改好了……
for(int i=0;i<other.len;i++)
data[i].~T();
for(int i=0;i<other.len;i++)
new(data+i)T(other.data[i]);
for(int i=other.len;i<len;i++)
data[i].~T();
len = other.len;
}
return *this;
}
//assigns specified element with bounds checking
// throw index_out_of_bound if pos is not in [0, size)
T & at(const size_t &pos) {//size_t是一个变量类型,和int型大小一样,一般会用 size_t size = sizeof(a);//a是int型变量
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
const T & at(const size_t &pos) const {
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
// assigns specified element with bounds checking
// throw index_out_of_bound if pos is not in [0, size)
// !!! Pay attentions
// In STL this operator does not check the boundary but I want you to do.
T & operator[](const size_t &pos) {
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
const T & operator[](const size_t &pos) const {
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
// access the first element. throw container_is_empty if size == 0
const T & front() const {
if(len==0) throw container_is_empty();
else return *(this->data);
}
//access the last element. throw container_is_empty if size == 0
const T & back() const {
if(len==0) throw container_is_empty();
else return *(this->data+len-1);
}
//returns an iterator to the beginning.
iterator begin() {
iterator tmp(this,0);//要不要throw?
return tmp;
}
const_iterator cbegin()const{
const_iterator tmp(this,0);
return tmp;
}
// returns an iterator to the end.
iterator end() {
iterator tmp(this,len);
return tmp;
}
const_iterator cend() const {
const_iterator tmp(this,len);
return tmp;
}
// checks whether the container is empty
bool empty() const {
if(size) return false;
else return true;
}
// returns the number of elements
size_t size() const {
size_t siz = len;
return siz;
}
// clears the contents
void clear() {
for(int i=0;i<len;i++)
data[i].~T();//删掉内容而已,没让你清空内存啊
len = 0;
}
// inserts value before pos
// returns an iterator pointing to the inserted value.
iterator insert(iterator pos, const T &value) {
if(pos.vecname->len+1 > pos.vecname->cpct) pos.vecname->doublespace();
for(int i=pos.vecname->len;i>=pos.idx;i--)
new(pos.vecname->data+i+1)T(pos.vecname->data[i]);
new(data+pos.idx)T(value);
pos.vecname->len ++;
iterator tmp(pos.vecname,pos.idx);
return tmp;
}
// inserts value at index ind.
// after inserting, this->at(ind) == value
// returns an iterator pointing to the inserted value.
// throw index_out_of_bound if ind > size (in this situation ind can be size because after inserting the size will increase 1.)
iterator insert(const size_t &ind, const T &value) {
if(ind > len) throw index_out_of_bound();
if(len+1 > cpct) doublespace();
for(int i=len;i>=ind;i--)
new(data+i+1)T(data[i]);
new(data+ind)T(value);
len ++;
iterator tmp(this,ind);
return tmp;
}
// removes the element at pos.
// return an iterator pointing to the following element.
// If the iterator pos refers the last element, the end() iterator is returned.
iterator erase(iterator pos) {
for(int i=pos.idx;i<pos.vecname->len-1;i++)
new(pos.vecname->data+i)T(pos.vecname->data[i+1]);
pos.vecname->data[pos.vecname->len-1].~T();
pos.vecname->len --;
if(pos.vecname->len == pos.idx) return pos.vecname->end();
iterator tmp(pos.vecname,pos.idx);
return tmp;
}
/**
* removes the element with index ind.
* return an iterator pointing to the following element.
* throw index_out_of_bound if ind >= size
*/
iterator erase(const size_t &ind) {
if(ind >= len) throw index_out_of_bound();
for(int i=ind;i<len-1;i++)
new(data+i)T(data[i+1]);
data[len-1].~T();
len--;
if(len == ind) return this->end();
iterator tmp(this,ind);
return tmp;
}
/**
* adds an element to the end.
*/
void push_back(const T &value) {
if(len+1 > cpct) this->doublespace();
new(data+len)T(value);
len++;
}
/**
* remove the last element from the end.
* throw container_is_empty if size() == 0
*/
void pop_back() {
if(len==0) throw container_is_empty();
data[len-1].~T();
len--;
}
};
}
#endif
version 2:使用了operator new和operator delete
#ifndef SJTU_VECTOR_HPP
#define SJTU_VECTOR_HPP
#include "exceptions.hpp"
#include <climits>
#include <cstddef>
namespace sjtu {
// a data container like std::vector
// store data in a successive memory and support random access.
template<typename T>
class vector {
private:
T *data;
int len;
size_t cpct;
public:
class iterator;
class const_iterator;
class const_iterator {
friend class iterator;
friend class vector;
private:
const vector *vecname;
int idx;
public:
const_iterator(vector *vecn,int index){
vecname = vecn;
idx = index;
}
const_iterator(const vector *vecn,int index){
vecname = vecn;
idx = index;
}
const_iterator operator+(const int &n) const {
const_iterator tmp(vecname,idx+n);
return tmp;
}
const_iterator operator-(const int &n) const {
const_iterator tmp(vecname,idx-n);
return tmp;
}
// return the distance between two iterators,
// if these two iterators point to different vectors, throw invalid_iterator.
int operator-(const iterator &rhs) const {
if(vecname != rhs.vecname ) throw invalid_iterator();
if(idx > rhs.idx ) return idx-rhs.idx ;
else return rhs.idx-idx;
}
T operator*() const{
return vecname->data[idx];
}
const_iterator operator++(int) {//iter++
iterator tmp(vecname,idx);
idx++;
return tmp;
}
const_iterator& operator++() {// ++iter
idx++;
return *this;
}
const_iterator operator--(int) {// iter--
iterator tmp(vecname,idx);
idx--;
return tmp;
}
const_iterator& operator--() {//--iter
idx--;
return *this;
}
// a operator to check whether two iterators are same
//(pointing to the same memory address).
bool operator==(const iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator==(const const_iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator!=(const iterator &rhs) const {// some other operator for iterator.
return !(*this == rhs);
}
bool operator!=(const const_iterator &rhs) const {
return !(*this == rhs);
}
};
class iterator {
friend class const_iterator;
friend class vector;
private:
vector<T> *vecname;
int idx;
public:
iterator(vector<T> *vecn,int index){
vecname = vecn;
idx = index;
}
iterator(const vector<T> *vecn,int index){
vecname = vecn;
idx = index;
}
//return a new iterator which pointer n-next elements
//as well as operator-
iterator operator+(const int &n) const {
iterator tmp(vecname,idx+n);
return tmp;
}
iterator operator-(const int &n) const {
iterator tmp(vecname,idx-n);
return tmp;
}
// return the distance between two iterators,
// if these two iterators point to different vectors, throw invalid_iterator.
int operator-(const iterator &rhs) const {
if(vecname != rhs.vecname ) throw invalid_iterator();
if(idx > rhs.idx ) return idx-rhs.idx ;
else return rhs.idx-idx;
}
iterator& operator+=(const int &n) {
idx += n;
return *this;
}
iterator& operator-=(const int &n) {
idx -= n;
return *this;
}
iterator operator++(int) {//iter++
iterator tmp(vecname,idx);
idx++;
return tmp;
}
iterator& operator++() {// ++iter
idx++;
return *this;
}
iterator operator--(int) {// iter--
iterator tmp(vecname,idx);
idx--;
return tmp;
}
iterator& operator--() {//--iter
idx--;
return *this;
}
T& operator*() const{//*it 0-base的吧
return *((vecname->data)+idx);
}
// a operator to check whether two iterators are same
//(pointing to the same memory address).
bool operator==(const iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator==(const const_iterator &rhs) const {
if(vecname != rhs.vecname ) return false;
if(idx != rhs.idx ) return false;
return true;
}
bool operator!=(const iterator &rhs) const {// some other operator for iterator.
return !(*this == rhs);
}
bool operator!=(const const_iterator &rhs) const {
return !(*this == rhs);
}
};
//TODO Constructs
// Atleast two: default constructor, copy constructor
vector() {
len = 0;
data = NULL;
cpct = 0;
}
vector(const vector &other) {
len = other.len;
cpct = other.cpct;
data = (T*) malloc(sizeof(T)*cpct);//分配空间,多搞点……??
for(int i=0;i<len;i++){
new(data+i)T(other.data[i]); //存进去数据
}
}
~vector() {// TODO Destructor
for(int i=0;i<len;i++)
data[i].~T();
free(data);
len = 0;
data = NULL;
cpct = 0;
}
void doublespace(){
if(cpct == 0){
data = (T*) malloc(sizeof(T));
cpct = 1;
return ;
}
cpct *= 2;
T* data2 = (T*) malloc(sizeof(T)*cpct);
for(int i=0;i<len;i++)
new(data2+i)T(data[i]);
for(int i=0;i<len;i++)
data[i].~T();
// operator delete(data,sizeof(T)*(cpct/2));
free(data);
data = data2;
}
vector &operator=(const vector &other) {// TODO Assignment operator赋值运算符
if(this == &other) return *this;//return 自己
if(cpct < other.cpct) {
for(int i=0;i<len;i++)//记得删除的时候~T()
data[i].~T();
// operator delete(data,sizeof(T)*cpct);
free(data);
cpct = other.cpct;
len = other.len;
data = (T*) malloc(sizeof(T)*cpct);
for(int i=0;i<len;i++)
new(data+i)T(other.data[i]);
}
else{
for(int i=0;i<other.len;i++)
new(data+i)T(other.data[i]);
for(int i=other.len;i<len;i++)
data[i].~T();
}
return *this;
}
//assigns specified element with bounds checking
// throw index_out_of_bound if pos is not in [0, size)
T & at(const size_t &pos) {//size_t是一个变量类型,和int型大小一样,一般会用 size_t size = sizeof(a);//a是int型变量
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
const T & at(const size_t &pos) const {
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
// assigns specified element with bounds checking
// throw index_out_of_bound if pos is not in [0, size)
// !!! Pay attentions
// In STL this operator does not check the boundary but I want you to do.
T & operator[](const size_t &pos) {
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
const T & operator[](const size_t &pos) const {
if(pos >= len) throw index_out_of_bound();
else return *(this->data+pos);
}
// access the first element. throw container_is_empty if size == 0
const T & front() const {
if(len==0) throw container_is_empty();
else return *(this->data);
}
//access the last element. throw container_is_empty if size == 0
const T & back() const {
if(len==0) throw container_is_empty();
else return *(this->data+len-1);
}
//returns an iterator to the beginning.
iterator begin() {
iterator tmp(this,0);//要不要throw?
return tmp;
}
const_iterator cbegin()const{
const_iterator tmp(this,0);
return tmp;
}
// returns an iterator to the end.
iterator end() {
iterator tmp(this,len);
return tmp;
}
const_iterator cend() const {
const_iterator tmp(this,len);
return tmp;
}
// checks whether the container is empty
bool empty() const {
if(size) return false;
else return true;
}
// returns the number of elements
size_t size() const {
size_t siz = len;
return siz;
}
// clears the contents
void clear() {
for(int i=0;i<len;i++)
data[i].~T();//删掉内容而已,没让你清空内存啊
len = 0;
}
// inserts value before pos
// returns an iterator pointing to the inserted value.
iterator insert(iterator pos, const T &value) {
if(pos.vecname->len+1 > pos.vecname->cpct) pos.vecname->doublespace();
for(int i=pos.vecname->len;i>=pos.idx;i--)
new(pos.vecname->data+i+1)T(pos.vecname->data[i]);
new(data+pos.idx)T(value);
pos.vecname->len ++;
iterator tmp(pos.vecname,pos.idx);
return tmp;
}
// inserts value at index ind.
// after inserting, this->at(ind) == value
// returns an iterator pointing to the inserted value.
// throw index_out_of_bound if ind > size (in this situation ind can be size because after inserting the size will increase 1.)
iterator insert(const size_t &ind, const T &value) {
if(ind > len) throw index_out_of_bound();
if(len+1 > cpct) doublespace();
for(int i=len;i>=ind;i--)
new(data+i+1)T(data[i]);
new(data+ind)T(value);
len ++;
iterator tmp(this,ind);
return tmp;
}
// removes the element at pos.
// return an iterator pointing to the following element.
// If the iterator pos refers the last element, the end() iterator is returned.
iterator erase(iterator pos) {
for(int i=pos.idx;i<pos.vecname->len-1;i++)
new(pos.vecname->data+i)T(pos.vecname->data[i+1]);
pos.vecname->data[pos.vecname->len-1].~T();
pos.vecname->len --;
if(pos.vecname->len == pos.idx) return pos.vecname->end();
iterator tmp(pos.vecname,pos.idx);
return tmp;
}
/**
* removes the element with index ind.
* return an iterator pointing to the following element.
* throw index_out_of_bound if ind >= size
*/
iterator erase(const size_t &ind) {
if(ind >= len) throw index_out_of_bound();
for(int i=ind;i<len-1;i++)
new(data+i)T(data[i+1]);
data[len-1].~T();
len--;
if(len == ind) return this->end();
iterator tmp(this,ind);
return tmp;
}
/**
* adds an element to the end.
*/
void push_back(const T &value) {
if(len+1 > cpct) this->doublespace();
new(data+len)T(value);
len++;
}
/**
* remove the last element from the end.
* throw container_is_empty if size() == 0
*/
void pop_back() {
if(len==0) throw container_is_empty();
data[len-1].~T();
len--;
}
};
}
#endif
tips
- 上述两种开辟空间的方式,均可以解决类型没有默认构造函数的问题。注意,
malloc
和free
配合使用,operator new
和operator delete
配合使用,才能顺利开辟/释放空间。一些具体的语法如下,以doublespace
中间的一段为例:(注释号写在前面的语句行是被代替掉的语句,是正常的new
和delete
的那种语句)
// T *data = new T[capacity];
T* data2 = (T*) malloc(sizeof(T)*capacity);//开辟空间不构造
for(int i=0;i<len;i++)
// data2[i] = data[i];
new(data2+i)T(data[i]);//赋值操作(是构造,用的拷贝构造函数吧)
for(int i=0;i<len;i++)
data[i].~T();//记得这种情况下析构要分步,先析构每一个T型变量
// delete []data;
free(data);//最后释放data数组
// T *data = new T[capacity];
T* data2 = (T*) operator new(sizeof(T)*capacity);//开辟空间不构造
for(int i=0;i<len;i++)
// data2[i] = data[i];
new(data2+i)T(data[i]);//赋值操作(构造,用的拷贝构造函数吧)
for(int i=0;i<len;i++)
data[i].~T();//记得这种情况下析构要分步,先析构每一个T型变量
// delete []data;
operator delete(data,sizeof(T)*capacity);//最后释放data数组
如果operator delete
写出来编译器不认,建议换个编译器。
- 不写
doublespace
的倔强的我已经认输了,因为如果不写就一定会超时,具体案例是给的测试点2跑了40多分钟才跑完,仅仅是220而已(其实也很大了) - 其他超时的原因有:
iterator
和const_iterator
初始化可以尝试初始化列表(可是我不会啊,因为有模板变量,但是也可能是我编译器的问题啦);重载等号的时候,考虑开空间是开成和等号右边的len
一样还是capacity
一样,本题可能需要空间换时间,开成和capacity一样就能过了,否则过不了…… iterator
和const_iterator
的区别还是很大的,按照样例来分析的话,可能const_iterator
指向的是一个const vector
,并且只能访问不能修改(是这样的吗,还有待讨论),所以const_iterator的成员参数必须是一个const vector *
类型的变量,剩下的可以自己定义,否则你不可以用const vector *
去给vector(非const)
赋值。