<C++>STL->vector

vector的介绍

vector的使用文档

  • vector是一个可改变数组大小的序列容器
  • vector和数组一样采取连续的空间存放数据,可以使用方括号访问vector的元素,和数组一样高效。但是vector的大小可以动态增长,而数组不行
  • 实际上vector内部使用一个动态分配的数组存放数据。当插入新元素时,数组会按需重新分配大小为了增加存储空间。其做法是,分配一个新的数组,然后将所有元素移动到这个数组中。这是一个比较耗时间的策略,因此每当插入一个新元素时,vector并不会每次重新分配大小。
  • vector分配策略:vector会分配一些额外的空间用来适应插入元素时的增长,因此实际存储空间比当前元素所占用存储空间要大。不同的库采用不同策略平衡内存使用和重新分配,但无论如何,重新分配只能以对数增长的大小间隔进行,以便在向量末尾插入各个元素可以提供摊销常数时间复杂度
  • 与数组相比,vector会消耗更多的内存换取管理存储和更高效的动态增长的能力
  • 相比于其他动态增长的容器,vector获取元素和尾部插入删除元素更加高效;对于中间某一个元素插入删除时的效率没有其他容器高效,并且迭代器和引用的一致性不如列表和单向列表。

vector的使用

构造函数

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 空初始化:调用默认构造函数,没有元素
  2. 填充构造函数:使用nval初始化vector,每一个元素的值都是val
  3. 范围构造函数:使用[First, Last)中的元素一次初始化vector的每一个元素
  4. 拷贝构造函数:使用已存在的vector初始化新的vector
void test1()
{string str("hello world");vector<int> v1;			//vector是一个类模板,显示模板实例化intvector<int> v2(3, 1);	    //填充构造,3个1初始化v2;vector<char> v3(str.begin(), str.end());//范围构造vector<int> v4(v2);		 //拷贝构造for (auto e : v1){cout << e;   	       //输出为空}cout << endl;for (auto e : v2){cout << e << " ";     //1 1 1}cout << endl;for (auto e : v3){cout << e;		   //hello world} cout << endl;for (auto e : v4){cout << e << " ";    //1 1 1}cout << endl;
}

赋值重载

operator=image-20240116103104495

  1. 功能:将其他vector的内容替换当前vector的值
  2. 参数:相同类型的vector
  3. 返回值:*this

demo:

// vector assignment
#include <iostream>
#include <vector>int main ()
{std::vector<int> foo (3,0);std::vector<int> bar (5,0);bar = foo;foo = std::vector<int>();std::cout << "Size of foo: " << int(foo.size()) << '\n';//Size of foo: 0std::cout << "Size of bar: " << int(bar.size()) << '\n';//Size of bar:  3 return 0;
}

迭代器

string一样,vector是数据连续存储的容器,因此迭代器是指针。

begin/end

beginimage-20240116104257101

  1. 功能:返回容器第一个元素的指针
  2. 参数:迭代器函数的参数为空
  3. 返回值:如果容器是只读的,返回一个只读的迭代器;如果容器可读可写,返回一个可读可写的迭代器。

end外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:返回指向vector最后一个元素的下一个位置的迭代器。
  2. 参数:迭代器函数的参数为空
  3. 如果容器是只读的,返回一个只读的迭代器;如果容器可读可写,返回一个可读可写的迭代器。

demo:

// vector::begin/end
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;for (int i=1; i<=5; i++) myvector.push_back(i);		std::cout << "myvector contains:";for (std::vector<int>::iterator it = myvector.begin() ; it != myvector.end(); ++it)std::cout << ' ' << *it;						//1 2 3 4 5std::cout << '\n';return 0;
}

rbegin/rend

rbeginimage-20240116105141291

  1. 功能:返回指向vector最后一个元素反向迭代器
  2. 参数:反向迭代器函数的参数为空
  3. 返回值:如果容器是只读的,返回一个只读的反向迭代器;如果容器可读可写,返回一个可读可写的反向迭代器。

rendimage-20240116105619515

  1. 功能:返回指向vector第一个元素反向迭代器
  2. 参数:反向迭代器函数的参数为空
  3. 返回值:如果容器是只读的,返回一个只读的反向迭代器;如果容器可读可写,返回一个可读可写的反向迭代器。

demo:

