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

一、STL 概述

STL——C++標(biāo)準(zhǔn)模板庫牡辽,定義了常用的數(shù)據(jù)結(jié)構(gòu)和算法粒氧。提供三種類型的組件:容器越除、迭代器和算法

  1. 容器分為順序和關(guān)聯(lián)兩種:
  • 順序容器:vector 外盯、list摘盆、deque、string等是一系列元素的有序集合
  • 關(guān)聯(lián)容器:set饱苟、multiset孩擂、map、multimap包含查找元素的鍵值箱熬。
  1. 迭代器用于遍歷容器类垦。

  2. 算法庫包含四類:排序、不可變序坦弟、變序和數(shù)值算法护锤。

遍歷vector向量并統(tǒng)計其中元素之和的程序示例:

#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可以像數(shù)組一樣隨機訪問元素厌处,而且有內(nèi)存自動管理功能线召,對元素的插入刪除可動態(tài)調(diào)整所占內(nèi)存。有三種創(chuàng)建方式:

  1. 不指定元素個數(shù):
vector<int> v;
  1. 創(chuàng)建時指定容器大小赤炒,下標(biāo)0~9,每個元素的值初始為0.0
vector<double> v(10);
  1. 創(chuàng)建有n個元素的vector亏较,每個元素有指定的初始值
vector<double> v(10, 8.6);

基本函數(shù)

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

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

  • size():返回向量的大小莺褒,即元素個數(shù)

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

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

  • insert(): 在任意位置前插入一個新元素,就是占位于這個位置雪情,原來此位置及以后的元素后移一位

  • erase(): 刪除vector中迭代器所指的一個元素或一段區(qū)間中的所有元素

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

  • reverse():將向量中某段迭代器區(qū)間元素反向排列

  • sort():要求使用隨機訪問迭代器排序遵岩,默認按升序排。可自定義比較函數(shù)定義排序規(guī)則尘执。

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

//自定義比較函數(shù)使降序排序
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;           //使用下標(biāo)賦值
    cout << v[6]<<endl; //使用下標(biāo)訪問元素

    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關(guān)鍵字
auto是C++11新引入的類型說明符表悬,讓編譯器分析表達式所屬的類型,用于從初始化表達式中推斷出變量的數(shù)據(jù)類型丧靡。所以auto定義的變量必須要有初始值蟆沫。有以下好處:

  • 可靠性:如果表達式的類型發(fā)生更改(包括函數(shù)返回值發(fā)生更改的情況),它也能工作温治。
  • 性能:確保將不會進行轉(zhuǎn)換饭庞。
  • 方便:不必擔(dān)心類型名稱拼寫困難和拼寫有誤。
  • 效率高:代碼會變得更高效熬荆。
//  auto a;                 // 錯誤但绕,沒有初始化表達式,無法推斷出a的類型  
//  auto int a = 10;        // 錯誤惶看,auto不能與其他類型組合連用
  
    // 1. 自動幫助推導(dǎo)類型  
    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. 使用模板技術(shù)時捏顺,如果某個變量的類型依賴于模板參數(shù),  不使用auto將很難確定變量的類型(使用auto后纬黎,將由編譯器自動進行確定)幅骄。  
template <class T, class U>  
void Multiply(T t, U u)  //函數(shù)和模板參數(shù)不能被聲明為auto
{  
    auto v = t * u;  
}  

//4. 不能用于類型轉(zhuǎn)換或其他一些操作,如sizeof和typeid
int value = 123;  
auto x2 = (auto)value; // 不能用 auto 轉(zhuǎn)換  
auto x3 = static_cast<auto>(value); // 錯誤同上

//5. 定義在一個auto序列的變量必須始終能被推導(dǎo)成同一類型
auto x1 = 5, x2 = 5.0, x3='r';  //錯誤

三本今、string基本字符系列容器

string可理解為字符串類拆座,其對象的元素是字符。提供了增刪改查比較等多種函數(shù)冠息。

  • 賦值兩種形式: 直接給字符串挪凑;賦字符指針

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

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

  • erase():刪除迭代器所指的元素或一個區(qū)間中所有元素

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

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

  • replace():替換string對象中的字符

  • find():查找字符串中的第一個字符元素或子串躏碳,返回下標(biāo)值或最大整數(shù)值,以下測試出的是64位

  • compare():字符串比較散怖,若比對方大返回1菇绵,小返回-1,相等返回0

  • reverse():反向排序string對象镇眷,需加頭文件algorithm

string對象也可作為vector的元素咬最,類似于字符串?dāng)?shù)組。

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

