乐趣区

关于c++:C-STL-Vector容器

一、前言

vector 和 array 的不同之处在于:array 实现的是动态数组(容量固定的数组),而 vector 实现的是一个动静数组。
vector 容器以类模板 vector<T>(T 示意存储元素的类型)的模式定义在 <vector> 头文件中,并位于 std 命名空间中。因而,在创立该容器之前,代码中需蕴含如下内容:

#include <vector>
using namespace std;

阐明:std 命名空间也可在应用 vector 容器时额定注明,如:

std::vector<double> values;

二、创立 vector 的形式

①std::vector<int> vecInt;
②std::vector<int> vecInt {1,5,23,45,87};
③std::vector<int> vecInt(10);
④std::vector<int> vecInt(10, 4);

①形式创立一个空的 vector 容器,因为容器中没有元素,所以没有调配空间,当用户增加元素时,vector 会主动分配内存空间。如果创立好的 vector 容器的容量有余,可通过 reserve()减少容器的容量。须要留神的是:

调用 reserve() 不会影响已存储的元素,也不会生成任何元素,即 vecInt 容器内此时依然没有任何元素;如果调用 reserve() 来减少容器容量,之前创立好的任何迭代器(例如开始迭代器和完结迭代器)都可能会生效,因为为了减少容器的容量,vector<T> ** 容器的元素可能曾经被复制或移到了新的内存地址 **。

②形式创立一个蕴含有 5 个元素的 vector 容器
③形式创立一个有 10 个元素、默认初始值为 0 的 vector 容器
④形式创立一个有 10 个元素、指定初始值为 4 的 vector 容器
圆括号 () 和大括号 {} 是有区别的,前者示意元素的个数,而后者则示意 vector 容器中的元素值。

三、成员函数

成员函数 性能
begin() 返回指向容器中第一个元素的迭代器
end() 返回指向容器最初一个元素所在位置后一个地位的迭代器,通常和 begin() 联合应用
rbegin() 返回指向最初一个元素的迭代器
rend() 返回指向第一个元素所在位置前一个地位的迭代器
cbegin() 和 begin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素
cend() 和 end() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素
crbegin() 和 rbegin() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素
crend() 和 rend() 性能雷同,只不过在其根底上,减少了 const 属性,不能用于批改元素
size() 返回理论元素个数
max_size() 返回元素个数的最大值,个别是 232-1,所以咱们很少会用到这个函数
resize() 扭转理论元素的个数
capacity() 返回以后容量
empty() 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false
reserve() 减少容器的容量
shrink _to_fit() 将内存缩小到等于以后元素理论所应用的大小
operator[] 重载了 [] 运算符,能够向拜访数组中元素那样,通过下标即可拜访甚至批改 vector 容器中的元素
at() 应用通过边界查看的索引拜访元素
front() 返回第一个元素的援用
back() 返回最初一个元素的援用
data() 返回指向容器中第一个元素的指针
assign() 用新元素替换原有内容
push_back() 在序列的尾部增加一个元素
pop_back() 移出序列尾部的元素
insert() 在指定的地位插入一个或多个元素
erase() 移出一个元素或一段元素
clear() clear()
swap() 替换两个容器的所有元素
emplace() 在指定的地位间接生成一个元素
emplace_back() 在序列尾部生成一个元素
std::swap(x , y) 非成员函数,替换数据

四、迭代器的用法

vector 的迭代器成员函数和 array 根本是一样的,如下:
begin()
end()
rbegin()
rend()
cbegin()
cend()
crbegin()
crend()
具体性能图示与 https://segmentfault.com/a/11…

1、vector 迭代器的独特之处

vector 容器能够随着存储元素的减少,自行申请更多的存储空间。因而,在创立 vector 对象时,咱们能够间接创立一个空的 vector 容器,并不会影响后续应用该容器。
vector 容器在申请更多内存后,再次应用之前的迭代器,可能会导致解体,因为 vector 容器在减少容量之后,首个元素的存储地址产生了变动,这个时候再应用之前创立的迭代器显然是谬误的,这个时候须要从新初始化迭代器。

五、拜访 vector 容器元素的形式

1、下标形式[]

相似 C ++ 中数组的拜访形式,vector 容器的索引是从 0 开始的,和数组一样。须要保障下标 n 的值不会超过容器的容量,否则会产生拜访越界的谬误。

2、at()

当传给 at()的索引值越界时,会抛出异样

3、遍历 vector 容器元素

依据 size()获取 vector 容器的大小,遍历容器中的元素即可
留神:不能应用 capacity(),因为它返回的是 vector 容器的容量而不是理论存储元素的个数

六、vector 容器增加元素

向 vector 容器中增加元素的惟一形式就是应用它的成员函数

1、push_back()

在 vector 容器尾部增加一个元素