// vector::rbegin/rend
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector (5);  // 5 default-constructed intsstd::vector<int>::reverse_iterator rit = myvector.rbegin();int i=0;for (rit = myvector.rbegin(); rit!= myvector.rend(); ++rit)*rit = ++i;std::cout << "myvector contains:";for (std::vector<int>::iterator it = myvector.begin(); it != myvector.end(); ++it)std::cout << ' ' << *it;		//5  4  3  2  1std::cout << '\n';return 0;
}

容量相关函数

size

sizeimage-20240116105944519

  1. 功能:返回vector有效数据个数
  2. 参数:空
  3. 返回值:类型为size_type,等同于size_t

demo:

// vector::size#include <iostream>#include <vector>int main ()
{std::vector<int> myints;std::cout << "0. size: " << myints.size() << '\n';for (int i=0; i<10; i++) myints.push_back(i);std::cout << "1. size: " << myints.size() << '\n';myints.insert (myints.end(),10,100);std::cout << "2. size: " << myints.size() << '\n';myints.pop_back();std::cout << "3. size: " << myints.size() << '\n';return 0;
}

output:

0. size: 0
1. size: 10
2. size: 20
3. size: 19

resize

resizeimage-20240116112034879

  1. 功能:改变vector的有效元素个数
    • 如果n<size,有效元素为前n个,删除超出的元素(是否会异地缩容取决编译器)
    • 如果n>capacity,先扩容使capacity==n,再用val填充剩下的空间
    • 如果size<n<capacity,直接用val填充capacity-size个空间
  2. 参数:
    • n:更新后vector有效元素个数
    • val:填充值
  3. 返回值:无

demo:

// resizing vector
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;// set some initial content:for (int i=1;i<10;i++) myvector.push_back(i);myvector.resize(5);myvector.resize(8,100);myvector.resize(12);std::cout << "myvector contains:";for (int i=0;i<myvector.size();i++)std::cout << ' ' << myvector[i];std::cout << '\n';return 0;
}

output:

myvector contains: 1 2 3 4 5 100 100 100 0 0 0 0 

capacity

capacityimage-20240116115903209

  1. 功能:返回vector的容量(最大存储有效元素的个数)
  2. 参数:空
  3. 返回值:size_t类型

demo:

// comparing size, capacity and max_size
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;// set some content in the vector:for (int i=0; i<100; i++) myvector.push_back(i);std::cout << "size: " << (int) myvector.size() << '\n';std::cout << "capacity: " << (int) myvector.capacity() << '\n';std::cout << "max_size: " << (int) myvector.max_size() << '\n';return 0;
}

output:

size: 100
capacity: 128
max_size: 1073741823

empty

emptyimage-20240116120331092

  1. 功能:判断vector是否为空(有效数据个数为0)
  2. 参数:无
  3. 返回值:size==0返回ture ,否则返回 false

demo:

// vector::empty
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;int sum (0);for (int i=1;i<=10;i++) myvector.push_back(i);while (!myvector.empty()){sum += myvector.back();myvector.pop_back();}std::cout << "total: " << sum << '\n';return 0;
}

output:

total = 55;

reserve

reserveimage-20240116120715351

  1. 功能:改变vectorcapacity,使得capacity最少容纳n个数据
    • n>capacity时,扩容至capacity==n,将原空间数据挪动到扩容后的新空间。
    • n<capacity时,不做处理。
    • reserve不会影响size
  2. 参数:vector最小的容量,实际capacity可能会大于n,类型为size_t
  3. 返回值:无

demo:

// vector::reserve
#include <iostream>
#include <vector>int main ()
{std::vector<int>::size_type sz;std::vector<int> foo;sz = foo.capacity();std::cout << "making foo grow:\n";for (int i=0; i<100; ++i) {foo.push_back(i);if (sz!=foo.capacity()) {sz = foo.capacity();std::cout << "capacity changed: " << sz << '\n';}}std::vector<int> bar;sz = bar.capacity();bar.reserve(100);   // this is the only difference with foo abovestd::cout << "making bar grow:\n";for (int i=0; i<100; ++i) {bar.push_back(i);if (sz!=bar.capacity()) {sz = bar.capacity();std::cout << "capacity changed: " << sz << '\n';}}return 0;
}

output:

making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 4
capacity changed: 8
capacity changed: 16
capacity changed: 32
capacity changed: 64
capacity changed: 128
making bar grow:
capacity changed: 100

