1. 程式人生 > >C++ STL快速入門(轉)

C++ STL快速入門(轉)

在數月之前的機試中第一次體驗到STL的威力,因為自己本來一直在用C語言做開發,很多資料結構都是自己造的,比如連結串列、佇列等,第一次接觸C++ STL後發現這些資料結構都已經給我提供好了,我直接拿去呼叫就好了,真是超級方便。最近的專案中也遇到了STL一些容器,所以現在自己好好總結一下STL中一些最常用的容器的使用方法,方便自己日後查閱。

C++ STL中最基本以及最常用的類或容器無非就是以下幾個:

  • string
  • vector
  • set
  • list
  • map

下面就依次介紹它們,並給出一些最常見的最實用的使用方法,做到快速入門。

string

首先看看我們C語言一般怎麼使用字串的

char* s1 = "Hello SYSU!"; //建立指標指向字串常量,這段字串我們是不能修改的

//想要建立 可以修改的字串,我們可以使用陣列分配空間
char s2[20] = "Hello SYSU!";
//或者這樣
char s3[] = "Hello SYSU!";

//當然我們也可以動態分配記憶體
char* s4 = (char*)malloc(20);
gets(s4);

C++ 標準庫中的string表示可變長的字串,它在標頭檔案string裡面。

#include <string>

用string初始化字串分兩類:用“=”號就是拷貝初始化,否則就是直接初始化。

string s1;//初始化字串,空字串
string s2 = s1; //拷貝初始化,深拷貝字串
string s3 = "I am Yasuo"; //直接初始化,s3存了字串
string s4(10, 'a'); //s4存的字串是aaaaaaaaaa
string s5(s4); //拷貝初始化,深拷貝字串
string s6("I am Ali"); //直接初始化
string s7 = string(6, 'c'); //拷貝初始化,cccccc


#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s1;//初始化字串,空字串
    string s2 = s1; //拷貝初始化,深拷貝字串
    string s3 = "I am Yasuo"; //直接初始化,s3存了字串
    string s4(10, 'a'); //s4存的字串是aaaaaaaaaa
    string s5(s4); //拷貝初始化,深拷貝字串
    string s6("I am Ali"); //直接初始化
    string s7 = string(6, 'c'); //拷貝初始化,cccccc

    //string的各種操作
    string s8 = s3 + s6;//將兩個字串合併成一個
    s3 = s6;//用一個字串來替代另一個字串的對用元素

    cin >> s1;

    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    cout << s4 << endl;
    cout << s5 << endl;
    cout << s6 << endl;
    cout << s7 << endl;
    cout << s8 << endl;
    cout << "s7 size = " << s7.size() << endl; //字串長度,不包括結束符
    cout << (s2.empty() ? "This string is empty" : "This string is not empty") << endl;;

    system("pause");
    return 0;
}

string的IO操作

使用cin讀入字串時,遇到空白就停止讀取。比如程式輸入的是

"     Hello   World"

那麼我們得到的字串將是"Hello",前面的空白沒了,後面的world也讀不出來。

如果我們想把整個hello world讀進來怎麼辦?那就這樣做

cin>>s1>>s2;

hello存在s1裡,world存在s2裡了。

有時我們想把一個句子存下來,又不想像上面那樣建立多個string來儲存單詞,怎麼辦?

那就是用getline來獲取一整行內容。

string str;
getline(cin, str);
cout << str << endl;

當把string物件和字元面值及字串面值混在一條語句中使用時,必須確保+的兩側的運算物件至少有一個是string

string s1 = s2 + ", "; //正確
string s3 = "s " + ", "; //錯誤
string s4 = "hello" + ", " + s1; //錯誤
string s5 = s1 + "hello " + ", "; //改一下順序,s1放前頭,正確了,注意理解=號右邊的運算順序

處理string中的字元

訪問字串的每個字元

for (int i = 0; i < s3.size(); i++)
{
    cout << s3[i] << endl;
    s3[i] = 's';
}

在C語言中我都是用下標或者指標來訪問陣列元素,而在C++裡,有個新奇的東西叫做迭代器iterator,我們可以使用它來訪問容器元素。

string str("hi sysu");
for (string::iterator it = str.begin(); it != str.end(); it++)
{
    cout << *it << endl;
}

我們也可以是使用const_iterator使得訪問元素時是能讀不能寫,這跟常量指標意思差不多。

string str2("hi sysu");
for (string::const_iterator it = str2.begin(); it != str2.end(); it++)
{
    cout << *it << endl;
    *it = 'l'; //這是錯誤的,不能寫
}

string還有一些很好用的函式,比如找子串

string sq("heoolo sdaa ss");
cout << s.find("aa", 0) << endl; //返回的是子串位置。第二個引數是查詢的起始位置,如果找不到,就返回string::npos
if (s.find("aa1", 0) == string::npos)
{
    cout << "找不到該子串!" << endl;
}

