第二章 C++ STL 泛型编程 1

作者: Nautilus1 | 来源:发表于2017-11-12 16:22 被阅读0次

一、STL 概述

STL——C++标准模板库,定义了常用的数据结构和算法。提供三种类型的组件:容器、迭代器和算法

  1. 容器分为顺序和关联两种:
  • 顺序容器:vector 、list、deque、string等是一系列元素的有序集合
  • 关联容器:set、multiset、map、multimap包含查找元素的键值。
  1. 迭代器用于遍历容器。

  2. 算法库包含四类:排序、不可变序、变序和数值算法。

遍历vector向量并统计其中元素之和的程序示例:

#include <vector>
#include <iostream>
#include <algorithm>
#include <numeric>       //accumulate算法需要
using namespace std;

int main()
{
    vector<int> v;
    int i;
    for (i = 0; i < 10; i ++)
        v.push_back(i);

    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
        cout << *it <<" ";
    cout<<endl;
    cout<<accumulate(v.begin(),v.end(),0) <<endl;
    return 0;
}

二、vector向量容器

vector可以像数组一样随机访问元素,而且有内存自动管理功能,对元素的插入删除可动态调整所占内存。有三种创建方式:

  1. 不指定元素个数:
vector<int> v;
  1. 创建时指定容器大小,下标0~9,每个元素的值初始为0.0
vector<double> v(10);
  1. 创建有n个元素的vector,每个元素有指定的初始值
vector<double> v(10, 8.6);

基本函数

  • begin():返回首元素位置的迭代器

  • end():返回最后一个元素的下一个位置的迭代器

  • size():返回向量的大小,即元素个数

  • empty():返回向量是否为空

  • push_back(): 在尾部追加元素

  • insert(): 在任意位置前插入一个新元素,就是占位于这个位置,原来此位置及以后的元素后移一位

  • erase(): 删除vector中迭代器所指的一个元素或一段区间中的所有元素

  • clear():一次性删除vector中的所有元素

  • reverse():将向量中某段迭代器区间元素反向排列

  • sort():要求使用随机访问迭代器排序,默认按升序排。可自定义比较函数定义排序规则。

#include <vector>
#include <iostream>
#include <algorithm>
#include <numeric>       //accumulate算法需要
using namespace std;

//自定义比较函数使降序排序
bool cmp(const int &a, const int &b)
{
    if (a != b) return a > b;
    return a > b;
}

//使用迭代器访问元素,迭代器的类型要与遍历的vector对象的元素类型一致
void Print(vector<int> v)
{
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
        cout << *it <<" ";
    cout<<endl;
}

int main()
{
    vector<int> v;
    int i;
    for (i = 0; i < 10; i ++)
        v.push_back(i);

    cout <<"初始时vector元素"<<endl;
    Print(v);

    v[6] = 12;           //使用下标赋值
    cout << v[6]<<endl; //使用下标访问元素

    v.insert(v.begin(), 11);              //在最前面插入11
    v.insert(v.end(), 13);                //末尾追加13,效果同v.push_back(13)
    v.insert(v.begin() + 2, 16);          //在第二个位置插入16,即v[2] = 16
    cout <<"插入后vector元素"<<endl;
    Print(v);

    v.erase(v.begin() + 2);        //删除v[2]
    v.erase(v.begin() + 1, v.begin() + 4);    //删除v[1] ~ v[3]共3个元素
    cout <<"删除后vector元素"<<endl;
    Print(v);

    sort(v.begin(), v.end());
    cout <<"排序后vector元素"<<endl;
    Print(v);

    sort(v.begin(), v.end(), cmp);
    cout <<"降序排序后vector元素"<<endl;
    Print(v);

    reverse(v.begin(), v.end());
    cout <<"反向排列后vector元素"<<endl;
    Print(v);

    cout << v.size() <<endl;       //输出向量大小
    v.clear();                     //清空向量
    cout << v.empty() <<endl;     //输出向量是否为空

    return 0;
}

auto关键字
auto是C++11新引入的类型说明符,让编译器分析表达式所属的类型,用于从初始化表达式中推断出变量的数据类型。所以auto定义的变量必须要有初始值。有以下好处:

  • 可靠性:如果表达式的类型发生更改(包括函数返回值发生更改的情况),它也能工作。
  • 性能:确保将不会进行转换。
  • 方便:不必担心类型名称拼写困难和拼写有误。
  • 效率高:代码会变得更高效。
//  auto a;                 // 错误,没有初始化表达式,无法推断出a的类型  
//  auto int a = 10;        // 错误,auto不能与其他类型组合连用
  
    // 1. 自动帮助推导类型  
    auto a = 10;  
    auto c = 'A';  
    auto s("hello");  
  
    // 2. 类型冗长  
    map<int, map<int,int> > map_;  
    map<int, map<int,int>>::const_iterator itr1 = map_.begin();  
    const auto itr2 = map_.begin();  
    auto ptr = []()  
    {  
        std::cout << "hello world" << std::endl;  
    };  
    return 0;  
};  
  
// 3. 使用模板技术时,如果某个变量的类型依赖于模板参数,  不使用auto将很难确定变量的类型(使用auto后,将由编译器自动进行确定)。  
template <class T, class U>  
void Multiply(T t, U u)  //函数和模板参数不能被声明为auto
{  
    auto v = t * u;  
}  

//4. 不能用于类型转换或其他一些操作,如sizeof和typeid
int value = 123;  
auto x2 = (auto)value; // 不能用 auto 转换  
auto x3 = static_cast<auto>(value); // 错误同上