可以看见,如果提前reserve一段空间,可以减少扩容和数据拷贝的次数从而提高效率。

注意:
不同的编译器对vector扩容机制不同,在VS下扩容后是扩容前空间的1.5倍,g++下是2倍image-20240117093007188

shrink_to_fit

shrink_to_fitimage-20240117093407523

  1. 功能:减少容器的capacity以适应其尺寸,函数可能会realloc,但是对size无影响。
  2. 参数:无
  3. 返回值:无
  4. 注意:该函数没有约束力,容器可以进行自由的优化,使其capacity>size

demo:

// vector::shrink_to_fit
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector (100);std::cout << "1. capacity of myvector: " << myvector.capacity() << '\n';myvector.resize(10);std::cout << "2. capacity of myvector: " << myvector.capacity() << '\n';myvector.shrink_to_fit();std::cout << "3. capacity of myvector: " << myvector.capacity() << '\n';return 0;
}

output:

1. capacity of myvector: 100
2. capacity of myvector: 100
3. capacity of myvector: 10

获取元素

operator[]

operator[]image-20240117095306769

  1. 功能:返回vector中第n个元素的引用。与vector::at具有相同功能,不同的是 vector::at 进行了边界检查,并通过抛出 out_of_range 异常来指示请求的位置是否超出范围。
  2. 参数:n是容器中第n个元素,类型为size_t
  3. 返回值:第n个元素的引用,如果是const vector,返回常引用,否则返回引用

demo:

// vector::operator[]
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector (10);   // 10 zero-initialized elementsstd::vector<int>::size_type sz = myvector.size();// assign some values:for (unsigned i=0; i<sz; i++) myvector[i]=i;// reverse vector using operator[]:for (unsigned i=0; i<sz/2; i++){int temp;temp = myvector[sz-1-i];myvector[sz-1-i]=myvector[i];myvector[i]=temp;}std::cout << "myvector contains:";for (unsigned i=0; i<sz; i++)std::cout << ' ' << myvector[i];std::cout << '\n';return 0;
}

output:

myvector contains: 9 8 7 6 5 4 3 2 1 0

data

data外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:返回一个指向vector用于内部存储数据的数组的指针。因为vector数据是连续存储的,所以可以通过data偏移量访问vector中的数据,例如v.data()[1]==v[1]
  2. 参数:空
  3. 返回值:指向第一个数据的指针。如果vector只读,指针指向的类型是const_value_type,否则指针指向的类型是value_type

demo:

// vector::data
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector (5);int* p = myvector.data();*p = 10;++p;*p = 20;p[2] = 100;std::cout << "myvector contains:";for (unsigned i=0; i<myvector.size(); ++i)std::cout << ' ' << myvector[i];std::cout << '\n';return 0;
}

output:

myvector contains: 10 20 0 100 0

修改

assign

assign外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:用数据覆盖vector原本的内容,并合适地修改size。当且仅当新的容器大小大于当前vector时,数组会realloc
  2. 参数:
    • 范围分配:firstlast是其他容器的迭代器,first是序列的初始位置,last是序列的结束位置,将[first,last)中的值分配给vector,这些值包括first不包括last
    • 填充分配:nvectorsize大小,类型为size_t,用nval填充vector
  3. 返回值:空

demo:

// vector assign
#include <iostream>
#include <vector>int main ()
{std::vector<int> first;std::vector<int> second;std::vector<int> third;first.assign (7,100);             // 7 ints with a value of 100std::vector<int>::iterator it;it=first.begin()+1;second.assign (it,first.end()-1); // the 5 central values of firstint myints[] = {1776,7,4};third.assign (myints,myints+3);   // assigning from array.std::cout << "Size of first: " << int (first.size()) << '\n';std::cout << "Size of second: " << int (second.size()) << '\n';std::cout << "Size of third: " << int (third.size()) << '\n';return 0;
}

output:

Size of first: 7
Size of second: 5
Size of third: 3

push_back

push_back外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:将val值插入到vector尾部。尾插后size会增加1个大小,当且仅当增加后的size>capacity时,分配的存储空间会realloc
  2. 参数:要复制到尾部的值,是一个常引用
  3. 返回值:空
  4. 注意:
    • 如果发生了realloc,那么realloc的时间与vectorsize成线性函数。
    • 如果发生了realloc,那么所有的迭代器,指针,引用都会失效,否则只有end_iterator是失效的,其他的迭代器,指针引用都和调用前指向相同。
    • 如果发生了realloc,所有的元素都会被复制到新分配的空间中。