vector

C++ STL中的verctor好比是C語言中的陣列,但是vector又具有陣列沒有的一些高階功能。與陣列相比,vector就是一個可以不用再初始化就必須制定大小的邊長陣列,當然了,它還有許多高階功能。

要想用vector首先得包含標頭檔案vector。

#include <vector>

怎麼初始化?

如果vector的元素型別是int,預設初始化為0;如果vector元素型別為string,則預設初始化為空字串。

vector<int> v1;
vector<father> v2;
vector<string> v3;
vector<vector<int> >;  //注意空格。這裡相當於二維陣列int a[n][n];
vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括號
vector<string> v6 = { "hi","my","name","is","lee" };
vector<int> v7(5, -1); //初始化為-1,-1,-1,-1,-1。第一個引數是數目,第二個引數是要初始化的值
vector<string> v8(3, "hi");
vector<int> v9(10); //預設初始化為0
vector<int> v10(4); //預設初始化為空字串

如何向vector新增元素?

請使用push_back加入元素,並且這個元素是被加在陣列尾部的。

for (int i = 0; i < 20; i++)
{
    v1.push_back(i);
}

vector其他的操作

訪問和操作vector中的每個元素

for (int i = 0; i < v1.size(); i++)
{
    cout << v1[i] << endl;
    v1[i] = 100;
    cout << v1[i] << endl;
}

注意:只能對已存在的元素進行賦值或者修改操作,如果是要加入新元素,務必使用push_back。push_back的作用有兩個:告訴編譯器為新元素開闢空間、將新元素存入新空間裡。

比如下面的程式碼是錯誤的,但是編譯器不會報錯,就像是陣列越界。

vector<int> vec;
vec[0] = 1;  //錯誤!

當然我們也可以選擇使用迭代器來訪問元素

vector<string> v6 = { "hi","my","name","is","lee" };
for (vector<string>::iterator iter = v6.begin(); iter != v6.end(); iter++)
{
    cout << *iter << endl;
    //下面兩種方法都行
    cout << (*iter).empty() << endl;
    cout << iter->empty() << endl; 
}

上面是正向迭代,如果我們想從後往前迭代該如何操作?
使用反向迭代器

for (vector<string>::reverse_iterator iter = v6.rbegin(); iter != v6.rend(); iter++)
{
    cout << *iter << endl;

}

vector最常用的增刪操作



#include <iostream>
#include <vector>
#include <string>

using namespace std;

template <typename T>
void showvector(vector<T> v)
{
    for (vector<T>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it;
    }
    cout << endl;
}

int main()
{
    vector<string> v6 = { "hi","my","name","is","lee" };
    v6.resize(3);  //重新調整vector容量大小
    showvector(v6);

    vector<int> v5 = { 1,2,3,4,5 }; //列表初始化,注意使用的是花括號
    cout << v5.front() << endl; //訪問第一個元素
    cout << v5.back() << endl; //訪問最後一個元素

    showvector(v5);
    v5.pop_back(); //刪除最後一個元素
    showvector(v5);
    v5.push_back(6); //加入一個元素並把它放在最後
    showvector(v5);
    v5.insert(v5.begin()+1,9); //在第二個位置插入新元素
    showvector(v5);
    v5.erase(v5.begin() + 3);  //刪除第四個元素
    showvector(v5);
    v5.insert(v5.begin() + 1, 7,8); //連續插入7個8
    showvector(v5);
    v5.clear(); //清除所有內容
    showvector(v5);

    system("pause");
    return 0;
} 

注意:雖然vertor物件可以動態增長,但是也或有一點副作用:已知的一個限制就是不能再範圍for迴圈中向vector物件新增元素。另外一個限制就是任何一種可能改變vector物件容量的操作,不如push_back,都會使該迭代器失效。

總而言之就是:但凡使用了迭代器的迴圈體,都不要向迭代器所屬的容器新增元素!

C++中push_back和insert兩個有什麼區別?

顧名思義push_back把元素插入容器末尾,insert把元素插入任何你指定的位置。
不過push_back速度一般比insert快。如果能用push_back儘量先用push_back。

set

set跟vector差不多,它跟vector的唯一區別就是,set裡面的元素是有序的且唯一的,只要你往set裡新增元素,它就會自動排序,而且,如果你新增的元素set裡面本來就存在,那麼這次新增操作就不執行。要想用set先加個標頭檔案set。

#include <set>

#include <iostream>
#include <set>
#include <string>

using namespace std;

template <typename T>
void showset(set<T> v)
{
    for (set<T>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it;
    }
    cout << endl;
}

