C++STL教程之vector模板的使用

目录
  • vector模板类
  • 1. vector模板类
    • 1.1 创建模板类
    • 1.2 STL容器都提供的成员方法
    • 1.3 vector特有的成员方法
    • 1.4 STL容器的非成员方法

vector模板类

STL(标准模板库)提供了容器、迭代器、函数对象、算法的模板。容器是类似于数组的东西,它可以存储若干值,STL容器是同质的,即存储的值的类型相同;迭代器是用来遍历容器的,它和能遍历数组的指针类似,是广义指针;函数对象是类似于函数的对象,可以是类对象和函数指针;算法就是一些能完成特定任务的处方。

我们来看最简单的容器:vector模板类。

1. vector模板类

1.1 创建模板类

在头文件vector中定义了vector模板,我们称之为矢量,它就像是加强版的数组。

创建vector模板对象:

std::vector<int> first;                                // empty vector of ints
std::vector<int> myadd(5);                             //vector of five ints
std::vector<int> second (4,100);                       // four ints with value 100
std::vector<int> third (second.begin(),second.end());  // iterating through second
std::vector<int> fourth (third);                       // a copy of third

一般来说,我们使用前三种方式初始化vector对象,创建好了后数组可以做的它都可以,例如我们可以使用[]随机访问数据。

矢量模板类还支持列表初始化语句

std::vector<int> a{1,2,3,4,5};

1.2 STL容器都提供的成员方法

  • size():返回容器中元素数目
  • swap():交换两个容器的内容
  • begin():返回一个指向容器第一个元素的迭代器
  • end():返回一个表示超过容器尾的迭代器

什么是迭代器?它是一个广义指针。它可以是指针,也可以是一个可对其执行–解除引用operator*()和递增operator++()–的对象。每一个容器类都定义了一个合适的迭代器,它的类型是一个名为iteratortypedef,其作用域是整个类。

我们可以这样声明一个迭代器:
vector<double>::iterator pd;
也可以使用auto关键字:
auto pd=scores.begin();
我们可以使用迭代器pd进行如下操作:

pd=scores.begin();
*pd=22.3;
++pd;
pd++;
--pd;
pd--;

总之迭代器就相当于是指向容器中元素的指针。

什么是超过结尾(past-the-end)?它是一种迭代器,指向容器中最后一个元素后面那个元素。例如在C风格字符串中,字符串的末尾的\0就是超过结尾指向的元素。end()成员函数会返回超过结尾迭代器。
那么我们的遍历可以这样写:

for(pd=scores.begin();pd!=scores.end(),pd++)
    cout<<*pd;
#include<vector>
#include<iostream>
int main()
{
    using std::cout;
    using std::endl;
    using std::vector;
    vector<double> a{1,2,3,4,5};
    vector<double> b{6,7,8};
    cout<<"a size: "<<a.size()<<endl;
    cout<<"b size: "<<b.size()<<endl;
    cout<<"a :";
    for(vector<double>::iterator i=a.begin();i!=a.end();i++)
        cout<<*i<<" ";
    cout<<"\nb :";
    for(vector<double>::iterator i=b.begin();i!=b.end();i++)
        cout<<*i<<" ";
    a.swap(b);
    cout<<"\nafter swap:"<<endl;
    cout<<"a :";
    for(vector<double>::iterator i=a.begin();i!=a.end();i++)
        cout<<*i<<" ";
    cout<<"\nb :";
    for(vector<double>::iterator i=b.begin();i!=b.end();i++)
        cout<<*i<<" ";
}

a size: 5
b size: 3
a :1 2 3 4 5
b :6 7 8
after swap:
a :6 7 8
b :1 2 3 4 5

以上代码是测试了,矢量类的一些接口

实际上还有很多接口:例如empty,front,back;可以直接看cplusplus

1.3 vector特有的成员方法

  • push_back():将元素添加到矢量末尾,而且矢量长度会自动增大
  • erase():删除给定区间内的元素
  • insert():插入指定区间内的元素

push_back()接受一个元素类型的参数,它相当于在矢量的超过末尾的地方加个元素:

vector<double> scores;
double temp=1.23;
scores.push_back(temp);

erase()接受两个迭代器参数,这两个迭代器定义了要删除的区间,第一个迭代器是区间起始处,第二个迭代器是区间终止后的第一个位置,例如a.erase(start,end);是指删除区间[start,end)左开右闭中的元素,而C++中所说的区间都是这种左开右闭的区间。

