自学内容网 自学内容网

C++——vector

目录

一、简介

二、接口

  1.构造

2.空间变化

3.增删查改

 三、vector与string的区别

四、模拟实现 

vector.h

test.cpp


一、简介

        vector,其实就是我们C语言学过的动态顺序表,一个可以存储任何数据类型,可以动态增长的数组。C++的STL将其收录,我们再想使用顺序表的时候就不用再自己去造轮子了,可以直接调用库中的顺序表帮我们完成各种需求。

        本博客主要还是介绍vector的各种接口以及部分常用接口的模拟实现

二、接口

        纵览所有接口,我们可以发现vector的接口比string简洁多了,这是因为vector吸取了很多string的经验,减少了冗余。

        我会把比较重要的接口调用的演示代码给出,并配上注释,各位有string的经验应该很容易明白,各个容器之间的很多知识是互通的。

  1.构造

#include<iostream>
#include<vector>
using namespace std;

void test_vector1()
{
// 默认构造,啥也没有,capacity是0
vector<int> v1;
// 10个1构造并初始化
vector<int> v2(10, 1);
// 迭代器区间构造,这个迭代器不仅可以是vector的,其实也可以是其它容器的
vector<int> v3(++v2.begin(), --v2.end());
// 拷贝构造
vector<int> v4(v3);

// 普通遍历
for (size_t i = 0; i < v4.size(); i++)
{
cout << v4[i] << " ";
}
cout << endl;

// 迭代器遍历
vector<int>::iterator it = v4.begin();
while (it != v4.end())
{
cout << *it << " ";
++it;
}
cout << endl;

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

int main()
{
test_vector1();

return 0;
}

2.空间变化

#include<iostream>
#include<vector>
using namespace std;

void TestVectorExpand()
{
// vector在vs环境下,底层是刚开始开辟一个buff数组,等数组满了之后再开始1.5倍扩容
// 如果是gcc条件下,就不会有buff数组,初始就是2倍扩容
size_t sz;
vector<int> v;
v.reserve(100);

sz = v.capacity();
cout << "capacity changed: " << sz << '\n';

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';
}
}
}

