<C++>STL->vector

news2024/11/25 1:08:09

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是一个类模板,显示模板实例化int
	vector<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: 0
  std::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 5
  std::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 ints

  std::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  1
  std::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 above
  std::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 elements

  std::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 100

  std::vector<int>::iterator it;
  it=first.begin()+1;

  second.assign (it,first.end()-1); // the 5 central values of first

  int 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 element
  myvector.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 100
  std::vector<int> bar (5,200);   // five ints with a value of 200

  foo.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的size
			int sz = v._finish - v._start;
							//v的capacity
			int 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,防止MemoryLeak
			delete[] _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];
										//拷贝元数据到新空间,数据拷贝时需要注意深拷贝问题,使用赋值而不用memcpy
				for (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.coloradmin.cn/o/1405710.html

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

相关文章

MySQL-SQL-DQL

DQL-介绍 DQL-语法 基本查询 1、查询多个字段 2、设置别名 3、去除重复记录 条件查询 1、语法 2、条件 聚合函数 1、介绍 2、常见的聚合函数 3、语法 分组查询 1、语法 2、where与having区别 排序查询 1、语法 2、排序方式 分页查询 1、语法 DQL-执行顺序

多维时序 | Matlab实现WOA-TCN-Multihead-Attention鲸鱼算法优化时间卷积网络结合多头注意力机制多变量时间序列预测

多维时序 | Matlab实现WOA-TCN-Multihead-Attention鲸鱼算法优化时间卷积网络结合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现WOA-TCN-Multihead-Attention鲸鱼算法优化时间卷积网络结合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计参考资料 效…

C++大学教程(第九版)6.29素数

题目 (素数)素数是只能被1和自已整除的整数。例如,235和7是素数而468和9不是素数 a)编写一个函数&#xff0c;确定一个数是否是素数。 b)在程序中使用这个函数&#xff0c;该程序确定和打印2 ~10000之间的所有素数。在确信已找到所有的素数之前&#xff0c;实际需测试这些数中…

五邑大学餐厅网络点餐系统设计与实现(包含完整源码详细开发过程)

博主介绍&#xff1a;✌专研于前后端领域优质创作者、本质互联网精神开源贡献答疑解惑、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战&#xff0c;深受全网粉丝喜爱与支持✌有需要可以联系作者我哦&#xff01; &#x1f345;文末获…

你不知道的git如何撤销回退版本

简言之&#xff1a;从1 回退到 3&#xff0c;在3版本通过回退记录(git reflog)找到它的上一条回退记录的hash值&#xff0c;复制1的hash值进行回退&#xff0c;执行git reset --hard 粘贴1的hash值进来&#xff0c;此时就回到1的版本了&#xff0c;执行git log即可看到1、2、3、…

安装pytorch GPU的方法,一次安装成功!!win10、win11皆可用!!

前提—查看是否有NVIDIV英伟达显卡&#xff01;&#xff01; 在控制面板打开设备管理器 一、查看电脑的显卡驱动版本 方法一&#xff1a;在cmd命令窗口中输入nvidia-smi&#xff0c;可以发现版本为12.2 方法2&#xff1a;点击NVIDIA控制面板→系统信息 二、安装CUDA 方法1…

算法(4)——前缀和

目录 一、前缀和的定义 二、一维前缀和 三、一维前缀和OJ题 3.1、前缀和 3.2、寻找数组中心下标 3.3、除自身以外数组的乘积 3.4、和为K的数组 3.5、和可被K整除的子数组 3.6、连续数组 四、二位前缀和 4.1、二维前缀和 4.2、矩阵区域和 一、前缀和的定义 对于一个…

探索全球DNS体系 | 从根服务器到本地解析

DNS 发展 DNS&#xff08;Domain Name System&#xff09;的起源可以追溯到互联网早期。 早期的挑战&#xff1a; 早期互联网主要通过IP地址进行通信&#xff0c;用户需要记住复杂的数字串来访问网站。 需求的催生&#xff1a; 随着互联网的扩大&#xff0c;更简单、易记的…

pytest+allure 生成中文报告

背景 已安装pytestallure&#xff0c;生成的报告是英文 allure生成中文报告 参考&#xff1a;allure report 报告中文化及其它优化 方法1&#xff1a;直接在报告中切换中文 方法2&#xff1a;依赖系统中文语言 创建一个setting.js 文件在index.html 同级目录 // 尝试从 l…

