[STL]: Detailed explanation of vector usage

Friends and lads, we meet again. In this issue, I will explain to you the basic usage of vector. If it inspires you after reading it, please leave your three links and I wish you all your wishes will come true. !

C Language Column:C Language: From Beginner to Master

Data structure column:Data structure

Person main number:stackY,

C + + 专栏 :C++

Linux 专 栏 :Linux

​ 

Table of contents

1. Introduction to vector

2. Vector usage

2.1 Definition of vector

2.2vector iterator

2.3vector space growth

2.4Vector addition, deletion, checking and modification

2.4.1 Iterator invalidation


1. Introduction to vector

vector official document reference

Similar tomentioned in the data structureSequence table

  1. vector is a sequence container that represents a variable-size array.
  2. Just like an array, vector also uses continuous storage space to store elements. This means that you can use subscripts to access the elements of the vector, which is as efficient as an array. But unlike an array, its size can be dynamically changed, and its size will be automatically handled by the container.
  3. Essentially, vector usesdynamically allocated arrays to store its elements. When new elements are inserted, the array needs to be resized to increase storage space. This is done by allocating a new array and then moving all elements into this array. In terms of time, this is a relatively expensive task, because the vector is not resized every time a new element is added to the container.
  4. vector allocation space strategy:vector allocates some extra space to accommodate possible growth because the storage space is larger than the actual storage space required. Different libraries use different strategies to trade off space usage and reallocation. But in any case, the reallocation should be logarithmically increasing in interval size, so that inserting an element at the end is done in constant time.
  5. Therefore, vector takes up more storage space in order to gain the ability to manage storage space and grow dynamically in an efficient manner.
  6. Compared with other dynamic sequence containers (deque, list and forward_list), vector is more efficient when accessing elements, and adding and deleting elements at the end is relatively efficient. For other deletion and insertion operations that are not at the end, the efficiency is even lower. Better than unified iterators and references of list and forward_list

2. Vector usage

Be sure to learn when learning vectorView the documentation:Vector official documentation reference< a i=4>, vector is very important in practice. In practice, we only need to be familiar with common interfaces. The following lists which interfaces we need to focus on.

2.1 Definition of vector

Constructor declaration Interface Description
vector() No-argument construction
vector(size_type n, const value_type& val = value_type()) Construct and initialize n vals
vector (const vector& x) copy construction
vector (InputIterator first, InputIterator last) Initialization using iterators

 Before using vector, you need to include the header file corresponding to vector:#include <vector>

#include <vector>

//定义测试
void test_vector1()
{
	//1. 无参
	vector<int> v1;

	//2. n个val构造
	vector<int> v2(10, 0);

	//3. 使用迭代器区间
	vector<int> v3(v2.begin(), v2.end());

	//4. 使用其他容器的迭代器区间
	string str = "Hello World!";
	vector<int> v4(str.begin(), str.end());

	//拷贝构造
	vector<int> v5(v2);
}

2.2vector iterator

Use of iterator Interface Description
begin +
end
Get the iterator/const_iterator of the first data position, Get the iterator/const_iterator of the next position of the last data
rbegin + rend Get the reverse_iterator of the last data position, and get the reverse_iterator of the previous position of the first data
reverse_iterator

