string類
- 1 STL 簡介
- 2 STL怎么學習
- 3 STL缺陷
- 4 string
- 4.1 初識 string
- 4.2 初步使用
- 構造函數
- 成員函數
- 5 小試牛刀
- Thanks?(・ω・)ノ謝謝閱讀!!!
- 下一篇文章見!!!
1 STL 簡介
現在我正式開始學習STL,這讓我期待好久了,一想到不用手撕鏈表,手搓堆棧,心里非常爽。接下來我們先來介紹一下STL:
STL,英文全稱 standard template library,中文可譯為標準模板庫或者泛型庫,其包含有大量的模板類和模板函數,是 C++ 提供的一個基礎模板的集合,用于完成諸如輸入/輸出、數學計算等功能。 STL 最初由惠普實驗室開發,于 1998 年被定為國際標準,正式成為 C++ 程序庫的重要組成部分。
主要分為這幾個版本:HP STL、SGI STL、STLport、PJ STL、Rouge Wave STL 等
其中我們需要重點學習的是SGI版本:
SGI版本由Silicon Graphics Computer Systems,Inc公司開發,繼承自HP版本。被GCC(Linux)采用,可移植性好,可公開、修改甚至販賣,從命名風格和編程 風格上看,閱讀性非常高。學習STL 要閱讀部分源代碼,主要參考的就是這個版本
2 STL怎么學習
網上有句話說:“不懂STL,不要說你會C++”。STL是C++中的優秀作品,有了它的陪伴,許多底層的數據結構以及算法都不需要自己重新造輪子,站在前人的肩膀上,健步如飛的快速開發。那么我們應該如何學習呢?
首先就是關注官方網站 C++中查閱資料。我推薦使用這個:C++庫
然后 學好英語很重要,要學會閱讀文檔,無論學習什么新技術,英語絕對是必不可少的。(程序員的盡頭是英語)
3 STL缺陷
- STL庫的更新太慢了。這個得嚴重吐槽, 上一版靠譜是C++98,中間的C++03基本一些修訂。C++11出來已經相隔了13年,STL才進一步更新。
- STL現在都沒有支持線程安全。并發環境下需要我們自己加鎖。且鎖的粒度是比較大的。
- STL極度的追求效率,導致內部比較復雜。比如類型萃取,迭代器萃取。
- STL的使用會有代碼膨脹的問題,比如使用vector/vector/vector這樣會生成多份代碼,當然這是模板語法本身導致的
4 string
接下來讓我們開始學習string類吧:
4.1 初識 string
根據上面我們進行的搜索我們可以了解到 :
- string是一個代表字符串的對象。
- 標準string類提供了類似標準字符容器的接口,而且添加了單字節操作的特性。
- string類 是 basic_string類模版的一個實例,使用char類型來實例化basic_string 模版類。
- 注意這個類獨立于所使用的編碼來處理字節: 如果使用 multi-byte 或 多長度字符(例如UTF-8編碼),這個類的所有成員(比如 長度和大小),以及該類的迭代器將仍然在該字節(而不是實際的編碼字符)來操作。
可以總結為以下內容:
- string是表示字符串的字符串類
- 該類的接口與常規容器的接口基本相同,再添加了一些專門用來操作string的常規操作。
- string在底層實際是:basic_string模板類的別名,typedef basic_string<char, char_traits, allocator>string;
- 不能操作多字節或者變長字符的序列
在使用string類時,必須包含#include頭文件string 以及using namespace std;
4.2 初步使用
構造函數
構造函數 | 功能 |
---|---|
string() (重點) | 構造空的string類對象,即空字符串 |
string(const char* s) (重點) | 用C-string來構造string類對象 |
string(size_t n, char c) | string類對象中包含n個字符c |
string(const string&s) (重點) | 拷貝構造函數 |
來看使用效果:
#include<string>
#include<iostream>
using namespace std;int main() {string s1;string s2("Hello!");string s3(5,'n');string s4(s2);cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;return 0;
}
流操作符也在string類中進行了重載,輸出很絲滑~
成員函數
成員函數 | 作用 |
---|---|
begin() | 返回字符首位置 (迭代器常用 ) |
end() | 返回字符結尾 (迭代器常用) |
size(重點) | 返回字符串有效字符長度 |
length | 返回字符串有效字符長度 |
capacity | 返回空間總大小 |
empty (重點) | 檢測字符串釋放為空串,是返回true,否則返回false |
clear (重點) | 清空有效字符 |
reserve (重點) | 為字符串預留空間 |
resize (重點) | 將有效字符的個數該成n個,多出的空間用字符c填充 |
來使用一下:
#include<string>
#include<iostream>
using namespace std;int main() {string s1("Hello!");cout << s1 << endl;//有效字符長度cout <<"有效字符長度:" << s1.size() << endl;//字符串所占空間cout << "字符串所占空間:" << s1.capacity() << endl;//實際長度(不包括‘\0')cout << "實際長度:" << s1.length() << endl;//檢查是否為空 (為空返回1 不為空返回0)cout <<"是否為空:" << s1.empty() << endl;//-----------清空試試-------cout << "\n---------清空--------\n";s1.clear();cout << s1 << endl;//有效字符長度cout << "有效字符長度:" << s1.size() << endl;//字符串所占空間cout << "字符串所占空間:" << s1.capacity() << endl;//實際長度(不包括‘\0')cout << "實際長度:" << s1.length() << endl;//檢查是否為空 (為空返回1 不為空返回0)cout << "是否為空:" << s1.empty() << endl;//--------更改大小-------cout << "\n---------更改有效字符個數--------\n";s1.resize(10, 'a');cout << s1 << endl;//有效字符長度cout << "有效字符長度:" << s1.size() << endl;//字符串所占空間cout << "字符串所占空間:" << s1.capacity() << endl;//實際長度(不包括‘\0')cout << "實際長度:" << s1.length() << endl;//檢查是否為空 (為空返回1 不為空返回0)cout << "是否為空:" << s1.empty() << endl;return 0;
}
看看運行效果:
這樣,對string就有了一個大概了解。
有些注意事項:
- size()與length()方法底層實現原理完全相同,引入size()的原因是為了與其他容器的接口保持一
致,一般情況下基本都是用size()。 - clear()只是將string中有效字符清空,不改變底層空間大小。
- resize(size_t n) 與 resize(size_t n, char c)都是將字符串中有效字符個數改變到n個,不同的是當字符個數增多時:resize(n)用0來填充多出的元素空間,resize(size_t n, char c)用字符c來填充多出的元素空間。注意:resize在改變元素個數時,如果是將元素個數增多,可能會改變底層容量的大小,如果是將元素個數減少,底層空間總大小不變。
- reserve(size_t res_arg=0):為string預留空間,不改變有效元素個數,當reserve的參數小于string的底層空間總大小時,reserver不會改變容量大小
5 小試牛刀
家人們! 上鏈接!!!:字符串相加
我們來嘗試使用我們剛剛學習的string來解決問題:
首先:我們不能簡單的進行字符串轉換為整數,然后相加,最后轉換為字符串。你問我為什么?
請看VCR:
測試用例沒問題,但是Leetcode給我們的數據太大了,longlong都沒辦法容納。
所以我們使用最樸素的算法:豎式算法
很簡單 依次相加 按運算法則進位 得到該位的數值然后插入到string即可。
class Solution {
public:string addStrings(string num1, string num2) {// 從個位開始,所以取字符串末位int i = num1.length() - 1;int j = num2.length() - 1;// 計算所需變量int n1 = 0,n2 = 0 ,carry = 0;//答案string對象string ans = "";//開始計算while(i >= 0 || j >= 0 || carry != 0 ){//這里一定要寫判斷,不然會發生數組越界。n1 = i >= 0 ? num1[i] - '0' : 0; n2 = j >= 0 ? num2[j] - '0' : 0;//得到結構就尾插ans.push_back((n1 + n2 + carry) % 10 + '0');//迭代carry = (n1 + n2 + carry) / 10;i--;j--;}//注意因為我們是尾插的,所以要調換頭尾順序才可以//這里使用 對稱對調法。for(int k = 0 ;k<ans.size()/2;k++){char tmp = ans[k] ;ans[k] = ans[ans.size() - 1 - k];ans[ans.size() - 1 - k] = tmp;}//這個函數更方便,但是不方便解釋了在這里//reverse(ans.begin(),ans.end());return ans;}
};
來看效果奧:
牛批!!!!! 過啦!!!!