C++ std::vector的初始化、遍历、插入、删除

作者: admin 分类: C++ 发布时间: 2020-01-31 13:50

【一】vector

删除元素

Std::vector<int> exampleVec = {1,2,3,4,5,6,7};

1. iterator erase( const_iterator pos )  //移除位于 pos 的元素

【注意点】:

(1)迭代器 pos 必须合法且可解引用。所以不能以 end() 迭代器为 pos 的值(合法,但不可解引用),不然会抛异常。

    比如:exampleVec.erase(exampleVec.end()); —–>程序向你抛出一个大大的异常,并且崩溃了

2. iterator erase( const_iterator first, const_iterator last )  //移除范围 [first; last) 中的元素

【注意点】:

(1) 若 first==last ,则迭代器 first 不必可解引用:

        比如:exampleVec.erase(exampleVec.end(), exampleVec.end());  —>合法的。原因参看下面第2点

(2) 擦除空范围是无操作。

   比如:exampleVec.erase(example.begin(),exampleVec.begin());   —->无任何操作,元素还是1,2,3,4,5,6,7

 

【返回值】:erase操作的返回值均为最后删除元素的下一个元素的迭代器,如果被删除的元素是最后一个元素,则返回的是end()迭代器。

【删除元素迭代器失效问题】

因为删除元素后,会导致该元素的迭代器失效,所以对vector循环遍历删除某些元素的时候,可能会有迭代器失效问题从而导致程序崩溃。

正确的做法是利用erase的返回值解决问题。下面是正确的示例,该示例演示删除vector中所有的奇数元素。

for (auto beg = exampleVec .begin(); beg != exampleVec .end();)  //不是在这里对beg++