//迭代器
void test_vector2()
{
	vector<int> v2(10, 0);

	for (size_t i = 0; i < v2.size(); i++)
	{
		//vector也可以使用[]
		cout << v2[i] << " ";
	}
	cout << endl;

	//迭代器的使用
	//vector<int>::iterator it = v2.begin();
	auto it = v2.begin();
	while (it != v2.end())
	{
		cout << *it << " ";
		it++;
	}
	cout << endl;

	//范围for
	for (auto e : v2)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.3vector space growth

capacity space Interface Description
size Get the number of data
capacity Get capacity size
empty Determine whether it is empty
resize Change the size of vector
reserve  Change the capacity of vector
  • When the capacity code is run under vs and g++ respectively, you will find that the capacity increases by 1.5 times under vs and 2 times by g++. This issue is often investigated. Don’t rigidly believe that the vector capacity is increased by 2 times. The specific increase is defined based on specific needs. vs is the PJ version STL, g++ is the SGI version STL.
  • Reserve is only responsible for opening up space. If you know for sure how much space is needed, reserve can alleviate the cost problem of vector expansion.
  • Resize will also initialize while opening space, which affects size.
// 测试vector的默认扩容机制
void TestVectorExpand()
{
	size_t sz;
	vector<int> v;
	sz = v.capacity();
	cout << "making v grow:\n";
	for (int i = 0; i < 100; ++i)
	{
		v.push_back(i);
		if (sz != v.capacity())
		{
			sz = v.capacity();
			cout << "capacity changed: " << sz << '\n';
		}
	}
}

 vs:运行结果:vs下使用的STL基本是按照1.5倍方式扩容
making foo grow:
capacity changed: 1
capacity changed: 2
capacity changed: 3
capacity changed: 4
capacity changed: 6
capacity changed: 9
capacity changed: 13
capacity changed: 19
capacity changed: 28
capacity changed: 42
capacity changed: 63
capacity changed: 94

capacity changed: 141


g++ running results: STL used under Linux is basically expanded by 2 times
making foo grow:
capacity changed: 1 capacity changed: 16< /span> capacity changed: 128 capacity changed: 64 capacity changed: 32 capacity changed: 8 capacity changed: 4
capacity changed: 2





If you have determined the approximate number of elements to be stored in the vector, you can set enough space in advance (reserve())
to avoid the problem of inefficiency caused by expansion while inserting.

Let’s focus on resize and reserve:

If we want to initialize a vector, we must first create the space and then initialize it, so here we needresizeorreserve?

What resize changes is the size of the vector, and size represents the number of valid elements. Reserve changes the capacity of the vector, and capacity represents the valid space, so resize is required to initialize a vector.

//容量
void test_vector3()
{
	vector<int> v;

	//v.reserve(100); // size == 0    capacity == 100
	v.resize(100); //  size == 100   capacity == 100
	//初始化
	for (size_t i = 0; i < v.size(); i++)
	{
		v[i] = i;
	}
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

2.4Vector addition, deletion, checking and modification

Vector addition, deletion, check and modification Interface Description
push_back tail plug
pop_back  tail delete
find Find. (Note that this is an algorithm module implementation, not a member interface of vector)
insert insert val before position
erase Delete position data
swap Swap the data spaces of two vectors
operator[ ]  access like array

1. End insertion, end deletion 

void test_vector4()
{
	vector<int> v;
	//尾插
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	//尾删
	v.pop_back();
	v.pop_back();
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;
}

2. Insert, delete, find

The find algorithm does not belong to the interface in vector (convenient for insertion and deletion)

//插入、删除
void test_vector5()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);

	//头插
	v.insert(v.begin(), 0);
	//头删
	v.erase(v.begin());

	//在pos位置插入
	v.insert(v.begin() + 2, 30);
	//删除pos位置
	v.erase(v.begin() + 2);

	//在pos位置插入n个val
	v.insert(v.begin() + 1, 5, 10);

	//找到5个10并删除
	for (size_t i = 0; i < 5; i++)
	{
		v.erase(find(v.begin(), v.end(), 10));
	}
}

 

2.4.1 Iterator invalidation

When using vector for insert and erase operations, the vector’s iterator will become invalid:

void test_vector7()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	vector<int>::iterator it = v.begin();
	while (it != v.end())
	{
		cout << *it << ' ';
		v.insert(v.begin() + 2, 7);  //造成迭代器失效
		it++;
	}
}

void test_vector8()
{
	vector<int> v = { 1,2,3,4,5,6,7,8,9,10 };
	vector<int>::iterator it = v.begin();
	//删除偶数
	while (it != v.end())
	{
		if (*it % 2 == 0)
		{
			v.erase(it);
		}
		it++;
	}
}

The same string insert and erase will also cause the iterator to fail:

void TestString()
{
	string s("hello");
	auto it = s.begin();
	// 放开之后代码会崩溃,因为resize到20会string会进行扩容
	// 扩容之后,it指向之前旧空间已经被释放了,该迭代器就失效了
	// 后序打印时,再访问it指向的空间程序就会崩溃
	//s.resize(20, '!');
	while (it != s.end())
	{
		cout << *it;
		++it;
	}

	cout << endl;
	it = s.begin();
	while (it != s.end())
	{
		it = s.erase(it);
		// 按照下面方式写,运行时程序会崩溃,因为erase(it)之后
		// it位置的迭代器就失效了
		// s.erase(it);
		++it;
	}
}

Solution to iterator failure: Just reassign the iterator before use.​ 

3. Clear and shrink (shrink_to_fit)

clear:Only clears data and does not release space.

shrink_to_fit:将capacity缩到size

void test_vector6()
{
	vector<int> v;
	v.push_back(1);
	v.push_back(2);
	v.push_back(3);
	v.push_back(4);
	v.push_back(5);
	for (auto e : v)
	{
		cout << e << " ";
	}
	cout << endl;

	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//清理
	v.clear();
	cout << v.size() << endl;
	cout << v.capacity() << endl;

	//缩容
	v.shrink_to_fit(); 

	cout << v.size() << endl;
	cout << v.capacity() << endl;
}

Friends and guys, good times are always short. Our sharing in this issue ends here. If you want to know what happens next, please listen to the next episode~. Don’t forget to leave you precious after reading it. Thank you for your support!

Guess you like

Origin blog.csdn.net/Yikefore/article/details/133668560