java基于安卓开发的流浪动物救助移动应用的设计与实现-计算机毕业设计源码12783

摘 要 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;流浪动物救助系统被用户普遍使用&#xff0c;为方便用户能…

前端面试题-(BFC,前端尺寸单位,网站页面常见的优化手段)

前端面试题-BFC&#xff0c;前端尺寸单位&#xff0c;网站页面常见的优化手段 BFC前端尺寸单位网站页面常见的优化手段 BFC BFC&#xff08;block formartting context&#xff09;块格式化上下文。是通过独立渲染的区域&#xff0c;它拥有自己的渲染规则&#xff0c;可以决定…

51单片机LCD1602调试工具

参考视频&#xff1a;江协科技51单片机 LCD1602头文件代码 #ifndef __LCD1602_H__ #define __LCD1602_H__//用户调用函数&#xff1a; void LCD_Init(); void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char); void LCD_ShowString(unsigned char Line,un…

纷享销客盛邀渠道生态伙伴共赴杭州,凝心聚力共谋未来

2024年1月19日&#xff0c;“凝心聚力 勇立潮头——2024纷享销客首场生态伙伴发展共建会”在杭州绿谷举办。此次会议汇聚了各方60余位伙伴到场&#xff0c;共同探讨行业的未来发展趋势&#xff0c;激发创新力和合作潜力。 会上&#xff0c;纷享销客创始人兼CEO罗旭详尽地介绍了…

Qt Designer教程

文章目录 创建一个 ui 文件选择控件Qt Designer基本控件介绍1、Layouts1.1、Layouts 布局1.2、参数配置 2、Spacers2.1、 Spacers 弹簧介绍2.2、 参数设置 3、Buttons 按键3.1、 Buttons 按键分类 4、Item Views&#xff08;Model-Based&#xff09; 项目视图(基于模型)4.1、 B…

鸿蒙 HarmonyOS ArkTS 弹窗、带点击回调

// xxx.ets@Entry@Componentstruct Page {@State color: Color = Color.Blue;build() {Column({ space: 20 }) {Button(弹窗).width(180).height(80).backgroundColor(this.color).onClick(()=>{AlertDialog.show({title: 弹窗标题,message: 弹窗内容,autoCancel: true,alig…

状态空间模型(SSM)是近来一种备受关注的 Transformer 替代技术

状态空间模型&#xff08;SSM&#xff09;是近来一种备受关注的 Transformer 替代技术&#xff0c;其优势是能在长上下文任务上实现线性时间的推理、并行化训练和强大的性能。而基于选择性 SSM 和硬件感知型设计的 Mamba 更是表现出色&#xff0c;成为了基于注意力的 Transform…

ElasticSearch的集群管理命令

ElasticSearch版本 {"name" : "data-slave1","cluster_name" : "data-es","cluster_uuid" : "xxxxxxxxxx-eMwxw","version" : {"number" : "7.2.1","build_flavor" : &…

重拾计网-第四弹 计算机网络性能指标

ps&#xff1a;本文章的图片内容来源都是来自于湖科大教书匠的视频&#xff0c;声明&#xff1a;仅供自己复习&#xff0c;里面加上了自己的理解 这里附上视频链接地址&#xff1a;1.5 计算机网络的性能指标&#xff08;1&#xff09;_哔哩哔哩_bilibili ​​​ 目录 &#x…

Windows ssh登录eNSP交换机

目录 1. Cloud IO配置1.1 创建UDP端口1.2 创建本地连接1.3 端口映射设置 2. 交换机配置2.1 配置vlanif2.2 配置vty2.3 配置ssh用户2.4 配置aaa2.5 使用Xshell工具登录2.6 用户和密码2.7 登录成功 3. 使用cmd 登录报错提示3.1 手动指定加密算法&#xff0c;提示密码长度无效3.2 …

通过MobaXterm实现串口通信与SSH通信

MobaXterm实现串口通信与SSH MobaXterm简介 MobaXterm是一款终端工具&#xff0c;不仅免费&#xff0c;而且高效&#xff0c;相比于收费的SecureCRT和免费的PuTTy&#xff0c;MobaXterm可谓博采众长。在师兄的建议下&#xff0c;选择这款工具作为终端调试工具。 界面如下图所示…