String 類
string類是一個模闆類:
typedef basic_string< char > string
使用string類要包含頭檔案< string>
string 對象的初始化:
- string s1(“hello”);
- string month=”match”;
- string s2(8,’x’);
- 等。。。。
#include <iostream>
#include <string>
using namespace std;
int main(){
string s1("hello");
cout<<s1<<endl;
string s2(, 'x');
cout<<s2<<endl;
string match = "matrch";
cout<<match<<endl;
string s;
s = 'n';
cout<<s<<endl;
return ;
}
hello
xxxxxxxx
matrch
n
string支援getline函數
- string s;
- getline(cin,s)
string的指派和連接配接
- 用=指派
- string s1(“cat”), s2
- s2=s1
- 用assign成員函數指派
- string s1(“cat”), s2
- s2.assign(s1);
- 用assign成員函數部分複制
- string s1(“catpig”), s3;
- s3.assign(s1,1,3); //下标為1到3這3個元素指派給s3
- 單個字元指派
- 單個字元複制:s2[5]=s1[3]=’a’;
- 逐個通路string中的字元string s1(“hello”) s1.at(i)
- 用+運算符連接配接字元串
- string s1(“good”), s2(“morning!”);
- s1+=s2
- 用成員函數append連接配接字元串
- string s1(“good”), s2(“morning”)
- s1.append(s2)
- s1.append(s1, 3, s1.size()) //下标為3的位置開始,指派s1.size()個字元,如果沒用那麼多字元,就指派到最後一個字元
- 用<,>,==比較字典序
- 用成員函數compare比較string的大小
- s1.compare(1,2,s3,0,3)是說,用s1的下标為1到2(包括2)的字元和s3的0到3的字元比較
子串
string s1(“hello world”), s2;
s2 = s1.substr(4,5); //從下标為4的位置,向後數5個字元進行指派
交換兩個string: s1.swap(s2)
尋找string中的字元
- 成員函數 find()和rfind()
- string s1(“hello world”)
- s1.find(“lo”)
- 在s1中從前向後查找,”lo”第一次出現的地方,如果找到,傳回”lo”開始的下标(“l”的下标) 如果找不到,傳回string::npos(string中定義的靜态常量)
- s1.find(“lo”,1)//從下标為1的地方開始找
- find_first_of() 和find_last_of()(這個是最後一次出現的地方)
- string s1(“hello world”);
- s1.find_first_of(“abcd”);
- 在s1中從前向後找”abcd”中任何一個字元第一次出現的地方,如果找到,傳回找到字母的位置,找不到則傳回string::npos。
- 成員函數find_first_not_of() 和find_last_not_of()
- string s1(“hello world”)
- s1.find_first_not_of(“abcd”);
- 在s1中從前向後查找不在,“abcd”中的字母第一次出現的地方,如果找到,傳回找到字母的位置,如果找不到,傳回string::npos。
- 删除string中的字元
- 成員函數erase()
- string s1(“hello world”)
- s1.erase(5) //删除5以及之後的字元
- 替換string中的字串
- 成員函數replace()
- string s1(“hello world”)
- s1.replace(2,3,”haha”) // 将s1中下标2開始的3個字元換成”haha”
- s1.replace(2,3,”haha”,1,2) // 将s1中下标2開始的3個字元換成“haha”中下标1開始的2個字元
- 在string中插入字元
- 成員函數insert()
- string s1(“hello world”)
- string s2(“show insert”)
- s1.insert(5, s2)
- s1.insert(2, s2, 5, 3)
- 轉換成C語言式char *字元串
- 成員函數c_str()
- string s1(“hello world”)
- printf(“%s\n”,s1.c_str()) // s1.c_str() 傳回傳統的const char*類型字元串,該字元串以 ‘\0’ 結尾
- 轉換成c語言式char*字元串
- 成員函數data()
- string s1(“hello world”)
- const char *p1=s1.data()
- for(int i=0;i
字元串流處理
除了标準流和檔案流輸入輸出之外,還可以從string進行輸入輸出
類似istream和ostream進行标準流輸入輸出,我們用istringstream和ostringstream進行字元串上的輸入輸出,也稱為記憶體輸入輸出:include< sstream>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(){
string s1("hello world");
string ss1, ss2;
istringstream inputstring(s1);
inputstring>>ss1>>ss2;
cout<<ss1<<" "<<ss2;
return ;
}
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main(){
string s1("hello world");
string ss1, ss2;
istringstream inputstring(s1);
inputstring>>ss1>>ss2;
ostringstream out;
out<<"the "<<<<" ok"<<endl;
cout<<out.str();
cout<<"there";
return ;
}
the ok
there
标準模闆庫(STL)概述
泛型程式設計
c++語言的核心優勢之一就是便于軟體的重用
c++中有兩個方面展現重用,
- 面向對象的思想:繼承和多态,标準類庫
- 泛型程式設計的思想:模闆機制以及标準模闆庫STL
STL中的基本的概念
- 容器:可容納各種資料類型的通用資料結構,是類模闆
- 疊代器:可用于一次存取容器中元素,類似于指針
- 算法:用來操作容器中哦的元素的函數模闆
- sort() 來對一個vector中的資料進行排序
- find()來搜尋一個list中的對象
- 算法本身與他們操作的資料的類型無關,是以他們可以在從簡單數組到高度複雜容器的任何資料結構上使用
容器概述:可以用于存放各種類型的資料(基本資料類型的變量,對象等)的資料結構,都是類模闆,分為三種:
- 順序容器:vector, deque, list
- 關聯容器:set, multiset, map, multimap
- 容器擴充卡:stack, queue, priority_queue
順序容器簡介
vector:動态數組,元素在記憶體連續存放。
deque:頭檔案< deuqe>雙向隊列。元素在記憶體連續存放。随機存取任何元素都能在常數時間内完成(但次于vector)。在兩端增删元素具有較佳的性能(大部分情況下是常數時間)。
list:頭檔案< list>雙向連結清單。元素在記憶體不連續存放。在任何位置增删元素都能在常數時間内完成。不支援随機存取。
關聯容器簡介
- 元素是排序的
- 插入任何元素,都按相應的排序規則來确定其位置
- 在查找時具有
- 通常以平衡二叉樹方式實作,插入和檢索時間都是O(log(N))
- set/multiset 頭檔案< set> set即集合。set中不允許相同元素,multiset中允許存在相同元素。
- map/multimap 頭檔案< map>
- map和set的不同在于map中存放的元素有且僅有兩個成員變量,一個名為first,另一個名為second,map根據first值對元素進行從小到大排序,并可快速地根據first來檢索元素。map同multimap的不同在于是否允許相同first值的元素。
容器擴充卡簡介
- stack:頭檔案:< stack> 棧。是項的有限序列,并滿足序列中被删除、檢索和修改的項隻能是最近插入序列的項(棧頂的項)。後進先出
- queue:頭檔案< queue>隊列。插入隻可以在尾部進行,删除、檢索和修改隻允許從頭部進行。先進先出。
- priority_queue:頭檔案< queue> 優先級隊列。最高優先級元素總是第一個出列
順序容器和關聯容器中都有哪些成員函數
- begin: 傳回指向容器中第一個元素的疊代器
- end: 傳回指向容器中最後一個元素後面位置的疊代器
- rbegin:傳回指向容器中最後一個元素的疊代器
- rend: 傳回指向容器中第一個元素前面的位置的疊代器
- erase: 從容器中删除一個或幾個元素
- clear: 從容器中删除所有元素
順序容器的常用的成員函數
- front: 傳回容器中第一個元素的引用
- back: 傳回容器中最後一個元素的引用
- push_back: 在容器末尾增加新元素
- pop_back: 删除容器末尾的元素
- erase:删除疊代器指向的元素(可能會使該疊代器失效),或删除一個區間,傳回被删除元素後面的那個元素的疊代器
标準模闆庫STL概述(二)
疊代器
- 用于指向順序容器和關聯容器中的元素
- 疊代器用法和指針類似
- 有const和非const兩種
- 通過疊代器可以讀取它指向的元素
- 通過非const疊代器還能修改其指向的元素
定義疊代器的方法
- 容器類名::iterator 變量名;
- 容器類名::const_iterator 變量名;
- 通路一個疊代器指向的元素:*疊代器變量名
疊代器上可以執行++操作,以使其指向容器中的下一個元素。如果到達了最後一個元素後面,就會出錯。
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> v;
v.push_back();
v.push_back();
v.push_back();
v.push_back();
vector<int>::const_iterator i;
for (i = v.begin(); i != v.end(); ++i) {
cout<<*i<<",";
}
cout<<endl;
vector<int>::reverse_iterator r;//反向疊代器,這裡r++會指向容器中的前一個元素
for (r = v.rbegin(); r!=v.rend(); ++r) {
cout<<*r<<",";
}
vector<int>::iterator j; //非常量疊代器
for (j = v.begin(); j != v.end() ; ++j) {
*j=;
}
cout<<endl;
for(auto x:v){
cout<<x<<",";
}
}
1,2,3,4,
4,3,2,1,
100,100,100,100,
雙向疊代器
- ++p, p++, –p, p–
- *p //傳回那個值(的引用)
- p=p1
- p==p1, p!=p1
随機通路疊代器
- 雙向疊代器的所有操作
- p+=i
- p-=i
- p+i, p-i, p[i],
- p
容器和容器上疊代器的種類
- vector 随機通路
- deque 随機通路
- list 雙向
- set/multiset 雙向
- map/multimap 雙向
- stack 不支援疊代器
- queue 不支援疊代器
- priority_queue 不支援疊代器
有的容器,例如sort和binary_search需要通過随機通路疊代器來通路容器中的元素,那麼list以及關聯容器就不支援改算法
vector 的疊代器是随機疊代器
list是雙向疊代器,用法如下:
list<int> vv;
vv.push_back();
vv.push_back();
vv.push_back();
list<int> ::const_iterator ii;
//這裡不能用ii<vv.end(),不能用vv[i]
for (ii=vv.begin();ii!=vv.end();++ii){
cout<<*ii<<",";
}
算法簡介
- 算法就是一個個函數模闆,大多是在< algorithm>中定義
- STL中提供能在各種容器中通用的算法,比如查找、排序等
- 算法通過疊代器來操縱容器中的元素,許多算法可以對容器中的一個局部區間進行操作,是以需要兩個參數,一個是起始元素的疊代器,一個是終止元素的後面一個元素的疊代器
- 有的算法傳回一個疊代器。比如find()算法,在容器中查找一個元素,并傳回一個指向該元素的疊代器
- 算法可以處理容器,也可以處理普通數組
算法示例 find()
- template
STL中“大”,“小”的概念
- 關聯容器内部的元素是從小到大排序的
- 有些算法要求其操作的區間是從小到大排序的,稱為“有序區間算法”。例如:binary_search
- 有些算法會對區間進行從小到大排序,成為排序算法。例如:sort
- 還有一些其他算法會用到“大”,“小”的概念
- 使用STL時,在預設的情況下,以下三個說法等價:x比y小,x
#include <iostream>
#include <algorithm>
using namespace std;
class A{
int v;
public:
A(int n):v(n){}
bool operator < (const A &a2)const{
cout<<v<<"<"<<a2.v<<"?"<<endl;
return false;
}
bool operator == (const A &a2) const{
cout<<v<<"=="<<a2.v<<"?"<<endl;
return v==a2.v;
}
};
int main()
{
A a[]={A(), A(), A(), A(), A()};
cout<<binary_search(a, a+, A());//折半查找中,隻是判斷了是否小于。。傳回1是找到了
return ;
}
3<9?
2<9?
1<9?
9<1?
1
vector 和deque
vector
#include <iostream>
#include <vector>
using namespace std;
template <class T>
void PrintVector(T s, T e){
for(;s!=e;++s)
cout<<*s<<" ";
cout<<endl;
}
int main(){
int a[]={,,,,};
vector<int> v(a, a+);
cout<<"1)"<<v.end()-v.begin()<<endl;
cout<<"2)";
PrintVector(v.begin(), v.end());
v.insert(v.begin()+, );//插入。。第一個參數是位置,第二個位置是元素
cout<<"3)";
PrintVector(v.begin(), v.end());
v.erase(v.begin()+);//删除
cout<<"4)";
PrintVector(v.begin(), v.end());
vector<int> v2(, );//4個元素,每個元素都是100
v2.insert(v2.begin(),v.begin()+, v.begin()+);//在v2裡面插入某個區間
cout<<"5) v2:";
PrintVector(v2.begin(), v2.end());
v.erase(v.begin()+, v.begin()+);
cout<<"6) ";
PrintVector(v.begin(), v.end());
return ;
}
1)5
2)1 2 3 4 5
3)1 2 13 3 4 5
4)1 2 3 4 5
5) v2:2 3 100 100 100 100
6) 1 4 5
vector 二維數組
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector< vector<int> > v();
for (int i = ; i < v.size(); ++i) {
for (int j = ; j < ; ++j) {
v[i].push_back(j);
}
}
for (int i = ; i < v.size(); ++i) {
for (int j = ; j < ; ++j) {
cout<<v[i][j]<<" ";
}
cout<<endl;
}
return ;
}
0 1 2 3
0 1 2 3
0 1 2 3
deque:适合vector的操作都适用于deque。
deque還要push_front(将元素插入到前面)和pop_front(删除最前面的元素)操作,複雜度是O(1)
雙向連結清單:list
- 在任何位置插入删除都是常數時間,不支援随機存取
- 除了具有所有容器都有的成員函數以外,還支援8個成員函數:
- push_front: 在前面插入
- pop_front: 删除前面的元素
- sort:排序(list不支援STL的算法sort)
- remove: 删除和指定值相同的所有元素
- unique: 删除所有和前一個元素相同的元素(要做到元素不重複,則unique之前還需要sort)
- merge:合并兩個連結清單,并清空被合并的那個
- reverse:颠倒連結清單
- splice: 在指定位置前面插入另一個連結清單中的一個或多個元素,并在另一連結清單中删除被插入的元素
#include <list>
#include <iostream>
#include <algorithm>
using namespace std;
class A{
private:
int n;
public:
A(int _n):n(_n){}
friend bool operator<(const A &a1, const A &a2);
friend bool operator==(const A &a1, const A &a2);
friend ostream &operator<<(ostream &o, const A &a);
};
bool operator<(const A &a1, const A &a2) {
return a1.n<a2.n;
}
bool operator==(const A &a1, const A &a2) {
return a1.n==a2.n;
}
ostream& operator<<(ostream &o, const A &a) {
o<<a.n;
return o;
}
template <class T>
void PrintList(const list<T> & lst){
//不推薦的寫法,用兩個疊代器更好
typename list<T>::const_iterator i; //typename用來說明list<T>::const_iterator是個類型
i = lst.begin();
for (i = lst.begin(); i!=lst.end(); ++i) {
cout<<*i<<",";
}
}
int main()
{
list<A> lst1, lst2;
lst1.push_back();lst1.push_back();
lst1.push_back();lst1.push_back();
lst1.push_back();
lst2.push_back();
lst2.push_front();
lst2.push_back();
lst2.push_front();
lst2.push_back();
lst2.push_front();
lst2.push_back();
cout<<"1)";
PrintList(lst1);cout<<endl;
cout<<"2)";
PrintList(lst2);cout<<endl;
lst2.sort();
cout<<"3)";
PrintList(lst2);
cout<<endl;
lst2.pop_front();//删掉頭部元素
cout<<"4)";
PrintList(lst2);
cout<<endl;
lst1.remove(); //删除和A(2)相等的元素
cout<<"5)";
PrintList(lst1);
cout<<endl;
lst2.unique();
cout<<"6)";
PrintList(lst2);
cout<<endl;
lst1.merge(lst2); //合并lst2到lst1并清空lst2
cout<<"7)";
PrintList(lst1);
cout<<endl;
cout<<"8)";
PrintList(lst2);
cout<<endl;
lst1.reverse();
cout<<"9)";
PrintList(lst1);
cout<<endl;
lst2.push_back();
lst2.push_back();
lst2.push_back();
lst2.push_back();
list<A>::iterator p1, p2, p3;
p1 = find(lst1.begin(), lst1.end(), );
p2 = find(lst2.begin(), lst2.end(), );
p3 = find(lst2.begin(), lst2.end(), );
lst1.splice(p1, lst2, p2, p3);//将lst2[p2,p3)插入到p1之前, 并從lst2中删除[p2, p3)
cout<<"10)";
PrintList(lst1);
cout<<endl;
cout<<"11)";
PrintList(lst2);
cout<<endl;
return ;
}
1)1,3,2,4,2,
2)40,30,20,10,30,30,40,
3)10,20,30,30,30,40,40,
4)20,30,30,30,40,40,
5)1,3,4,
6)20,30,40,
7)1,3,4,20,30,40,
8)
9)40,30,20,4,3,1,
10)40,30,20,4,200,300,3,1,
11)100,400,
函數對象:若一個類重載了運算符“()”,則該類的對象就成為函數對象
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <functional>
using namespace std;
int SumSquares(int total, int value)
{return total+value*value;}
template <class T>
void PrintInterval(T first, T last)
{
for(;first!=last;++first)
{
cout<<*first<<" ";
}
cout<<endl;
}
template <class T>
class SumPowers
{
private:
int power;
public:
SumPowers(int p):power(p){}
const T operator()(const T&total, const T&value){
T v=value;
for(int i=;i<power-;i++) v=v*value;
return total+v;
}
};
int main()
{
const int SIZE = ;
int a1[]={,,,,,,,,,};
vector<int> v(a1, a1+SIZE);
cout<<"1)";
PrintInterval(v.begin(), v.end());
int result = accumulate(v.begin(), v.end(), , SumSquares);//SumSquares是個函數
/*
這裡執行個體化了:
int accumulate(vector<int>::iterator first, vector<int>::iterator last, int init, int(*op)(int, int))
{
for(;first!=last;++first)
init=op(init, *first);
return init;
}
*/
cout<<"2)平方和"<<result<<endl;
//SumPowers是個類模闆,SumPowers<int>模闆類,SumPowers<int>(3)是個對象,這個對象重載了“()”
result = accumulate(v.begin(), v.end(), , SumPowers<int>());
/*
int accumulate(vector<int>::iterator first, vector<int>::iterator last, int init, SumPowers<int> op)
{
for(;first!=last;++first)
init=op(init, *first);
return init;
}
*/
cout<<"3)立方和"<<result<<endl;
result=accumulate(v.begin(), v.end(), , SumPowers<int>());
cout<<"4)4次方和"<<result<<endl;
return ;
}
1)1 2 3 4 5 6 7 8 9 10
2)平方和385
3)立方和3025
4)4次方和25333
//在c++源碼中如下:
template<typename _InputIterator, typename _Tp>
inline _Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_requires_valid_range(__first, __last);
for (; __first != __last; ++__first)
__init = __init + *__first;
return __init;
}
template<typename _InputIterator, typename _Tp, typename _BinaryOperation>
inline _Tp
accumulate(_InputIterator __first, _InputIterator __last, _Tp __init,
_BinaryOperation __binary_op)
{
// concept requirements
__glibcxx_function_requires(_InputIteratorConcept<_InputIterator>)
__glibcxx_requires_valid_range(__first, __last);
for (; __first != __last; ++__first)
__init = __binary_op(__init, *__first);
return __init;
}
STL中的函數對象類模闆:頭檔案:< functional>
greater 函數對象類模闆
//在c++中源碼如下:
template<typename _Tp>
struct greater : public binary_function<_Tp, _Tp, bool>
{
_GLIBCXX14_CONSTEXPR
bool
operator()(const _Tp& __x, const _Tp& __y) const
{ return __x > __y; }
};
greater的應用
list有兩個sort成員函數
- void sort(); 将list中的元素按”<”規定的比較方法升序排列
- template< class Compare>
- void sort(Compare op); 将list中的元素按op規定的比較方法升序排列。即要比較x, y大小時,看op(x, y)的傳回值,為true則認為x小于y
#include <list>
#include <iostream>
using namespace std;
class MyLess{
public:
bool operator()(const int &c1, const int &c2)
{
//比較各位數
return (c1%)<(c2%);
}
};
template <class T>
void Print(T first, T last){
for(;first!=last;++first) cout<<*first<<",";
}
int main()
{
const int SIZE=;
int a[SIZE]={,,,,};
list<int> lst(a, a+SIZE);
lst.sort(MyLess());
Print(lst.begin(), lst.end());
cout<<endl;
lst.sort(greater<int>());//greater<int>()是個對象
Print(lst.begin(), lst.end());
cout<<endl;
return ;
}
21,2,3,14,5,
21,14,5,3,2,
在STL中使用自定義的“大”,“小”關系
關聯容器和STL中許多算法,都是可以用函數或函數對象自定義比較器的。在自定義了比較器op的情況下,以下三個說法是等價的:1.x小于y;2.op(x,y) 傳回true;3.y大于x
#include <iostream>
#include <iterator>
using namespace std;
class MyLess{
public:
bool operator()(int a1, int a2){
if((a1%)<(a2%)) return true;
else return false;
}
};
bool MyCompare(int a1, int a2){
if((a1%)<(a2%)) return false;
else return true;
}
template <class T, class pred>
T MyMax(T first, T last, pred op){
T temp = first;
for(;first!=last;++first){
if(op(*temp, *first)) 如果*temp小于*first
temp = first;
}
return temp;
};
int main()
{
int a[]={, ,, , };
cout<<*MyMax(a, a+, MyLess())<<endl;
cout<<*MyMax(a, a+, MyCompare)<<endl;
return ;
}
19
12