2、emplace_back()

C++11 新增的,性能和 push_back()雷同。
既然性能雷同,为什么要减少一个 emplace_back()呢?

首先咱们理解一下 emplace_back() 和 push_back() 的区别:底层实现的机制不同。push_back() 向容器尾部增加元素时,首先会创立这个元素,而后再将这个元素拷贝或者挪动到容器中(如果是拷贝的话,预先会自行销毁先前创立的这个元素);而 emplace_back() 在实现时,则是间接在容器尾部创立这个元素,省去了拷贝或挪动元素的过程,因而 emplace_back()的执行效率比 push_back()高。

七、vector 插入元素

1、insert()

在 vector 容器的指定地位插入一个或多个元素。该函数的语法格局有多种,如下:

格局 阐明
iterator insert(pos,elem) 在迭代器 pos 指定的地位之前插入一个新元素 elem,并返回示意新插入元素地位的迭代器
iterator insert(pos,n,elem) 在迭代器 pos 指定的地位之前插入 n 个元素 elem,并返回示意第一个新插入元素地位的迭代器
iterator insert(pos,first,last) 在迭代器 pos 指定的地位之前,插入其余容器(不仅限于 vector)中位于 [first,last) 区域的所有元素,并返回示意第一个新插入元素地位的迭代器
iterator insert(pos,initlist) 在迭代器 pos 指定的地位之前,插入初始化列表(用大括号 {} 括起来的多个元素,两头有逗号隔开)中所有的元素,并返回示意第一个新插入元素地位的迭代器

2、emplace()

C++ 11 中新增的成员函数,用于在 vector 容器指定地位之前插入 一个 新的元素。

iterator emplace (const_iterator pos, args...);

pos 为指定插入地位的迭代器;args… 示意与新插入元素的构造函数绝对应的多个参数;该函数会返回示意新插入元素地位的迭代器。
留神:
①当拷贝构造函数和挪动构造函数同时存在时,insert() 会优先调用挪动构造函数。
②理论中,emplace() 的运行效率比 insert()高。emplace() 在插入元素时,是在容器的指定地位间接结构元素,而不是先独自生成,再将其复制(或挪动)到容器中。

八、vector 删除元素的几种形式

如下:

函数 性能
pop_back() 删除 vector 容器中最初一个元素,该容器的大小(size)会减 1,但容量(capacity)不会产生扭转
erase(pos) 删除 vector 容器中 pos 迭代器指定地位处的元素,并返回指向被删除元素下一个地位元素的迭代器。该容器的大小(size)会减 1,但容量(capacity)不会产生扭转
swap(beg)、pop_back() 先调用 swap() 函数替换要删除的指标元素和容器最初一个元素的地位,而后应用 pop_back() 删除该指标元素
erase(beg,end) 删除 vector 容器中位于迭代器 [beg,end)指定区域内的所有元素,并返回指向被删除区域下一个地位元素的迭代器。该容器的大小(size)会减小,但容量(capacity)不会产生扭转
remove() 删除容器中所有和指定元素值相等的元素,并返回指向最初一个元素下一个地位的迭代器。值得一提的是,调用该函数不会扭转容器的大小和容量
clear() 删除 vector 容器中所有的元素,使其变成空的 vector 容器。该函数会扭转 vector 的大小(变为 0),但不是扭转其容量

九、实例

1、拜访 vector 容器中的元素

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

int main()
{
    // 初始化 vector
    std::vector<int> vecInt;
    std::vector<int> vecInt2{3,8,9,6,7,10};
    std::vector<int> vecInt3(10);
    std::vector<int> vecInt4(20, 4);
   
    for (size_t i = 0; i < vecInt.size(); i++)
    {std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "vecInt size:" << vecInt.size() << "capacity:" << vecInt.capacity() << std::endl;

    for (size_t i = 0; i < vecInt2.size(); i++)
    {std::cout << "vecInt2[" << i << "]=" << vecInt2[i] << std::endl;
    }
    std::cout << "vecInt2 size:" << vecInt2.size() << "capacity:" << vecInt2.capacity() << std::endl;

    for (size_t i = 0; i < vecInt3.size(); i++)
    {std::cout << "vecInt3[" << i << "]=" << vecInt3[i] << std::endl;
    }
    std::cout << "vecInt3 size:" << vecInt3.size() << "capacity:" << vecInt3.capacity() << std::endl;

    for (size_t i = 0; i < vecInt4.size(); i++)
    {std::cout << "vecInt4[" << i << "]=" << vecInt4[i] << std::endl;
    }
    std::cout << "vecInt4 size:" << vecInt4.size() << "capacity:" << vecInt4.capacity() << std::endl;

    system("pause");
    return 0;
}

后果如下:

2、vector 容器迭代器的应用

 // 初始化 vector
    std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301};

    //begin、end
    int i = 0;
    std::vector<int>::iterator vecIter = vecInt.begin();
    for (; vecIter != vecInt.end(); vecIter++)
    {std::cout << "begin and end test: vecInt[" << i++ << "]=" << *vecIter << std::endl;
    }


    //rbegin、rend
    i = 0;
    std::vector<int>::reverse_iterator vecIterR = vecInt.rbegin();
    for (; vecIterR != vecInt.rend(); vecIterR++)
    {std::cout << "rbegin and rend test: vecInt[" << i++ << "]=" << *vecIterR << std::endl;
    }

    //cbegin、cend 
    i = 0;
    std::vector<int>::const_iterator vecIterC = vecInt.cbegin();
    for (; vecIterC != vecInt.cend(); vecIterC++)
    {std::cout << "cbegin and cend test: vecInt[" << i++ << "]=" << *vecIterC << std::endl;
    }

    //crbegin、crend
    i = 0;
    std::vector<int>::const_reverse_iterator vecIterCR = vecInt.crbegin();
    for (; vecIterCR != vecInt.crend(); vecIterCR++)
    {std::cout << "crbegin and crend test: vecInt[" << i++ << "]=" << *vecIterCR << std::endl;
    }