void test_vector2()
{
//TestVectorExpand();

// reserve接口的作用和在string中的类似
vector<int> v(10, 1);
v.reserve(20);
cout << v.size() << endl;
cout << v.capacity() << endl;

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

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

void test_vector3()
{
//TestVectorExpand();

// resize的作用与string中的resize类似
vector<int> v(10, 1);
v.reserve(20);
cout << v.size() << endl;
cout << v.capacity() << endl;

v.resize(15, 2);
cout << v.size() << endl;
cout << v.capacity() << endl;

v.resize(25, 3);
cout << v.size() << endl;
cout << v.capacity() << endl;

v.resize(5);
cout << v.size() << endl;
cout << v.capacity() << endl;
}
int main()
{
test_vector1();
    test_vector2();

return 0;
}

3.增删查改

 跟string很类似,看演示就好

#include<iostream>
#include<vector>
using namespace std;

void test_vector4()
{
vector<int> v(10, 1);
v.push_back(2);
v.insert(v.begin(), 0);

for (auto e : v)
{
cout << e << " ";
}
cout << endl;

v.insert(v.begin() + 3, 10);

for (auto e : v)
{
cout << e << " ";
}
cout << endl;

vector<int> v1(5, 0);
for (size_t i = 0; i < 5; i++)
{
cin >> v1[i];
}

for (auto e : v1)
{
cout << e << ",";
}
cout << endl;

}

void test_vector5()
{
vector<string> v1;
string s1("xxxx");
v1.push_back(s1);

v1.push_back("yyyyy");
for (const auto& e : v1)
{
cout << e << " ";
}
cout << endl;
}

int main()
{
test_vector4();
    test_vector5();

return 0;
}

 三、vector<char>与string的区别

        string存储的字符串是以/0结尾的,而vector<char>如果不手动添加,结尾就不是\0,另外,string有许多vector<char>没有的接口,更能有效地对字符串进行操作。 

四、模拟实现 

由于vector需要存储不同的数据类型,所以实现需要用到模板,而模板的声明和定义如果分离的话在运行的时候会发生链接错误,所以只需要一个头文件和一个测试文件

vector.h

实现过程要尤其注意迭代器失效的问题

插入的实现中,如果插入发生了扩容,那么原来传入的pos位置的迭代器就会失效,因为vector已经转移了空间位置,而pos仍在原位,为了得到之后相应的位置,可以把之后的pos位置作为返回值返回

reverse中,如果发生了扩容,则原来的start和finish指针也会失效,则其size()接口也会失效,所以需要在开始就记录下来old_size,方便后续的使用

#pragma once
#include <iostream>
#include <assert.h>
using namespace std;

namespace muss
{
// 使用模板的时候不要声明和定义分离,会发生链接错误
template<typename T>
class vector
{
typedef T* iterator;
typedef const T* const_iterator;

public:
vector() :_start(nullptr), _finish(nullptr), _end_of_storage(nullptr) { }
vector(const vector<T>& v)
{
reserve(v.size());
for (const auto& e : v)
{
push_back(e);
}
}
// 缺省值是类似于int()即整型的默认构造,默认是0
// 必须加const才能接收T()
vector(size_t n, const T& value = T())
{
// 提前开空间提高效率
reserve(n);
while (n--) push_back(value);
}

vector(int n, const T& val = T())
{
reserve(n);
for (int i = 0; i < n; i++)
{
push_back(val);
}
}

// 可以用任何容器的迭代器区间初始化
template<typename InputIterator>
vector(InputIterator begin, InputIterator end)
{
while (begin != end)
{
push_back(*begin);
++begin;
}
}

~vector()
{
if (_start)
{
delete[] _start;
_start = _finish = _end_of_storage = nullptr;
}
}

size_t size() const { return _finish - _start; }
size_t capacity() const { return _end_of_storage - _start; }

iterator begin() { return _start; }
iterator end() { return _finish; }
const_iterator begin() const { return _start; }
const_iterator end() const { return _finish; }

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 reserve(size_t n)
{
size_t old_size = size();
if (capacity() < n)
{
T* tmp = new T[n];
// 不能是memcpy,浅拷贝申请空间的自定义类型会出现错误
for (int i = 0; i < size(); ++i)
{
tmp[i] = _start[i];
}
delete[] _start;
_start = tmp;
// 这里的_start已经不能减_finish了,也就是说size求不出来了
// 把两行换换位置可以,不过写代码的过程中为了保险起见可以用old_size
//_finish = _start + size();
_finish = _start + old_size;
_end_of_storage = _start + n;
}
}

void resize(size_t n, const T& value = T())
{
if (n < size())
_finish = _start + n;
else
{
reserve(n);
// 填充到size而不是capacity
while (_finish < _start + n)
push_back(value);
}
}

void clear()
{
_finish = _start;
}

bool empty()
{
return _finish == _start;
}

// 擦除指定位置元素
void erase(iterator pos)
{
assert(pos >= _start && pos < _finish);

for (iterator i = pos; i < _finish - 1; ++i)
{
*i = *(i + 1);
}
--_finish;
}

// 一旦发生扩容,pos会失效(pos在原来位置,但是_start和_finish等等都已经转移)
//void insert(iterator pos, const T& value)
//{
//assert(pos >= _start && pos <= _finish);
//if(size() == capacity())
//reserve(capacity() == 0 ? 4 : 2 * capacity());
//for (iterator i = _finish; i > pos; --i)
//{
//*i = *(i - 1);
//}
//++_finish;
//*pos = value;
//}

// 所以我们需要在扩容结束时更新pos,并且如果想在函数外继续使用pos,我们需要给返回值
iterator insert(iterator pos, const T& value)
{
assert(pos >= _start && pos <= _finish);
if (size() == capacity())
{
size_t len = pos - _start;
reserve(capacity() == 0 ? 4 : 2 * capacity());
pos = _start + len;
}

for (iterator i = _finish; i > pos; --i)
{
*i = *(i - 1);
}
++_finish;
*pos = value;
return pos;
}

void push_back(const T& value)
{
if (size() == capacity())
{
reserve(capacity() == 0 ? 4 : 2 * capacity());
}
*_finish = value;
++_finish;
}

void pop_back()
{
erase(end() - 1);
}

T& operator[](size_t n)
{
assert(n < size());
return _start[n];
}

const T& operator[](size_t n) const
{
assert(n < size());
return _start[n];
}

vector<T>& operator=(const vector<T>& v)
{
clear();
reserve(v.size());

for (size_t i = 0; i < v.size(); ++i)
{
push_back(v[i]);
}

return *this;
}

private:
iterator _start = nullptr; // 首元素位置
iterator _finish = nullptr;// 尾元素位置的下一个位置
iterator _end_of_storage = nullptr;// 超出容量的下一个位置
};

// 可以打印所有容器
template<typename Container>
void print_container(const Container& c)
{
for (const auto& e : c)
{
cout << e << " ";
}
cout << endl;
}

void vector_test1()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
print_container(v1);

vector<int> v2(v1);
print_container(v2);

vector<int> v3(v2.begin() + 1, v2.end() - 1);
print_container(v3);

vector<int> v4(10);
// ???????????????
vector<int> v5(9, 12);
print_container(v4);
print_container(v5);

}

void vector_test2()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
print_container(v1);

v1.insert(v1.begin() + 1, 22);
print_container(v1);
v1.insert(v1.begin(), 123);
print_container(v1);
v1.insert(v1.end(), 999);
print_container(v1);

vector<int> v2;
v2.push_back(1);
v2.push_back(2);
v2.push_back(3);
v2.push_back(4);
v2.push_back(5);
print_container(v2);
v2.resize(3);
print_container(v2);
v2.resize(7, 8);
print_container(v2);
v2.resize(12, 13);
print_container(v2);

}