scores.erase(scores.begin(),scores.begin()+2);

上面这句代码就会删除矢量对象中前两个元素。

insert()会把指定区间里的元素插到一个位置前面。它接受三个迭代器参数,第一个参数指出新元素的插入位置,第二第三就是区间;

vector<int> old_v;
vector<int> new_v;
...
old_v.insert(old_v.begin(),new_v.begin()+1,new_v.end());

上面这段代码会把new_v中除了第一个元素外的所有元素插到old_v的第一个元素的前面。

超尾元素的存在,使得在最后一个元素后面插入元素变得简单:

old_v.insert(old_v.end(),new_v.begin()+1,new_v.end());

#include<vector>
#include<iostream>
int main()
{
    using namespace std;
    vector<int> a;
    a.push_back(1);
    a.push_back(2);
    cout<<"a: ";
    for(auto i=a.begin();i!=a.end();i++)
    cout<<*i;
    cout<<endl;
    vector<int>b{3,4,5,6,7};
    a.insert(a.end(),b.begin(),b.begin()+3);
    cout<<"after insert: ";
    cout<<"a: ";
    for(auto i=a.begin();i!=a.end();i++)
    cout<<*i;
    cout<<endl;
    a.erase(a.begin()+1,a.begin()+3);
    cout<<"after erase: ";
    cout<<"a: ";
    for(auto i=a.begin();i!=a.end();i++)
    cout<<*i;
    cout<<endl;
}

a: 12
after insert: a: 12345
after erase: a: 145

1.4 STL容器的非成员方法

我们会对容器做很多操作,例如搜索,排序。但是这些功能不会放在成员方法中,因为不同的容器类的排序或者搜索方法都是类似的,所以我们为了节省代码,就不会为每个容器单独写这种成员方法。但是,即使存在执行相同任务的非成员函数,STL容器可能也会定义相同的成员方法,例如vectorswap()成员方法比swap()非成员方法效率高,但是非成员函数让您可以交换两个不同类型的容器的内容。

  • for_each():遍历
  • random_shuffle():随机排列
  • sort():排序

这些方法都定义在头文件algorithm中,这就是我们所说的算法。
for_each()接受3个参数,前两个是定义区间的迭代器,最后一个是指向函数的指针(或者说是函数对象)。for_each()将被指向的函数应用于容器间的各个元素。但是for_each()不能修改容器的元素值。我们可以使用它来代替for循环。

for_each(books.begin(),books.end(),foo);//foo是函数名,即函数地址

这个语法很熟悉,很像基于范围的for循环:

double prices[5]={4.99,10.99,6.87,7.99,8.49};
for(double x:prices)
    cout<<x<<endl;
for_each(books.begin(),books.end(),foo);//foo是函数名,即函数地址
//等价于
for(auto x:books) foo(x);

但是基于范围的for循环可以改变容器的内容,我们只需要函数的参数是引用参数foo(int &);
然后我们的代码:

for(auto &x:books) foo(x);

random_shuffle()接受两个指定区间的迭代器,并随机排列区间中的元素,但是random_shuffle()要求容器允许随机访问(即使用books[i]可以直接访问元素)

random_shuffle(books.begin(),books.end());

sort()也要求容器支持随机访问
第一个版本的sort()接受两个指定区间的迭代器,并且使用<运算符对容器中的元素进行升序排列:

vector<int> coolstuff;
...
sort(coolstuff.begin(),coolstuff.end());

这就意味著,如果容器中的元素的类型必须定义operator<()

第二个版本的sort()接受三个参数,它更实用,前两个参数是指定区间的迭代器,第三个参数是函数指针(或函数对象)。这个函数指针指向一个返回bool值,接受两个元素的函数,如果true就说明排序正确,如果false就说明排序错误。

例如我们希望采用降序排列:

bool compare(double db1,double db2)
{
    if(db1<db2)
        return false;
    else
        return true;
}
int main(){
vector<double> a{4.99,10.99,6.87,7.99,8.49};
sort(a.begin(),a.end(),compare);
}

或者直接使用函数对象:

sort(a.begin(),a.end(),greater<double>());

这里使用的greater<double>()就是函数对象,它返回了double类型的大于运算。