int main()
{
    set<int> s1{9,8,1,2,3,4,5,5,5,6,7,7 }; //自動排序,從小到大,剔除相同項
    showset(s1);
    set<string> s2{ "hello","sysy","school","hello" }; //字典序排序
    showset(s2);
    s1.insert(9); //有這個值了,do nothing
    showset(s1);
    s2.insert("aaa"); //沒有這個字串,新增並且排序
    showset(s2);
    
    system("pause");
    return 0;
} 

list

list就是連結串列,在C語言中我們想使用連結串列都是自己去實現的,實現起來倒不難,但是如果有現成的高效的連結串列可以使用的話,我們就不需要重複造輪子了。STL就提供了list容器給我們。

list是一個雙向連結串列,而單鏈表對應的容器則是foward_list。

list即雙向連結串列的優點是插入和刪除元素都比較快捷,缺點是不能隨機訪問元素。

初始化方式就大同小異了,跟vector基本一樣。要想用list先加個標頭檔案list。

#include <list>

#include <iostream>
#include <list>
#include <string>

using namespace std;

template <typename T>
void showlist(list<T> v)
{
    for (list<T>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << *it;
    }
    cout << endl;
}

int main()
{
    list<int> l1{ 1,2,3,4,5,5,6,7,7 };
    showlist(l1);
    list<double> l2;
    list<char> l3(10);
    list<int> l4(5, 10); //將元素都初始化為10
    showlist(l4);

    
    system("pause");
    return 0;
} 

值得注意的是,list容器不能呼叫algorithm下的sort函式進行排序,因為sort函式要求容器必須可以隨機儲存,而list做不到。所以,list自己做了一個自己用的排序函式,用法如下:

list<int> l1{ 8,5,7,6,1,2,3,4,5,5,6,7,7 };
l1.sort();

map

map運用了雜湊表地址對映的思想,也就是key-value的思想,來實現的。

首先給出map最好用也最最常用的用法例子,就是用字串作為key去查詢操作對應的value。

要使用map得先加個標頭檔案map。

#include <map>
#include <iostream>
#include <map>
#include <string>

using namespace std;

void showmap(map<string, int> v)
{
    for (map<string, int>::iterator it = v.begin(); it != v.end(); it++)
    {
        cout << it->first << "  " << it->second << endl;  //注意用法,不是用*it來訪問了。first表示的是key,second存的是value
    }
    cout << endl;
}

int main()
{
    map<string, int> m1; //<>裡的第一個引數表示key的型別,第二個引數表示value的型別
    m1["Kobe"] = 100;
    m1["James"] = 99;
    m1["Curry"] = 98;

    string s("Jordan");
    m1[s] = 90;

    cout << m1["Kobe"] << endl;
    cout << m1["Jordan"] << endl;
    cout << m1["Durant"] << endl; //不存在這個key,就顯示0

    m1.erase("Curry");//通過關鍵字來刪除
    showmap(m1);
    m1.insert(pair<string, int>("Harris", 89)); //也可以通過insert函式來實現增加元素
    showmap(m1);
    m1.clear(); //清空全部


    system("pause");
    return 0;
}

如果想看看某個存不存在某個key,可以用count來判斷

if (m1.count("Lee"))
{
    cout << "Lee is in m1!" << endl;
}
else
{
    cout << "Lee do not exist!" << endl;
}

用迭代器來訪問元素

for (map<string, int>::iterator it = m1.begin(); it != m1.end(); it++)
{
    cout << it->first<<"  "<<it->second << endl;  //注意用法,不是用*it來訪問了。first表示的是key,second存的是value
}

相關推薦

C++ STL快速入門

在數月之前的機試中第一次體驗到STL的威力,因為自己本來一直在用C語言做開發,很多資料結構都是自己造的,比如連結串列、佇列等,第一次接觸C++ STL後發現這些資料結構都已經給我提供好了,我直接拿去呼叫就好了,真是超級方便。最近的專案中也遇到了STL一些容器,所以現在

C# AOP框架入門

出處:https://www.cnblogs.com/isaboy/p/Csharp_AOP_Log.html AOP面向切面程式設計(Aspect Oriented Programming),是通過預編譯方式和執行期動態代理實現程式功能的統一維護的一種技術。Spring框架用的核心技術就是AOP,是

c++STL map用法

此文章源於博主(sunshinewave),轉到自己部落格以後方便檢視 map是STL的一個關聯容器,它提供一對一(其中第一個可以稱為關鍵字,每個關鍵字只能在map中出現一次,第二個可能稱為該關鍵字的值)的資料處理能力,由於這個特性,它完成有可能在我們處理一對一

快速排序

最壞情況 sof 擴大 car ++i sta 混合 大於等於 python 上篇文章介紹了時間復雜度為O(nlgn)的合並排序,本篇文章介紹時間復雜度同樣為O(nlgn)但是排序速度比合並排序更快的快速排序(Quick Sort)。 快速排序是20世紀科技領域的十大算法之