int main()
{
    //創(chuàng)建字符串對象欠动,直接賦值并輸出字符串長度
    string s;
    s = "hello, STL";
    cout <<"hello, STL的長度為:" << s.length()<<endl;

    //使用字符指針賦給字符串對象
    char ch[100];
    scanf("%s", ch);     //scanf輸入速度比cin快得多永乌,但不支持string對象
    s = ch;              //整個字符數(shù)組賦給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(chǎn)’大:" << 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個開始,將連續(xù)的3個字符替換為good
    cout <<"替換后字符串為:" << s<< endl;

    cout <<"字符串中第一個o的位置" <<s.find('o')<<endl;
    cout <<"字符串中g(shù)ood的位置" <<s.find("good")<<endl;
    cout <<"字符串中dog的位置翅雏,找不到則返回最大正整數(shù)值" <<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 <<"翻轉(zhuǎn)后的字符串為:"<<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 類型的數(shù)字化處理
    分離讀入的數(shù)字的每位時碗脊,若用取余法效率較低,而且對于大數(shù)字也只能作為字符串處理輸入橄妆。

  • string 對象與字符數(shù)組互操作

    string s;
    char ss[100];
    scanf("%s",  ss);       //空格作為終止符不會被讀入
    s = ss;
    printf(s.c_str());        //用 printf 輸出字符串對象要用 c_str() 方法
    cout<<endl;
    printf("%s", ss);
  • string 對象與 sscanf 函數(shù)
    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 對象與數(shù)值相互轉(zhuǎn)換
#include <iostream>
#include <algorithm>
#include <string>
#include <sstream>
using namespace std;

//將數(shù)值轉(zhuǎn)化為string
string convertToString(double x)
{
    ostringstream o;
    if (o << x)
        return o.str();
    return "conversion error";
}

//將string轉(zhuǎn)換為數(shù)值
double convertFromString(const string &s)
{
    istringstream i(s);
    double x;
    if (i >> x)
        return x;
    return 0;     //若出錯
}

int main()
{
    //將數(shù)值轉(zhuǎn)化為string的C方法
    char b[10];
    string a;
    sprintf(b, "%d", 1975);
    a = b;
    cout<< a <<endl;

    //將數(shù)值轉(zhuǎn)化為string的C++方法
    string cc = convertToString(1976);
    cout << cc<< endl;

    //將string轉(zhuǎn)換為數(shù)值的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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末衙伶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子害碾,更是在濱河造成了極大的恐慌矢劲,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件慌随,死亡現(xiàn)場離奇詭異芬沉,居然都是意外死亡,警方通過查閱死者的電腦和手機阁猜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評論 3 395
  • 文/潘曉璐 我一進店門丸逸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人剃袍,你說我怎么就攤上這事黄刚。” “怎么了民效?”我有些...
    開封第一講書人閱讀 165,474評論 0 356
  • 文/不壞的土叔 我叫張陵憔维,是天一觀的道長。 經(jīng)常有香客問我畏邢,道長业扒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評論 1 295
  • 正文 為了忘掉前任舒萎,我火速辦了婚禮程储,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逆甜。我一直安慰自己虱肄,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,902評論 6 392
  • 文/花漫 我一把揭開白布交煞。 她就那樣靜靜地躺著,像睡著了一般斟或。 火紅的嫁衣襯著肌膚如雪素征。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評論 1 305
  • 那天,我揣著相機與錄音御毅,去河邊找鬼根欧。 笑死,一個胖子當(dāng)著我的面吹牛端蛆,可吹牛的內(nèi)容都是我干的凤粗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,418評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼今豆,長吁一口氣:“原來是場噩夢啊……” “哼嫌拣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呆躲,我...
    開封第一講書人閱讀 39,332評論 0 276
  • 序言:老撾萬榮一對情侶失蹤异逐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后插掂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體灰瞻,經(jīng)...
    沈念sama閱讀 45,796評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,968評論 3 337
  • 正文 我和宋清朗相戀三年辅甥,在試婚紗的時候發(fā)現(xiàn)自己被綠了酝润。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,110評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡璃弄,死狀恐怖要销,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谢揪,我是刑警寧澤蕉陋,帶...
    沈念sama閱讀 35,792評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站拨扶,受9級特大地震影響凳鬓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜患民,卻給世界環(huán)境...
    茶點故事閱讀 41,455評論 3 331
  • 文/蒙蒙 一缩举、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匹颤,春花似錦仅孩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至赦肃,卻和暖如春溅蛉,著一層夾襖步出監(jiān)牢的瞬間公浪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評論 1 272
  • 我被黑心中介騙來泰國打工船侧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留欠气,地道東北人。 一個月前我還...
    沈念sama閱讀 48,348評論 3 373
  • 正文 我出身青樓镜撩,卻偏偏與公主長得像预柒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子袁梗,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,047評論 2 355