#include<vector>
#include<iostream>
#include<algorithm>
void show(const int &a)
{
    std::cout<<a<<" ";
}
bool greater(const int &x,const int &y)
{
    return x>y;
}
int main()
{
    using std::vector;
    using std::random_shuffle;
    using std::sort;
    using std::for_each;
    using std::cout;
    vector<int> a;
    for(int i=0;i<20;i++)
        a.push_back(i);
    cout<<"initial: ";
    for_each(a.begin(),a.end(),show);
    random_shuffle(a.begin(),a.end());
    cout<<"\nafter shaking: ";
    for_each(a.begin(),a.end(),show);
    sort(a.begin(),a.end());
    cout<<"\nAscending: ";
    for_each(a.begin(),a.end(),show);
    sort(a.begin(),a.end(),greater);
    cout<<"\nDescending: ";
    for_each(a.begin(),a.end(),show);
}

initial: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19       
after shaking: 12 1 9 2 0 11 7 19 4 15 18 5 14 13 10 16 6 3 8 17 
Ascending: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19     
Descending: 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

到此这篇关于C++STL教程之vector模板的使用的文章就介绍到这了,更多相关C++ vector模板内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++STL之vector模板类详解

    目录 前言 vector模板类 创建vector对象,遍历元素 迭代器 容器的基本方法 STL函数,sort 总结 前言 STL标准模板库是C++中非常有用的功能库.本篇从vector容器开始学习STL. vector模板类 创建vector对象,遍历元素 vector模板类在头文件vector中,用于存储数组,并采用动态内存分配. 创建一个vector对象并初始化长度,通过[]运算符访问元素: #include <vector> using namespace std; int main()

  • C++标准模板库vector的常用操作

    一:介绍 vector是C++标准模板库,是一个容器,底层是数组,为连续内存. 命名空间为std,所属头文件为<vector>   注意:不是<vector.h> vector存储数据时,会分配一个存储空间,如果继续存储,该分配的空间已满,就会分配一块更大的内存,把原来的数据复制过来,继续存储,这些性能也会一定程度上会有损耗 二:常用操作 容量: a.vector大小:vector.size() b.vector所占内存实际大小:vector.capacity() 修改: a.尾部

  • C++模板以及实现vector实例详解

    目录 函数模板 类模板 Vector实现 简单的类模板实现代码及测试: win msvc编译器的实现: 容器的空间配置器 运算符重载与迭代器实现 最终vector的实现代码 总结 函数模板 函数模板:是不进行编译的,因为类型还不知道 模板的实例化:函数调用点进行实例化 模板函数:才是要被编译器所编译的 模板类型参数:typyname/class 模板非类型参数:模板非类型形参的详细阐述 模板的实参推演:可以根据用户传入的实参的类型,来推导出模板类型参数的具体 模板的特例化(专用化)的实例化 模板

  • C++类模板实战之vector容器的实现

    目录 案例要求 完成步骤 1.封装数组类属性并完成有参构造以及析构函数 2.提供对应的深拷贝构造函数防止调用析构时出错 3.重载类内的赋值运算符防止浅拷贝问题出现 4.提供尾部插入和删除的方法 5.重载[]得到数组中对应下标的数据信息 6.提供get方法获取当前数组容量及大小 7.提供打印函数测试基本数据类型和自定义数据类型的存储 案例要求 可以对内置数据类型以及自定义数据类型的数据进行存储 将数组中的数据存储到堆区 构造函数中可以传入数组的容量 提供对应的拷贝构造函数以及operator=防止

  • C++STL教程之vector模板的使用

    目录 vector模板类 1. vector模板类 1.1 创建模板类 1.2 STL容器都提供的成员方法 1.3 vector特有的成员方法 1.4 STL容器的非成员方法 vector模板类 STL(标准模板库)提供了容器.迭代器.函数对象.算法的模板.容器是类似于数组的东西,它可以存储若干值,STL容器是同质的,即存储的值的类型相同;迭代器是用来遍历容器的,它和能遍历数组的指针类似,是广义指针;函数对象是类似于函数的对象,可以是类对象和函数指针;算法就是一些能完成特定任务的处方. 我们来看

  • AngularJS入门教程之AngularJS 模板

    是时候给这些网页来点动态特性了--用AngularJS!我们这里为后面要加入的控制器添加了一个测试. 一个应用的代码架构有很多种.对于AngularJS应用,我们鼓励使用模型-视图-控制器(MVC)模式解耦代码和分离关注点.考虑到这一点,我们用AngularJS来为我们的应用添加一些模型.视图和控制器. 请重置工作目录: git checkout -f step-2 我们的应用现在有了一个包含三部手机的列表. 步骤1和步骤2之间最重要的不同在下面列出.,你可以到GitHub去看完整的差别. 视图

  • AngularJS入门教程之Helloworld示例

    本文实例讲述了AngularJS入门教程之Helloworld示例.分享给大家供大家参考,具体如下: 什么是AngularJs? angularjs是一个为动态WEB应用设计的结构框架.它能让你使用HTML作为模板语言,通过扩展HTML的语法,让你能更清楚.简洁地构建你的应用组件.它的创新点在于,利用数据绑定和依赖注入,它使你不用再写大量的代码了.这些全都通过浏览器端的javascript实现,这也使得它能够完美地和任何服务器技术结合. AngularJS简单的Helloworld例子: <!D

  • Kotlin基础教程之Run,标签Label,函数Function-Type

    Kotlin基础教程之Run,标签Label,函数Function-Type 在Java中可以使用{}建立一个匿名的代码块,代码块会被正常的执行,除了改变了作用域之外,似乎并没有什么其他的作用.然而在Kotlin中却不能这么做,这是为什么呢? 其实,我们都知道一个函数一定与一个内存地址相关,而一个匿名的代码块其实也相当于是一个匿名的函数.在Kotlin中一般使用run函数来运行一段匿名代码块. 如下: 在Kotlin中使用标识符后跟@符号来定义一个标签,使用@后跟标识符来引用一个标签,run函数

  • php入门教程之Zend Studio设置与开发实例

    本文实例讲述了php入门教程之Zend Studio设置与开发方法.分享给大家供大家参考,具体如下: 新建文档的模板设置 新建文档的模板设置 Demo1.php: <?php echo "阅谁问君诵,水落清香浮." ?> orderform.php: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD

  • JavaWeb基础教程之Java基础加强版

    1.myeclipse的安装和使用 * eclipse:是一个免费的开发工具 * myeclipse:是一个收费的插件,破解myeclipse, ** 安装目录的要求: 不能有中文和空格 ** 安装完成之后,选择一个工作空间 ,这个工作空间不能有中文和空格 * 破解myeclipse ** 运行run.bat文件,但是运行之前,必须要安装jdk,通过配置环境变量 * myeclipse的使用 * 创建一个工程 - 类型 java project web project - 选择依赖的jdk,可以

  • 微信小程序 教程之WXML

    系列文章: 微信小程序 教程之WXSS 微信小程序 教程之引用 微信小程序 教程之事件 微信小程序 教程之模板 微信小程序 教程之列表渲染 微信小程序 教程之条件渲染 微信小程序 教程之数据绑定 微信小程序 教程之WXML WXML WXML(WeiXin Markup Language)是MINA设计的一套标签语言,结合基础组件.事件系统,可以构建出页面的结构. 用以下一些简单的例子来看看WXML具有什么能力: 数据绑定 <!--wxml--> <text> {{message}

  • 微信小程序 教程之WXSS

    系列文章: 微信小程序 教程之WXSS 微信小程序 教程之引用 微信小程序 教程之事件 微信小程序 教程之模板 微信小程序 教程之列表渲染 微信小程序 教程之条件渲染 微信小程序 教程之数据绑定 微信小程序 教程之WXML WXSS WXSS(WeiXin Style Sheets)是MINA设计的一套样式语言,用于描述WXML的组件样式. WXSS用来决定WXML的组件应该怎么显示. 为了适应广大的前端开发者,我们的WXSS具有CSS大部分特性. 同时为了更适合开发微信小程序,我们对CSS进行

  • Zend Framework教程之Zend_Helpers动作助手ViewRenderer用法详解

    本文实例讲述了Zend Framework教程之Zend_Helpers动作助手ViewRenderer用法.分享给大家供大家参考,具体如下: MVC结构中视图层和控制器的解耦,以及渲染.往往是重复或者冗余的工作.如果一个完善的框架,对MVC的使用,必定会对这些操作进行合理的设计.让开发者更专注内容而不是控制逻辑结构本身.在ZendFramework中,主要是通过动作助手ViewRenderer来完成这个操作的.ViewRenderer 自动的完成在控制器内建立视图对象并渲染视图的过程: Vie

随机推荐