C++ STL使用的一点总结

最近正好做到这道题目1071 Speech Patterns,题目本身没有什么算法思想,但是却很灵活的使用到了STL。之前刷完了PAT的Basic Level后,的确感觉自己在STL的使用上熟练了很多。学会灵活的使用STL,真得让代码简洁了不少呢~~~,做题思路也更清晰了(),所以今天就来总结一下我做的一些算法题中常常用到的STL和容器和方法o( ̄︶ ̄)o
就从1071 Speech Patterns这道题目说起,这是我ac的代码:

#include<iostream>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
bool cmp(const pair<string,int> &a,const pair<string,int> &b)
{
    return a.second==b.second?a.first<b.first:a.second>b.second;
}
int main()
{
     int i,j;
     string speech,word;
     getline(cin,speech);
     map<string,int> mp;
     for(i=0;i<speech.length();i++)
     {
 	    if(!isalnum(speech[i]))
 	        continue;
 	    j=i+1;
         while(isalnum(speech[j]))
             j++;
         word=speech.substr(i,j-i);
         transform(word.begin(),word.end(),word.begin(),::tolower);
         mp[word]++;
         i=j-1;
     }
     vector<pair<string,int>> vec(mp.begin(),mp.end());
     sort(vec.begin(),vec.end(),cmp);
     printf("%s %d",vec[0].first.c_str(),vec[0].second);
     return 0;
 }

这段代码中涉及到了很多很实用的方法~~~
下面是我的一丢丢总结 (ง •̀_•́)ง

  1. 判断字符是否是数字、字母、数字+字母
    isalpha( )
    isdigit( )
    isalnum( )

  2. 字符串、字符转换成数字
    stof( )
    atof( )
    所在头文件:cmath

  3. transform( )函数的使用
    大小写转换的方法只能针对字符而言,要想直接对字符串进行操作,就需要使用transform( )方法
    函数模板原型如下:

    template < class InputIterator, class OutputIterator, class UnaryOperator > 
       OutputIterator transform ( InputIterator first1,  // 源容器的起始地址 
                                 InputIterator last1,    // 源容器的终止地址 
                                 OutputIterator result,  // 目标容器的起始地址 
                                 UnaryOperator op );     // 函数指针 
    

transform最经常使用到的就是大小写转换了:

string str;
//函数前面的::一定不能省略了(`・ω・´)
transform(str.begin( ),str.end( ),str.begin( ),::toupper);
transform(str.begin( ),str.end( ),str.begin( ),::tolower);
  1. 对map按value排序
    对map是不能直接使用sort( )函数进行排序的,要想对map按照value排序,得先把map放进vector中,再按照指定的排序方法,对vector排序
    !!!还有map本身就是按照key的顺序排序的,并不是按照插入的顺序排序的(,,•́ . •̀,,)
    那么再将map放入vector中时要使用pair,pair是将两个值,组合成一个数据,pair的两个成员变量first,second。
    将map放入vector中:

     //写法一
     vector<pair<string,int>> vec;
     map<string,int> mp;
     for(map<string,int>::iterator it=mp.begin( );it!=mp.end( ),it++)
         vec.push_back(make_pair(it->first,it->second);
    
    //写法二
     vector<pair<string,int>> vec(mp.begin( ),mp.end( ));
    
  2. 函数参数尽量写成const &的形式
    函数参数如果不改变值的情况下,尽量写成const &的形式,尤其是cmp这类排序方式的函数中,是可以达到加快排序速度的效果的~~~~
    关于const &形式的参数,之前在看C++primer plus的时候,这里面花了很多篇幅说了这个问题,大家有兴趣可以去看一看(。◕ˇ∀ˇ◕)
    下面是一点点这方面当时看书时做的笔记:
    对于使用传递的值而不做修改的函数:

    • 如果数据对象很小,如内置数据类型或小型结构,则按值传递。
    • 如果对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针。
    • 如果数据对象是较大的结构,则使用const 指针或const引用,以提高程序的效率。
    • 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是c++增加这个特性的主要原因,因此传递类对象标准方式是按引用传递。
  3. unordered_map和map的区别
    我做PAT上的题目时,遇到过不少次因为一个测试点运行超时而不能AC的情况,除了算法复杂度的问题外。最坑的是这些地方o(╥﹏╥)o,花了好久的时间找测试点不过的原因,最后发现把所有的cin和cout换成scanf和printf就ac了,还有这种把map换成unordered_map就ac了的情况。
    那么unordered_map和map在速度上到底有什么区别呢?
    传统的map内部的结构是红黑树,那么查找的时候实际上是二分查找,而且红黑树的每个节点都要存储其父节点、子节点以及自身的红黑性质,造成传统map占用内容较多,空间利用率不高。而unodered_map内部维护的结构是hash表,所以查找起来速度自然就要快~~~
    所以当涉及到大数据的查找问题时,就要考虑使用unordered_map了

  4. 迭代器的使用
    说到STL容器,怎么能不说迭代器呢?
    以vector为例,用迭代器进行遍历
    正向迭代器:

    vector<int> vec;
    for(vector<int>::iterator it=vec.begin();vector!=vec.end();it++)
    

反向迭代器:

for(vector<int>::reverse_iterator riter=vec.rbegin();vector<vec.rend();riter++)

C++11在循环遍历时新增了一个特性就是使用auto,我觉得这个比iterator使用起来更简单一些~~
所以我现在一般都用auto,不过要注意一下,iterator it和auto it在使用上还是有区别的,迭代器的it: it->first,但是auto it: it.first
事实上,auto遍历比迭代器的效率要高一些的,所以可以尽量考虑用auto

  1. set容器
    set容器在查找方面是很有用的~,其内部实现的数据结构是红黑树,插入、删除、查找都比vector快
    set我最常用到的就是find( )函数了,find( )返回一个指向被查找到元素的迭代器,所以如果查找不到的话,返回的是end( )

好了,暂时就说这么多啦(o)/~

原文地址:https://www.cnblogs.com/CuteyThyme/p/11820391.html