void vector_test3()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
print_container(v1);
cout << v1[2] << endl;
cout << v1[0] << endl;
cout << v1[4] << endl;
v1.clear();
print_container(v1);
cout << v1.empty() << endl;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
cout << v1.empty() << endl;
print_container(v1);

v1.erase(v1.begin() + 1);
print_container(v1);
v1.erase(v1.begin());
print_container(v1);
// 要注意尾删得用end()-1,不然会越界
v1.erase(v1.end() - 1);
print_container(v1);
v1.pop_back();
print_container(v1);
}

void vector_test4()
{
vector<int> v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
v1.push_back(5);
print_container(v1);

vector<int> v2;
vector<int> v3;
v2 = v3 = v1;
print_container(v2);
print_container(v3);
vector<int> v4;
v4.push_back(11);
v4.push_back(22);
v4.push_back(33);
swap(v4, v1);
print_container(v1);
print_container(v4);

}

void vector_test5()
{
vector<string> v;
v.push_back("111111");
v.push_back("111111");
v.push_back("111111");
v.push_back("111111");
v.push_back("111111");
v.push_back("111111");
v.push_back("111111");
print_container(v);
}
}

test.cpp

#include "vector.h"
#include <vector>
//using namespace std;

int main()
{
//vector<int> v1 = { 1,2,3,4,5,7,8,5,13,54 };
//cout << v1.capacity() << endl;
//vector<int> v2(v1);
//cout << v2.capacity() << endl;

muss::vector_test5();

//cout << int() << endl;


return 0;
}

完结撒花~~~~(✿╹◡╹)


原文地址:https://blog.csdn.net/2301_79830926/article/details/142791657

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!