//5. 定义在一个auto序列的变量必须始终能被推导成同一类型
auto x1 = 5, x2 = 5.0, x3='r';  //错误

三、string基本字符系列容器

string可理解为字符串类,其对象的元素是字符。提供了增删改查比较等多种函数。

  • 赋值两种形式: 直接给字符串;赋字符指针

  • 尾部追加字符/字符串: 用“+”或者s.append()。注意字符串要用“”。

  • inset():将一个字符插入到迭代器位置之前

  • erase():删除迭代器所指的元素或一个区间中所有元素

  • length():返回字符串长度

  • empty():返回字符串是否为空

  • replace():替换string对象中的字符

  • find():查找字符串中的第一个字符元素或子串,返回下标值或最大整数值,以下测试出的是64位

  • compare():字符串比较,若比对方大返回1,小返回-1,相等返回0

  • reverse():反向排序string对象,需加头文件algorithm

string对象也可作为vector的元素,类似于字符串数组。

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

int main()
{
    //创建字符串对象,直接赋值并输出字符串长度
    string s;
    s = "hello, STL";
    cout <<"hello, STL的长度为:" << s.length()<<endl;

    //使用字符指针赋给字符串对象
    char ch[100];
    scanf("%s", ch);     //scanf输入速度比cin快得多,但不支持string对象
    s = ch;              //整个字符数组赋给string对象
    cout <<"输入的字符串为:" << s << endl;

    s = s + '1';         //直接用‘+’在尾部添加字符
    s = s + "+-";        //尾部追加字符串要用 ""
    s.append("***");     //尾部追加字符串
    cout <<"追加后的字符串为:" << s << endl;

    string::iterator it;  //定义迭代器
    it = s.begin();
    s.insert(it + 1, '?');  //将'?'插入到s[1]
    cout <<"插入‘?’后的字符串为:" << s << endl;

    cout <<"首字符比‘a’大:" << s[0] - 'a' << endl;

    s.erase(it + 2);           //删除s[2]
    s.erase(it, it + 4);       //删除s[0] ~ s[3]共4个元素
    cout <<"删除后字符串为:" << s<< endl;

    s = "";                    //清空
    cout <<"字符串是否为空"<<s.empty()<<endl;

    s = "abc123456";
    s.replace(3,3,"good");      //从第3个开始,将连续的3个字符替换为good
    cout <<"替换后字符串为:" << s<< endl;

    cout <<"字符串中第一个o的位置" <<s.find('o')<<endl;
    cout <<"字符串中good的位置" <<s.find("good")<<endl;
    cout <<"字符串中dog的位置,找不到则返回最大正整数值" <<s.find("dog")<<endl;

    //字符串比较,比对方大则返回1,小返回-1,相等返回0
    cout <<"与bcd比较:" <<s.compare("bcd")<<endl;
    cout <<"与自己比较:" <<s.compare("abcgood456")<<endl;
    cout <<"与aaaaa比较:" <<s.compare("aaaaa")<<endl;

    s = "1234567";
    reverse(s.begin(), s.end());
    cout <<"翻转后的字符串为:"<<s <<endl;

    vector<string> v;
    v.push_back("yeah");
    v.push_back("nope");
    v.push_back("great");
    cout << v[2] <<endl;
    cout << v[1][0] <<endl;
    cout << v[0].length()<<endl;
    return 0;
}
  • string 类型的数字化处理
    分离读入的数字的每位时,若用取余法效率较低,而且对于大数字也只能作为字符串处理输入。

  • string 对象与字符数组互操作

    string s;
    char ss[100];
    scanf("%s",  ss);       //空格作为终止符不会被读入
    s = ss;
    printf(s.c_str());        //用 printf 输出字符串对象要用 c_str() 方法
    cout<<endl;
    printf("%s", ss);
  • string 对象与 sscanf 函数
    C语言中 sscanf 用于将一个字符串按需要的方式分离出子串
    string s1, s2, s3;
    char sa[100], sb[100], sc[100];
    sscanf("abc 123 pc", "%s %s %s", sa, sb, sc);
    s1 = sa;
    s2 = sb;
    s3 = sc;
    cout<<s1 <<" "<<s2<<" "<<s3<<endl;

    int a, b, c;
    sscanf("1 2 3", "%d %d %d", &a, &b, &c);
    cout<<a <<" "<<b<<" "<<c<<endl;

    sscanf("4,5$6", "%d,%d$%d", &a, &b, &c);
    cout<<a <<" "<<b<<" "<<c<<endl;
  • string 对象与数值相互转换
#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
using namespace std;

//将数值转化为string
string convertToString(double x)
{
    ostringstream o;
    if (o << x)
        return o.str();
    return "conversion error";
}

//将string转换为数值
double convertFromString(const string &s)
{
    istringstream i(s);
    double x;
    if (i >> x)
        return x;
    return 0;     //若出错
}

int main()
{
    //将数值转化为string的C方法
    char b[10];
    string a;
    sprintf(b, "%d", 1975);
    a = b;
    cout<< a <<endl;

    //将数值转化为string的C++方法
    string cc = convertToString(1976);
    cout << cc<< endl;

    //将string转换为数值的C++方法
    string dd = "2006";
    int p = convertFromString(dd) + 2;
    cout << p <<endl;
    return 0;
}

实际上就是

    ostringstream o;
    int x = 123;
    o << x;
    cout<<o.str()<<endl;

    istringstream i("456");
    i >> x;
    cout<<x<<endl;

//输出123       456

相关文章

网友评论

    本文标题:第二章 C++ STL 泛型编程 1

    本文链接:https://www.haomeiwen.com/subject/fulduxtx.html