demo:

// vector::push_back
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;int myint;std::cout << "Please enter some integers (enter 0 to end):\n";do {std::cin >> myint;myvector.push_back (myint);} while (myint);std::cout << "myvector stores " << int(myvector.size()) << " numbers.\n";return 0;
}

pop_back

pop_back外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:删除vector中最后一个元素,size大小减一。
  2. 参数:空
  3. 返回值:空
  4. 注意:
    • pop_back后,任何指向被删除元素的迭代器,指针,引用都失效

demo:

// vector::pop_back
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;int sum (0);myvector.push_back (100);myvector.push_back (200);myvector.push_back (300);while (!myvector.empty()){sum+=myvector.back();myvector.pop_back();}std::cout << "The elements of myvector add up to " << sum << '\n';return 0;
}

output:

The elements of myvector add up to 600

insert

insertimage-20240117111954131

  1. 功能:通过在指定位置的元素之前插入新元素来扩展vector,从而通过插入元素的数量有效地增加容器大小。当新的size>capacity时,分配的空间会realloc

  2. 参数:

    • position:插入元素的位置,iterator是一个成员类型,定义为指向元素的random_access_iterator类型。
    • val:插入值的常引用
    • n:插入元素的个数,类型为size_t
    • first,last:指定添加元素范围的区间。 [first,last) 范围内的元素副本将插入到position位置(以相同的顺序)。范围包括first不包括lastfirstlast都是vector::iterator类型。
  3. 返回值:返回一个指向新插入的第一个元素迭代器,返回值类型为vector::iterator

  4. 注意:

    • 时间复杂度:与插入的元素数量(复制/移动构造)加上位置后的元素数量(移动)成线性关系。若不是在vector末尾插入元素,效率通常不会很高 O ( n ) O(n) O(n)

    • 迭代器失效:如果内存分配发生realloc,那么所有的迭代器,指针,引用都会失效;否则只有指向position之后的迭代器,指针,引用会失效,指向position之前的迭代器,指针,引用不会失效。

demo:

// inserting into a vector
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector (3,100);std::vector<int>::iterator it;it = myvector.begin();it = myvector.insert ( it , 200 );myvector.insert (it,2,300);//After reallocation, "it" no longer valid, get a new one:it = myvector.begin();std::vector<int> anothervector (2,400);myvector.insert (it+2,anothervector.begin(),anothervector.end());int myarray [] = { 501,502,503 };myvector.insert (myvector.begin(), myarray, myarray+3);std::cout << "myvector contains:";for (it=myvector.begin(); it<myvector.end(); it++)std::cout << ' ' << *it;std::cout << '\n';return 0;
}

output:

myvector contains: 501 502 503 300 300 400 400 200 100 100 100

erase

erase外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:从vector中删除单个元素或删除一段迭代器区间。size大小减一。
  2. 参数:
    • position:指向vector中需要被删除的元素。vector::iteratorvector::const_iterator都是成员类型,也是random_access_iterator
    • first,last:指定要删除vector的区间,包括[first,last)中的所有元素,即包括first不包括lastfirstlast都是vector::iterator类型,即random_access_iterator
  3. 返回值:返回一个指向最后一个被删除元素的下一个新位置的迭代器。
  4. 注意:
    • 时间复杂度:与删除(破坏)的元素数量加上最后一个元素删除(移动)之后的元素数量成线性关系。处尾删外,删除效率不是很高 O ( n ) O(n) O(n)
    • 迭代器失效:指向 position(或 first)及以后元素的迭代器、指针和引用将失效,而指向 position(或 first)之前元素的所有迭代器、指针和引用将保证继续指向调用前所指向的相同元素。

demo:

/ erasing from vector
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;// set some values (from 1 to 10)for (int i=1; i<=10; i++) myvector.push_back(i);// erase the 6th elementmyvector.erase (myvector.begin()+5);// erase the first 3 elements:myvector.erase (myvector.begin(),myvector.begin()+3);std::cout << "myvector contains:";for (unsigned i=0; i<myvector.size(); ++i)std::cout << ' ' << myvector[i];std::cout << '\n';return 0;
}