{

        if (*beg % 2 != 0)

        {

                beg = exampleVec .erase(beg);  //在这里获取下一个元素

        }

        else

            ++beg;

程序输出:2,4,6

 

插入元素

1. iterator insert( const_iterator pos, const T& value );  //在 pos 前插入 value

【注意点】:

(1) pos 可为 end() 迭代器

比如: exampleVec.insert( exampleVec.end(),8)  —>正确,则现在元素为:1,2,3,4,5,6,7,8

 

【返回值】:insert操作的返回值都为第一个插入元素的迭代器。

 

【插入元素迭代器失效问题】

因为插入元素后,后面的元素移动或者当前容量不够存放元素时候进行容量扩展的时候,迭代器会失效,所以对vector循环遍历插入某些元素时候,可能会有迭代器失效问题从而导致程序崩溃。

正确的做法也是利用insert的返回值。下面是正确的示例,该示例演示在vector中所有偶数元素后面插入一个数100。

for (auto beg = vec.begin(); beg != vec.end();++beg)

{

        if (*beg % 2 == 0)

        {

            beg = vec.insert(++beg,100);         //如果仅仅写成vec.insert(++beg,100);则程序崩溃       

                                                                    //因为插入后,beg已经失效,再次进入循环时候++beg则异常崩溃

        }

程序输出:1,2,100,3,4,100,5,6,100,7

总结:关于插入删除迭代器失效的问题,c++11中都使用插入/删除的返回值来获取正确的返回值。以上代码都经过vs2017测试运行。最后吐槽一下,网上好多博客内容都是一本正经的胡说。

————————————————

版权声明:本文为CSDN博主「帝江VII」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:

https://blog.csdn.net/qq_31175231/article/details/80854057

使用vector,必须加上:#include <vector>

 

1.初始化vector,一般有这几种方式:

 

    std::vector<std::wstring> v1;                //创建一个空的wstring类型的vector

    std::vector<std::wstring> v2(3, L"c");       //创建一个容量为3,全部初始化L"c"

    std::vector<int> v3(5);                      //创建容量为5,数据类型为int的vector

    std::vector<int> v4(v3);                     //创建一个从v3拷贝过来的vector

    std::vector<int> v5 = {1,2,3,4,5,6,7};       //C++11才支持,直接值初始化,最方便

 

第五种方法:  vector<int> v5{1,2,3.0,4,5,6,7};

v5初始化为列表中元素的拷贝,列表中元素必须与v5的元素类型相容,本例中必须是与整数类型相容的类型,整形会直接拷贝,其他类型会进行类型转换

 

 

 

 

 

2.在指定位置插入元素:

v2.insert(v2.begin()+4, L"3");   //在指定位置,例如在第五个元素前插入一个元素

 

v2.insert(v2.end(), L"3");   //在末尾插入一个元素

 

v2.push_back(L"9");   //在末尾插入一个元素

 

v2.insert(v2.begin(), L"3");   //在开头插入一个元素

 

 

 

 

 

3.删除数据:

   v2.erase(v2.begin()); //删除开头的元素

 

   v2.erase(v2.begin(),v2.end); //删除[begin,end]区间的元素

 

   v2.pop_back();   //删除最后一个元素

 

 

 

 

 

 

   函数                                   说明

 

c.assign(beg,end)            //将[beg; end)区间中的数据赋值给c。

 

c.assign(n,elem)             //将n个elem的拷贝赋值给c。

    

c.at(idx)                    //传回索引idx所指的数据,如果idx越界,抛出out_of_range。

    

c.back()                     //传回最后一个数据,不检查这个数据是否存在。

    

c.begin()                    //传回迭代器中的第一个数据地址。

    

c.capacity()                 //返回容器中数据个数。

    

c.clear()                    //移除容器中所有数据。

    

c.empty()                    //判断容器是否为空。

 

c.end()                      //指向迭代器中的最后一个数据地址。

 

c.erase(pos)                 //删除pos位置的数据,传回下一个数据的位置。

 

c.erase(beg,end)             // 删除[beg,end)区间的数据,传回下一个数据的位置。

 

c.front()                    //传回第一个数据。

    

get_allocator                //使用构造函数返回一个拷贝。

    

c.insert(pos,elem)           //在pos位置插入一个elem拷贝,传回新数据位置。

 

c.insert(pos,n,elem)         //在pos位置插入n个elem数据。无返回值。

 

c.insert(pos,beg,end)        //在pos位置插入在[beg,end)区间的数据。无返回值。

    

c.max_size()                 //返回容器中最大数据的数量。

    

c.pop_back()                 //删除最后一个数据。

    

c.push_back(elem)            //在尾部加入一个数据。

 

c.rbegin()                   //传回一个逆向队列的第一个数据。

    

c.rend()                     //传回一个逆向队列的最后一个数据的下一个位置。

 

c.resize(num)                //重新指定队列的长度。

 

c.reserve()                  //保留适当的容量。

 

c.size()                     //返回容器中实际数据的个数。

 

c1.swap(c2)                  //将c1和c2元素互换。

 

swap(c1,c2)                  //同上操作。

    

vector<Elem> c               //创建一个空的vector。

 

vector<Elem> c1(c2)          //复制一个vector。

 

vector <Elem> c(n)           //创建一个vector,含有n个数据,数据均已缺省构造产生。

 

vector <Elem> c(n, elem)     //创建一个含有n个elem拷贝的vector。

 

vector <Elem> c(beg,end)     //创建一个以[beg;end)区间的vector。

 

c.~ vector <Elem>()          //销毁所有数据,释放内存。

    

operator[]                   //返回容器中指定位置的一个引用。

 

————————————————

版权声明:本文为CSDN博主「Bird鸟人」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/wcc27857285/article/details/77855196

Vector元素的遍历和修改

转载WangEason1985 最后发布于2018-10-29 00:58:58 阅读数 1778  收藏

展开

https://blog.csdn.net/the_lastest/article/details/70162729

 

/*************************************************************************

    > File Name: vector.cpp

    > Author: 

    > Mail: 

    > Created Time: Thu 13 Apr 2017 08:57:25 PM CST

 ************************************************************************/

#include<iostream>

#include<vector>

using namespace std;

int main()

{

    vector<int> ivec;

    for(int i = 0; i < 10; ++i)

        ivec.push_back(i);

    //遍历vector元素

    //1: 利用迭代器

    for(auto it = ivec.begin(); it != ivec.end(); ++it)

        cout<<*it<<" ";

    cout<<endl;

    //2: 利用下标操作符

    for(auto i = 0; i < ivec.size(); ++i)

        cout<<ivec[i]<<" ";

    cout<<endl;

    //3: 利用范围for循环

    for(auto i : ivec)

        cout<<i<<" ";

    cout<<endl<<endl;

    //修改vector中的元素(前提条件是vector中已有元素,且以下方式均不能改变已有元素的个数)

    //1: 利用迭代器

    for(auto it = ivec.begin(); it != ivec.end(); ++it)

    {

        *it = *it * 2;

        cout<<*it<<" ";

    }

    cout<<endl;

    //2: 利用下标操作符

    for(auto i = 0; i < ivec.size(); ++i)

    {

        ivec[i] = ivec[i] * 2;

        cout<<ivec[i]<<" ";

    }

    cout<<endl;

    //3: 利用范围for循环

    for(auto &i : ivec)//注意此处是引用

    {

        i = i * 2;

        cout<<i<<" ";

    }

    cout<<endl;

    return 0;

}

——————— 

作者:亡城 

来源:CSDN 

原文:https://blog.csdn.net/the_lastest/article/details/70162729 

版权声明:本文为博主原创文章,转载请附上博文链接!

vector::erase() vector中如何删除元素?

转载那年聪聪 最后发布于2016-02-22 16:38:56 阅读数 66090  收藏

展开

vector::erase():从指定容器删除指定位置的元素或某段范围内的元素

vector::erase()方法有两种重载形式

如下:

1、iterator erase(iterator _Where);

v1.erase( v1.begin( ) );//删除v1中的第一个元素

vec.erase(vec.begin()+2);删除第3个元素

2、iterator erase(iterator _First,iterator _Last);

    //删除v1.begin() + 1和v1.begin() + 2两个元素

v1.erase(v1.begin() + 1, v1.begin() + 3);

vec.erase(vec.begin()+i,vec.begin()+j);删除区间[i,j-1];区间从0开始

插入元素:vec.insert(vec.begin()+i,a);在第i+1个元素前面插入a;

如果是删除指定位置的元素时:

返回值是一个迭代器,指向删除元素下一个元素;如果是删除某范围内的元素时:返回值也表示一个迭代器,指向最后一个删除元素的下一个元素;

#include "stdafx.h"

#include <cv.h>

#include <vector> 

#include <iostream> 

using namespace std;

int main()

{

using namespace std;

vector <int> v1;

vector <int>::iterator Iter;

v1.push_back(10);

v1.push_back(20);

v1.push_back(30);

v1.push_back(40);

v1.push_back(50);

cout << "v1 =";

for(Iter = v1.begin(); Iter != v1.end(); Iter++)

cout << " " << *Iter;

cout << endl;

v1.erase(v1.begin());//删除v1的第一个元素

cout << "v1 =";

for(Iter = v1.begin(); Iter != v1.end(); Iter++)

cout << " " << *Iter;

cout << endl;

//删除v1.begin() + 1和v1.begin() + 2两个元素

v1.erase(v1.begin() + 1, v1.begin() + 3);

cout << "v1 =";

for(Iter = v1.begin(); Iter != v1.end(); Iter++)

cout << " " << *Iter;

cout << endl;

}

v1.erase( v1.begin( ) );//删除v1中的第一个元素

erase的原理,当调用erase()后Iter迭代器就失效了,变成了一野指针。

所以要处理这种问题,关键是要解决调用erase()方法后,Iter迭代器变成野指针的问题,

这个时候呢给他赋一个新的迭代器给他。

for(Iter = v1.begin(); Iter != v1.end(); Iter++) 

  if(*Iter == 10) 

  { 

      v1.erase(Iter);

     Iter = v1.begin(); //当erase后,旧的容器会被重新整理成一个新的容器

  } 

}

重新Iter迭代器指定下一个元素。

上面那种方法是给Iter重新赋于新v1的begin迭代器。

还有一种方法是直接赋删除元素的下一个迭代器给Iter

实现方法的代码如下:

for(Iter = v1.begin(); Iter != v1.end(); Iter++) 

  if(*Iter == 10) 

  { 

   Iter = v1.erase(Iter);//Iter为删除元素的下一个元素的迭代器

  //即第一次这段语句后Iter 会是20,大家可以通过debug调试出来查看下数值

  } 

 

  if(Iter == v1.end()) //要控制迭代器不能超过整个容器

  { 

   break;

  } 

}

