<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是一个类模板,显示模板实例化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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙开发教程-管理组件状态

概述 在应用中&#xff0c;界面通常都是动态的。如图1所示&#xff0c;在子目标列表中&#xff0c;当用户点击目标一&#xff0c;目标一会呈现展开状态&#xff0c;再次点击目标一&#xff0c;目标一呈现收起状态。界面会根据不同的状态展示不一样的效果。 ArkUI作为一种声明式…

【Unity】AB包下载

【Unity】AB包下载 1.使用插件打AB包 a.AB包分类 一般地&#xff0c;将预制体作为AB包资源&#xff0c;不仅需要对预制体本身进行归类&#xff0c;还要对其涉及的动画&#xff08;AnimationClip&#xff09;、动画状态机&#xff08;AnimatorController&#xff09;、以及所…

数据可视化 | 期末复习 | 补档

文章目录 &#x1f4da;介绍可视化&#x1f407;什么是可视化&#x1f407;科学可视化&#xff0c;信息可视化&#xff0c;可视分析系统三者之间有什么区别&#x1f525;&#x1f407;可视化的基本流程&#x1f407;可视化的两个基本设计原则&#x1f407;数据属性&#x1f407…

Linux基本常用命令大全(一)

一、基本命令 1.1 关机和重启 关机 shutdown -h now 立刻关机 shutdown -h 5 5分钟后关机 poweroff 立刻关机 重启 shutdown -r now 立刻重启 shutdown -r 5 5分钟后重启 reboot 立刻重启 1.2 帮助命令 –help命令 shutdown --help&#xff1a; ifconfig --help&#xff1a…

蓝牙资产标签

在高科技信息行业的迅猛发展下&#xff0c;信息化管理在各领域的应用体现了很大的优势&#xff0c;从人员、资产、车辆、物料等的各类应用的定位信息是数字化管理的重要组成部分&#xff0c;小编详细 介绍下蓝牙资产标签在物资管理的应用。 G806采用低功耗蓝牙技术&#xff0c…

JavaScript 操作(DOM)文档对象模型

文章目录 什么是DOM浏览器内置解析器JavaSiript 如何修改结构与样式浏览器解析顺序DOM相关APIgetElementByIdgetElementsByTagNamecreateElementinnerText与innerHTMLappendChild JavaScript 修改结构与样式案例 什么是DOM DOM&#xff1a;DOM&#xff08;文档对象模型&#x…

gradle构建spring-framework源码

5.3.22版本构建 通过启动的jvm参数配置代理下载 Could not download jruby-stdlib-9.2.20.1.jar (org.jruby:jruby-stdlib:9.2.20.1) Could not get resource https://repo.maven.apache.org/maven2/org/jruby/jruby-stdlib/9.2.20.1/jruby-stdlib-9.2.20.1.jar. Could not GE…

如何在Linux部署JumpServer堡垒机并实现远程访问本地服务

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

数据结构:非完全二叉树(递归实现)

非完全二叉树是指在二叉树中&#xff0c;除了叶子节点&#xff08;无子节点&#xff09;外&#xff0c;其他节点的子节点个数可以不同&#xff0c;即不一定是每个节点都有两个子节点&#xff0c;有右孩子时也不一定有左孩子。 tree.h /* * 文件名称&#xff1a;tree.h * …

VMware workstation平台下配置Fedora-Server-39-1.5虚拟机网络

VMware workstation平台下配置Fedora-Server-39-1.5虚拟机网络 Fedora包含的软件以自由及开放源码许可来发布&#xff0c;并旨在成为该技术领域的领先者。Fedora在专注创新、抢先集成新技术、与上游Linux社区紧密工作方面拥有良好名声。该文档适用于在VMware workstation平台下…

项目03——《古罗马战场》

接下来我们布置场景&#xff0c;我们的预期结果&#xff08;功能分析&#xff09;是&#xff1a; 实现两角色阵列面向冲锋 首先进入资源商店准备下载角色模型资源&#xff0c; 搜索Monster&#xff0c; 将免费资源导入unity包&#xff0c; 创建一个地面Plane&#xff0c; 对两…