Kotlin快速入門基礎

一個表 range fix font 有一個 get() nta 兼容 des Kotlin快速入門(一)基礎 Kotlin學習筆記,主要記錄與Java不同的地方。 1 基本類型 1.1 數字 1)數字沒有隱式擴寬轉換 val b: Byte = 1 // OK, 字面值

Zookeeper 快速入門

his 限制 change gic ise child 可能 他會 tom 來源:holynull, blog.leanote.com/post/holynull/Zookeeper 如有好文章投稿,請點擊 → 這裏了解詳情 Zookeeper是Hadoop分布式調

Docker三十分鐘快速入門

confirm base 描述 源碼 load maven pass 監控工具 yml 一、背景   上篇文章我們進行了Docker的快速入門,基本命令的講解,以及簡單的實戰,那麽本篇我們就來實戰一個真實的項目,看看怎麽在產線上來通過容器技術來運行我們的項目,來達到學會

Spring Boot快速入門:使用MyBatis註解形式進行數據庫操作

訪問 ins name ont clas assert xxx main apach 原文地址:https://lierabbit.cn/articles/7 添加依賴 新建項目選擇web,MyBatis,MySQL三個依賴 對於已存在的項目可以在bulid.gradle

Spring Boot快速入門:thymeleaf

return 之前 err static 默認 示例 圖片資源 css 官網 原文地址:https://lierabbit.cn/articles/8 靜態資源 在我們開發Web應用的時候,需要引用大量的js、css、圖片等靜態資源。 Spring Boot的默認位置是re

開源性能測試工具JMeter快速入門

正則表達 特殊 返回 預編譯 提取 檢查 blog 1.4 組織 目錄一、JMeter簡介二、JMeter功能介紹三、JMeter腳本四、關於JMeter小提示一、JMeter簡介1.定義JMeter是Apache組織開發的基於Java的壓力測試工具。用於對軟件做壓力測試,

開源性能測試工具JMeter快速入門

代碼 取模 .bat -h 斷言 調度 測試 格式 needed 目錄一、JMeter簡介二、JMeter功能介紹三、JMeter腳本四、關於JMeter小提示三、JMeter腳本1.測試計劃測試計劃是JMeter進行測試的起點 ,是其他JMeter測試元件的容器,每個測試

全棧開發之HTML快速入門

ack enter 提示 其他 red tle 顯示圖片 val password 一、HTML 是什麽? HTML 指的是超文本標記語言 (Hyper Text Markup Language) HTML 不是一種編程語言,而是一種標記語言 (markup lan

spring-data-jpa快速入門——

快速 span ron blank support bubuko body lan -s 一、概述   官網:https://projects.spring.io/spring-data-jpa/   1.什麽是spring-data-jpa   Spring D

spring-data-jpa快速入門——簡單查詢

ref spa data mail domain event cif open 寫實 一、方法名解析   1.引言     回顧HelloWorld項目中的dao接口 public interface GirlRepository extends JpaRepos

Selenium框架切換-----Selenium快速入門

type eset 9.png 說了 int 否則 work .html 切換   上一篇說了窗口的切換,本篇說說框架的切換。   切換框架:是指切換html中的iframe標簽元素或者frame標簽元素,註意,並不包括frameset   以下是常用的方法: 方法

顯式等待-----Selenium快速入門

edr gif tex 通過 輸出信息 except 顯式 eve span   上一篇說了元素定位過程中的隱式等待,今天我們來探討一下顯示等待。顯式等待,其實就是在使用WebDriverWait這個對象,進行等待。顯式等待對比隱式等待,多了一些人性化的設置,可以說是更細化

Docker快速入門

AS 重復 為什麽 函數調用 apt-get curl 命令 IE pwd SQ 上篇文章《Docker快速入門(一)》介紹了docker的基本概念和image的相關操作,本篇將進一步介紹image,容器和Dockerfile。 1 image文件 (1)Docker

筆記45 Hibernate快速入門

pre 快速入門 -- ret hbm spa -m int property Hibernate O/R 映射 一、多對一   一個Product對應一個Category,一個Category對應多個Product,所以Product和Category是多對一的關系。使用

筆記50 Mybatis快速入門

play ati driver 多個 目錄 自動 name 定制化 png 一、Mybatis簡介   MyBatis 是一款優秀的持久層框架,它支持定制化 SQL、存儲過程以及高級映射。MyBatis 避免了幾乎所有的 JDBC 代碼和手動設置參數以及獲取結果集。MyBa

筆記61 Spring Boot快速入門

user demo model 前端 req oot 項目 htm 顯示 IDEA+Spring Boot快速搭建 一、IDEA創建項目 略 項目創建成功後在resources包下,屬性文件application.properties中,把數據庫連接屬性加上,同時可以設置服