std::vector中swap()函数使用解析以及去重复操作

原创欧特GO 最后发布于2019-08-26 09:59:34 阅读数 552  收藏

展开

1、常用方式,交换vector内部的两个元素

int main(int argc, char* argv[])

{

std::vector<string> sentence;

sentence.push_back("hello");

sentence.push_back("how");

sentence.push_back("are");

sentence.push_back("you");

sentence.push_back("csdn");

swap(sentence[0] ,sentence[4] );

return 0;

}

2、利用swap()函数进行内存的释放

1)简单介绍

 在vector的数据结构中:

  .clear();清空数据

  .size();当前vector容器内存储的元素的个数

  .capacity();当前vector容器重新分配内存之前所能容纳的元素数量

  .swap();函数交换

  .reserve();向系统预订一段足够的连续的空间

2) 释放内存

  首先,vector与deque不同,其内存占用空间只会增长,不会减小。比如你首先分配了10,000个字节,然后erase掉后面9,999个,则虽然有效元素只有一个,但是内存占用仍为10,000个。所有空间在vector析构时回收。

  在用vector时,输入完一组数据处理完后,调用clear()进行清理,如果此时打印vector[0],会发现仍然输出之前vector所存的内容,但是如果调用.empty()函数又会返回1,告诉我们这个容器现在是空的,什么原因? 这是因为使用.clear()清空内容,但是没有释放内存的原因。举例如下:

#include <iostream>

#include <vector>

using namespace std;

int main()

{

vector <int >a;

cout<<a.empty()<<endl;//输出   1  代表该vector此时是空

a.push_back(1);

a.push_back(2);

cout<<a[0]<<" "<<a[1]<<endl;//输出1 2

cout<<a.empty()<<endl;//输出 0 代表该vector此时非空

cout<<a.size()<<endl;//输出2

cout<<a.capacity()<<endl;//输出2

cout<<"***************"<<endl;

 

//a[0]=NULL;a[1]=NULL; 这是赋值为0,并不清空数据,也不释放内存。

a.clear();

cout<<a[0]<<" "<<a[1]<<endl;//仍然输出1 2,因为没有释放内存,所以输出该地址的内容仍然与之前一样

cout<<a.empty()<<endl;//输出1  代表该vector此时已经为空

cout<<a.size()<<endl;//输出0,代表当前容器内存储元素个数是0,与.empty()类似,都告诉我们当前容器是空的意思

cout<<a.capacity()<<endl;//输出2,代表当前该vector在重新分配存储空间前所能容纳的元素数量并没有改变

cout<<"***************"<<endl;

 

/*

下面这五行说明,.pop_back()与.clear()起到了相同的作用,都是清空数据,但是没有释放内存

while(!a.empty()){

a.pop_back();

}

cout<<a.empty()<<endl;//输出 1 代表该vector此时已经为空

cout<<a[0]<<" "<<a[1]<<endl;//仍然输出为 1 2,因为没有释放内存,所以输出该地址的内容仍然与之前一样

*/

a.push_back(4);

cout<<a[0]<<" "<<a[1]<<" "<<a[2]<<endl;//输出 4 2 0   尽管没有释放内存,但是已经认为该vector已经被清空,所以再push_back();时,a[0]被覆盖。

cout<<a.size()<<endl;//输出1,代表当前容器内存储元素个数是1,就是刚刚push_back();装进去的数起到的作用

cout<<a.capacity()<<endl;//此时仍然输出2

cout<<"***************"<<endl;

  在《effective STL》和其实很多C++文章中都有指明,用clear()无法保证内存回收。但是swap技法可以。 那么如何释放内存呢?我们用swap交换到一个新的类型的vector,将原来的a拷贝出去,然后自然销毁,而新的到的a是全新的没有存任何数据的。

具体方法如下所示:

vector<int>().swap(a);

//或者如下所示 加一对大括号都可以,意思一样的:

{

 std::vector<int> tmp;   

 ivec.swap(tmp);

}     

//加一对大括号是可以让tmp退出{}的时候自动析构

cout<<a.size()<<endl;//输出 0

cout<<a.capacity()<<endl;.// 输出 0

//cout<<a[1]<<endl;

3) 修整空间

  在一个应用中,可能会需要向一个vector中插入很多记录,比如说100000条,为了避免在插入过程中移动内存,咱实现向系统预订一段足够的连续的空间,例如

vector<int> ivec;

ivec.reserve(100000);

  这个问题是解决了。但是如果后来这个vector不再需要存那么多的元素了,已经通过erase删除了。但是以前咱们预留的空间却无法被其他程序再度利用,这样会造成内存一定程度上的浪费。于是,我们利用目前的vector构造一个一模一样的vector,他并没有预留空间,于是以前预留的空间也被释放以作他用了:

ivec.swap(vector<int>(ivec)); 

// or vector<int>(ivec).swap(ivec)

或者如下所示 加一对大括号都可以,意思一样的:

  {

     std::vector<int> tmp = ivec;   

     ivec.swap(tmp);

    }     

  加一对大括号是可以让tmp退出{}的时候自动析构;使用这种方法的前提是vector从前存储了大量数据,比如10000000,经过各种处理后,现在只有100条,那么向清空原来数据所占有的空间,就可以通过这种交换技术swap技法就是通过交换函数swap(),使得vector离开其自身的作用域,从而强制释放vector所占的内存空间。

对于容器的去重复操作类似:

std::vector<int> ModuleArr;

//排序

std::sort(ModuleArr.begin(), ModuleArr.end());

//去重

ModuleArr.erase(unique(ModuleArr.begin(), ModuleArr.end()), ModuleArr.end());

————————————————

版权声明:本文为CSDN博主「欧特GO」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/m0_37251750/article/details/100071023

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表评论

标签云