output:

myvector contains: 4 5 7 8 9 10

swap

swap外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 功能:用另一个vector的内容交换当前vector的内容,两个vector的类型相同,size可能不同
  2. 参数:需要交换内容的vector引用xx与当前vector具有相同类型。
  3. 返回值:空
  4. 注意:
    • 成员函数swap是通过非成员库函数swap实现的
    • vector bool 特化为此函数提供了额外的重载vector<bool>::swap

demo:

// swap vectors
#include <iostream>
#include <vector>int main ()
{std::vector<int> foo (3,100);   // three ints with a value of 100std::vector<int> bar (5,200);   // five ints with a value of 200foo.swap(bar);std::cout << "foo contains:";for (unsigned i=0; i<foo.size(); i++)std::cout << ' ' << foo[i];std::cout << '\n';std::cout << "bar contains:";for (unsigned i=0; i<bar.size(); i++)std::cout << ' ' << bar[i];std::cout << '\n';return 0;
}

output:

foo contains: 200 200 200 200 200 
bar contains: 100 100 100 

clear

(clear)[https://cplusplus.com/reference/vector/vector/clear/]image-20240117205312205

  1. 功能:移除vector中的所有元素,让size=0。
  2. 参数:空
  3. 返回值:空
  4. 注意:
    • 调用该函数不能保证会发生realloc,也不能保证capacity会改变。强制清空capacity可以通过使用swap函数vector<T>().swap(x)
    • 复杂度:和size大小线性相关
    • 迭代器失效:vector中的所有迭代器都失效

demo:

// clearing vectors
#include <iostream>
#include <vector>int main ()
{std::vector<int> myvector;myvector.push_back (100);myvector.push_back (200);myvector.push_back (300);std::cout << "myvector contains:";for (unsigned i=0; i<myvector.size(); i++)std::cout << ' ' << myvector[i];std::cout << '\n';myvector.clear();myvector.push_back (1101);myvector.push_back (2202);std::cout << "myvector contains:";for (unsigned i=0; i<myvector.size(); i++)std::cout << ' ' << myvector[i];std::cout << '\n';return 0;
}

output:

myvector contains: 100 200 300
myvector contains: 1101 2202

vector的实现

成员变量

T* _start:指向存储空间的起始位置

T* _finish:指向最后一个有效数据的下一个位置

T* _end_of_storage:指向最后一个有效存储空间的下一个位置

迭代器

iterator:T*的重定义。

const_iterator:const T*的重定义。

成员函数

构造/析构函数

注意:

  • 在执行拷贝构造函数时,需要考虑深拷贝的问题~
  • range构造函数中first和last的类型是一样的,所以我们调用vector<int>(10,1)时,我们想用10个1去构造,但是编译器可能会识别为10和1全部都是迭代器,此时解引用就会造成非法访问,解决办法就是在fill构造函数中将第一个参数类型指定为int ,这样编译器在模板参数和显示参数中选择调用带有显示参数的构造函数,也就是我们想要的fill构造函数。
	template<typename T>class vector{public:typedef T* iterator;typedef const T* const_iterator;vector()			//default构造函数{_start = _finish = _end_of_storage = nullptr;}vector(int sz, const T& val = T()){					//fill构造函数,sz的类型为int让编译器区分构造vector<int>(3,1)类型时调用的是fill构造而不是range构造//为vector申请sz个空间_finish = _start = new T[sz];//fill构造时,_end_of_storage和_finish指向同个位置_end_of_storage = _start + sz;//这里也可以*_finish++ = val;for (size_t i = 0; i < sz; i++){push_back(val);}}vector(const vector<T>& v){					//拷贝构造函数//v的sizeint sz = v._finish - v._start;//v的capacityint capacity = v._end_of_storage - v._start;_start = new T[capacity];//注意:这里依次让v的每个元素赋值给*this,当*this类似于string类型时赋值可以调用string的深拷贝//不能简单的使用memcpy,memcpy是浅拷贝for (size_t i = 0; i < sz; i++){_start[i] = v._start[i];}//更新_finish和_end_of_storage_finish = _start + sz;_end_of_storage = _start + capacity;}//range构造函数template<typename InputerIterator>vector(InputerIterator first, InputerIterator last){					//数据区间为[first,last)while (first != last){				//等效于*_finish++ = *first++;push_back(*first++);//first++;}}~vector(){					//new的空间delete,防止MemoryLeakdelete[] _start;_start = _finish = _end_of_storage = nullptr;}

测试结果:外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

赋值重载

注意:当vector类型为string等,考虑深拷贝问题

		//赋值重载函数vector<T>& operator=(const vector<T>& v){int sz = v._finish - v._start;int capacity = v._end_of_storage - v._start;//start指向sz个空间_start = new T[sz];for (size_t i = 0; i < sz; i++){				//使用赋值考虑深拷贝的问题*_finish++ = v[i];}//更新_end_of_storage_end_of_storage = _start + capacity;return *this;}

测试结果:image-20240118094731283

迭代器

		//迭代器iterator begin(){					return _start;	}const_iterator begin() const{return _start;	}iterator end(){return _finish;}const_iterator end() const{return _finish;}

测试结果:image-20240118100044157

容量相关函数

注意:

  • 实现扩容相关函数时,涉及到将原空间数据拷贝到新空间中,所以需要考虑深拷贝问题
		rsize_t capacity() const{return _end_of_storage - _start;	//_end_of_storage和_start之间是存储空间}rsize_t size() const{return _finish - _start;			//_finish和_start之间是有效元素}void reserve(size_t n)		//预先开辟n个空间{size_t cap = capacity();size_t sz = size();if (n > cap)			//当且仅当n大于当前容量扩容{T* tmp = new T[n];//拷贝元数据到新空间,数据拷贝时需要注意深拷贝问题,使用赋值而不用memcpyfor (size_t i = 0; i < sz; i++){tmp[i] = _start[i];}delete[] _start;		//释放原数据空间//更新_start _finish _end_of_storage_start = tmp;_finish = _start + sz;_end_of_storage = _start + cap;}}void resize(size_t sz, T val = T()){size_t _sz = _finish - _start;size_t _capacity = _end_of_storage - _start;if (sz < _sz)				//情况1.sz小于当前size,直接缩小当前size,capacity不变{_finish -= sz;}else if (sz <= _capacity)	//情况2.size<sz<capacity,直接在剩下的存储空间中插入capacity-{while (_sz < sz){push_back(val);_sz++;}}else						//情况3.sz>capacity,先扩容,在插入sz-size个val{reserve(sz);while (_sz < sz){push_back(val);}}}

测试结果:image-20240118113057550

获取元素/修改

注意:

  • 当使用insert和erase时,需要注意迭代器失效。
    • insert:若插入后扩容了,如果是异地扩容,则原来的迭代器全部失效,需要更新,若没有扩容,原本指向插入位置之后的迭代器失效,之前的没有影响
    • erase:删除位置后面的迭代器全部失效,前面的没有影响
			/*访问*/T& operator[](size_t pos){assert(0 <= pos && pos < _finish - _start);return *(_start + pos);}const T& operator[](size_t pos) const{assert(0 <= pos && pos < _finish - _start);return *(_start + pos);}T front(){return *_start;}const T front() const {return *_start;}T back(){return *_finish;}const T back() const{return *_finish;}/*修改类*/void push_back(const T& val){size_t sz = _finish - _start;size_t ca = _end_of_storage - _start;if (ca == sz){reserve(ca == 0 ? 4 : 2 * ca);}*_finish = val;_finish++;//insert(end(), val);}void pop_back(){assert(_finish - _start >= 1);_finish--;//erase(end() - 1);}iterator insert(iterator pos, const T& val)//返回值用于更新扩容前指向pos处的迭代器{int sz = _finish - _start;int capacity = _end_of_storage - _start;int gap = pos - _start;				   //记录扩容前_start和pos的相对位置if (_finish == _end_of_storage)		   //扩容{//2倍扩容reserve(capacity == 0 ? 4 : 2*capacity);//此时_start _finish _end_of_storage已经是扩容后的位置了									pos = _start + gap;//修正pos}/*挪动数据*/iterator end = _finish;while (end > pos){*end = *(end - 1);end--;}*pos = val;_finish++;return pos;}template<class Inputiterator>iterator insert(iterator pos, Inputiterator first, Inputiterator last){int num = last - first;						//要插入的个数int sz = _finish - _start;int capacity = _end_of_storage - _start;int gap = pos - _start;						//_start和pos的相对位置//当前容量不够插入需要扩容if (sz + num >  capacity){reserve(sz + num);_finish = _end_of_storage;pos = _start + gap;iterator after = pos + num;iterator before = pos;while (after < _end_of_storage){*after++ = *before++;}while (first < last){*pos++ = *first++;}_finish = _end_of_storage;}//当前容量够插入else{iterator after = pos + num;iterator before = pos;while (before < _finish){*after++ = *before++;}while (first < last){*pos++ = *first++;}_finish = after;}return pos;}iterator erase(iterator pos){assert(pos >= _start);		//删除元素位置介于[first,last)assert(pos < _finish);iterator begin = pos;		//pos后面的元素往前挪while (begin < _finish - 1){*begin = *(begin + 1);begin++;}_finish--;return pos;}void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}void clear(){_finish = _start;			//size=0}

测试结果:image-20240118120643463

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646061.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

redis—Set集合

目录 前言 1.常见命令 2.使用场景 前言 集合类型也是保存多个字符串类型的元素的&#xff0c;但和列表类型不同的是&#xff0c;集合中1)元素之间是无序的2)元素不允许重复&#xff0c;如图2-24所示。一个集合中最多可以存储22 - 1个元素。Redis 除了支持集合内的增删查改操…

前端 .then 返回有数据但是return 不出来 ,并 解决处理后的 Promise下的Object

解决方法就是&#xff1a;async await async声明方法为异步方法&#xff0c;await等待异步操作执行完。 &#xff08;async函数return的是Promise&#xff0c;await Promise后得到Object&#xff09; 注意的是&#xff0c;异步方法返回值为peomise<>&#xff0c;接收时需…

【计算机网络】【练习题】【新加坡南洋理工大学】【Computer Control Network】

说明&#xff1a; 仅供学习使用。 一、题目描述 该题目描述一个网络中传播时延&#xff08;Transmission Delay&#xff09;的例子。题目如下&#xff1a; 二、问题解答&#xff08;个人&#xff09; 笔者第3问采用均值不等式求解。标答中采用求导数的方法求极值。似乎均值…

学术精选,EI检索2024年计算机应用系统与微芯片技术国际会议

2024年计算机应用系统与微芯片技术国际会议(ICCASMT 2024) 2024 International Conference on Computer Application Systems and Microchip Technology(ICCASMT 2024) 数据库&#xff1a;EI,CPCI,CNKI,Google Scholar等检索 一、【会议简介】 &#x1f514; ​2024年计算机应用…

JS之打地鼠案例

需要素材的同学可以私信我 效果图&#xff1a; 上代码&#xff1a; <!DOCTYPE html> <html> <head><meta charset"utf-8"><title></title><style>* {margin: 0;padding: 0;}.box {position: relative;width: 320px;heigh…

数据结构之树

树 前面文章讲的线性表&#xff0c;不论数组还是链&#xff0c;都是“一对一”的关系&#xff0c;本文章节让我们来认识一下“一对多”关系的数据结构——树&#xff08;Tree&#xff09;。 树结构分为二叉树和三叉树等&#xff0c;如下图所示。常用的就是二叉树&#xff0c;因…

深度学习(5)--Keras实战

目录 一.Keras基础概念 二.如何跑通Keras项目 2.1.在cmd上跑通 2.2.在PyCharm上跑通 一.Keras基础概念 Keras是深度学习中的一个神经网络框架&#xff0c;是一个高级神经网络API&#xff0c;用Python编写&#xff0c;可以在TensorFlow&#xff0c;CNTK或Theano之上运行。 …

如何保护电脑数据?电脑数据怎么保护?

电脑会储存大量的重要数据&#xff0c;而为了避免数据泄露&#xff0c;必须要使用专业的方式进行保护。那么&#xff0c;要如何保护电脑数据呢&#xff1f;下面我们就来了解一下。 文件夹加密超级大师 文件夹加密超级大师是一款专业的电脑数据加密软件&#xff0c;拥有强大的文…

医疗天使禅道使用工作流程:优化医疗服务的必经之路

目录 博客前言 医疗天使禅道使用工作流程 一.使用最高管理员账号admin管理组织结构 1.新增用户 产品经理使用禅道 1.创建产品 2.添加产品模块​编辑 3.添加产品计划 4.添加产品需求 5.创建项目 6.设置团队 项目经理使用禅道 1.关联需求 2.分解任务 测试主管使用禅…

200G数据中心:QSFP56和QSFP-DD光模块如何选择?

随着光通信与互联网技术的迅猛发展&#xff0c;网络数据流量的需求呈指数级增长&#xff0c;电信骨干网流量年均增速高达50%至80%。为了应对日益攀升的数据传输需求&#xff0c;光通信速率实现了从10G、25G、40G到当前主流的100G、200G、400G甚至更高规格的持续演进。 在此背景…

Linux-共享内存

文章目录 前言一、system V共享内存申请共享内存挂载共享内存删除共享内存挂载删除共享内存 二、示例代码三.运行效果 前言 在这之前我们已经学习了两种进程间通信方式&#xff1a;匿名管道和命名管道。 从我们之前的学习已经知道&#xff0c;想让多个进程间进行通信就需要让他…

前端JavaScript篇之intanceof 操作符的实现原理及实现、为什么0.1+0.2 ! == 0.3,如何让其相等

目录 intanceof 操作符的实现原理及实现为什么0.10.2 ! 0.3&#xff0c;如何让其相等 intanceof 操作符的实现原理及实现 instanceof 是一个用于检查对象是否属于特定类的 JavaScript 操作符。它返回一个布尔值&#xff0c;指示对象是否是特定类的实例或者原型链中是否存在该…

常见の算法

前言本文主要使用Java 什么&#xff0c;是快乐星球#&#xffe5;%……什么是算法&#xff1f; 算法是一组完成任务的指令。任何代码片段都可视为算法&#xff0c;但我们主要介绍常见算法 一、引入——二分查找 二分查找是一种算法&#xff0c;其输入是一个有序的元素列表。如…

浏览器实用:禁止浏览器http自动转成https

前言 因为有些网站支持http和https两种协议访问&#xff0c;有些只支持一种协议访问。但根据动态域名安全策略&#xff08;HSTS&#xff09;&#xff0c;只要该域名在浏览器中访问过一次https&#xff0c;那么浏览器将强制使http的请求变为https。 虽然这条浏览器的策略有利于提…

Flink入门教程

使用flink时需要提前准备好scala环境 一、创建maven项目 二、添加pom依赖 <properties><scala.version>2.11.12</scala.version></properties><dependency><groupId>org.scala-lang</groupId><artifactId>scala-library<…

携程基于Jira Cloud的敏捷项目管理实践

好的工具可以满足团队在各个成长阶段的管理诉求 实践一&#xff1a;对齐目标/团队OKR/多团队协作战略项目 实践二&#xff1a;以产品为中心的协作框架 实践三&#xff1a;交付团队管理 实践四&#xff1a;和海外子公司对齐&#xff0c;协作

在linux、window环境搭建kafka环境

一、搭建环境前置准备 下载kafka的官网 http://kafka.apache.org/downloads根据自己的需求选择版本,安装包不区分linux和windows环境,这一个安装包均可部署。 源代码包含kafka的代码文件,使用scala编写的。 二、linux环境 1. 上传安装包 我下载的版本是kafka_2.12-3.6.1…

09.Elasticsearch应用(九)

Elasticsearch应用&#xff08;九&#xff09; 1.搜索结果处理包括什么 排序分页高亮返回指定字段 2.排序 介绍 Elasticsearch支持对搜索结果排序&#xff0c;默认是根据相关度算分来排序 支持排序的字段 keyword数值地理坐标日期类型 排序语法 GET /[索引名称]/_sear…

网络协议与攻击模拟_08DHCP协议

技术学习要了解某项技术能干什么&#xff1f;它的详细内容&#xff1f;发展走向&#xff1f; 一、DHCP协议 1、DHCP基本概念 dhcp动态主机配置协议&#xff0c;广泛应用于局域网内部 主要是为客户机提供TCP/IP 参数&#xff08;IP地址、子网掩码、网关、DNS等&#xff09;…

5G赋能智慧文旅:科技与文化的完美结合,打造无缝旅游体验,重塑旅游业的未来

一、5G技术&#xff1a;智慧文旅的强大引擎 5G技术的起源可以追溯到2010年&#xff0c;当时世界各国开始意识到4G技术已经达到了瓶颈&#xff0c;无法满足日益增长的移动通信需求。2013年&#xff0c;国际电信联盟&#xff08;ITU&#xff09;成立了5G技术研究组&#xff0c;开…