后果如下:

3、拜访 vector 容器元素

 // 初始化 vector
    std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301};

    // 下标形式
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //at()形式
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "vecInt[" << i << "]=" << vecInt.at(i) << std::endl;
    }

    // 迭代器形式
    int i = 0;
    std::vector<int>::iterator vecIter = vecInt.begin();
    for (; vecIter < vecInt.end(); vecIter++)
    {std::cout << "iterator vecInt[" << i++ << "]=" << *vecIter << std::endl;
    }

后果如下:

4、往 vector 中插入元素

// 初始化 vector
    std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301};

    // 增加元素
    vecInt.push_back(4301);
    vecInt.emplace_back(910);

    // 下标形式
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "push_back and emplace_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }


    //insert
    vecInt.insert(vecInt.begin(), 72);
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "insert begin vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    vecInt.insert(vecInt.end(), 189);
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "insert end vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    std::array<int, 2> arrayInt{13,15};
    vecInt.insert(vecInt.end(), arrayInt.begin(), arrayInt.end());
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "insert array vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    vecInt.insert(vecInt.end(), {73,98,49});
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "insert array2 vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

后果如下:

5、删除 vector 容器中的元素

  // 初始化 vector
    std::vector<int> vecInt{3,8,9,6,7,10,34,57,981,301,201,701,623,82,201,2909};

    vecInt.pop_back();

    //
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "pop_back vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "pop_back vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //erase
    vecInt.erase(vecInt.begin() + 3);
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "erase vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "erase vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //swap
    swap(*(std::begin(vecInt) + 1), *(std::end(vecInt) - 1));
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "after swap vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "after swap vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;
    vecInt.pop_back();
    
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "after swap rest vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //erase 指定范畴
    vecInt.erase(vecInt.begin() + 2, vecInt.end() - 5);
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "erase appoint vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }

    //remove
    std::remove(vecInt.begin(), vecInt.end(), 3);
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "after remove vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "remove vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

    //clear
    vecInt.clear();
    for (int i = 0; i < vecInt.size(); i++)
    {std::cout << "clear vecInt[" << i << "]=" << vecInt[i] << std::endl;
    }
    std::cout << "clear vecInt size:" << vecInt.size() << "capacity is :" << vecInt.capacity() << std::endl;

后果如下:


阐明:
pop_back:执行后删除了最初一个元素,容器大小 -1,容量不变;
erase:执行后,会返回一个指向删除元素所在位置下一个地位的迭代器,erase 在删除元素时,会将删除地位后续的元素陆续前移,并将容器的大小减 -1;erase 也能够删除指定区域的元素,会返回指向此区域之后一个地位的迭代器;
remove:删除容器中和指定元素值雷同的所有元素,在对容器执行完 remove() 函数之后,因为该函数并没有扭转容器原来的大小和容量,因而借助 remove() 返回的迭代器实现正确的遍历
remove() 的实现原理是:在遍历容器中的元素时,一旦遇到指标元素,就做上标记,而后持续遍历,直到找到一个非指标元素,即用此元素将最先做标记的地位笼罩掉,同时将此非指标元素所在的地位也做上标记,期待找到新的非指标元素将其笼罩。通过 remove() 函数删除掉 demo 容器中的多个指定元素,该容器的大小和容量都没有扭转,其残余地位还保留了之前存储的元素,此时能够应用 erase 清理无用的数据:

vecInt.erase(iter, vecInt.end());

倡议 :remove() 用于删除容器中指定元素后,可应用 erase() 成员函数清理无用数据。
clear:清理容器中所有的元素

退出移动版