2023.1.17 关于 Redis 持久化 AOF 策略详解

目录 引言 AOF 策略 实例演示一 缓冲区 重写机制 手动触发 自动触发 AOF 重写流程 实例演示二 引言 Redis 实现持久化的两大策略 RDB ——> Redis DataBase&#xff08;定期备份&#xff09;AOF ——> Append Only File&#xff08;实时备份&#xff09; 注意&…

从零开始的OpenGL光栅化渲染器构建3-法线贴图和视差贴图

前言 我们可以用一张纹理贴图来表现物体表面的基础反射颜色&#xff0c;也可以用一张镜面反射贴图&#xff0c;来指派表面是否产生高光。除此之外&#xff0c;我们可以用贴图来存储表面的法线信息&#xff0c;以及高度信息&#xff0c;从而让渲染效果更加精细。 法线贴图 我…

vulhub之redis篇

CVE-2022-0543 | redis的远程代码执行漏洞 简介 CVE-2022-0543 该 Redis 沙盒逃逸漏洞影响 Debian 系的 Linux 发行版本,并非 Redis 本身漏洞, 漏洞形成原因在于系统补丁加载了一些redis源码注释了的代码 原理分析 redis一直有一个攻击面,就是在用户连接redis后,可以通过ev…

四、RHCE--远程连接服务器

四、RHCE--远程连接服务器 1、远程连接服务器简介2、连接加密技术简介&#xff08;1&#xff09;版本协商阶段&#xff08;2&#xff09;密钥和算法协商阶段&#xff08;3&#xff09;认证阶段 3、ssh服务配置4、用户登录ssh服务器 1、远程连接服务器简介 &#xff08;1&#…

【21K⭐】Legado:一款免费无广且支持高度自定义的必备阅读软件

【21K⭐】Legado&#xff1a;一款免费无广且支持高度自定义的必备阅读软件 随着数字化时代的到来&#xff0c;我们的阅读方式已经发生了巨大的变化。传统的纸质书籍逐渐被电子书取代&#xff0c;人们越来越倾向于使用电子设备来阅读。 然而对于一个喜欢阅读网络小说的人来说&…

从编程中思考:大脑的局部与全局模式(一)

郭靖正在帐篷中用Unity写代码&#xff0c;刚写完一段代码。欧阳锋从帐篷外走进来&#xff0c;正要说点什么&#xff0c;郭靖反应敏捷&#xff0c;转身反手一招神龙摆尾击出&#xff0c;将欧阳锋震出帐篷&#xff0c;灰溜溜逃跑。 using UnityEngine;public class LocalGlobalD…

旧路由重置新路由设置新路由设置教程|适用于自动获取IP模式

前言 如果你的光猫是直接拨号&#xff08;路由模式&#xff09;的&#xff0c;就可以按照本教程进行路由重置或者更换新路由器。 本文章适合电脑小白&#xff0c;请注意每一步哦&#xff01; 注意事项 开始之前需要确认光猫是桥接模式还是路由模式。如果光猫是路由模式&…

《二叉树》——1

目录 前言&#xff1a; 二叉树的链式结构 二叉树的遍历 前序遍历&#xff1a; 中序遍历&#xff1a; 后序遍历&#xff1a; 总结&#xff1a; 前言&#xff1a; 从本文开始&#xff0c;将进一步深入学习编程语言思想&#xff0c;从二叉树开始我们将接触许许多多的递归算…

GoLang基础

1 与其他语言相比&#xff0c;使用go有什么好处&#xff1f; 简洁易学&#xff1a;相比其他编程语言&#xff0c;Go语言具有清晰简洁的语法和规范&#xff0c;减少了代码的复杂性。Go语言拥有较少的关键字和一致的格式&#xff0c;使得代码易于编写、阅读和维护。新手可以很快…