黑馬程序員匠心之作|C++教程從0到1入門編程,學(xué)習(xí)編程不再難

C++重點(diǎn)筆記
tips
編譯和調(diào)試的區(qū)別
編譯(compile):依賴于編譯器,將源碼轉(zhuǎn)化成目標(biāo)文件 如.obj
調(diào)試:讓程序在系統(tǒng)中運(yùn)行之前查錯(cuò)和改錯(cuò),找出并修正潛在的錯(cuò)誤
-------------------------------------------------------------
B站篇幅有限,沒有markdown模式,完整筆記請看https://blog.csdn.net/liushuping528/article/details/126087429?spm=1001.2014.3001.5501
--------------------------------------------------------------
linux c++的四個(gè)處理過程
1. 預(yù)處理
將所有#include頭文件以及宏定義替換成其真正的內(nèi)容
2. 編譯
將經(jīng)過預(yù)處理之后的程序轉(zhuǎn)換成特定匯編代碼的過程
3. 匯編
將上一步的匯編代碼轉(zhuǎn)換成機(jī)器代碼,這一步產(chǎn)生的文件叫做目標(biāo)文件
4. 鏈接
將多個(gè)目標(biāo)文件以及所需的庫文件(.so)鏈接成最終的可執(zhí)行文件
數(shù)據(jù)類型
4種轉(zhuǎn)換較為規(guī)范的運(yùn)算符
`reinterpret_cast<type-name>(expression)`
1. reinterpret_cast 可以將指針類型轉(zhuǎn)換為足以存儲(chǔ)指針表示的整型
2. 不能將函數(shù)指針轉(zhuǎn)換為數(shù)據(jù)指針
static_cast
`auto *ptr = static_cast<void(Teacher::*)(QString)>(&Teacher::hungry);`
尖括號(hào)里面的轉(zhuǎn)為外面的
用于各種隱式轉(zhuǎn)換,如非const轉(zhuǎn)const,void*轉(zhuǎn)指針,static_cast能用于多態(tài)向上轉(zhuǎn)化,如果向下轉(zhuǎn)能成功但是不安全
## 內(nèi)存模型和名稱空間
### 單獨(dú)編譯
將組件函數(shù)放在獨(dú)立的文件中,然后將他們鏈接成可執(zhí)行的程序。如若要修改文件,只需重新頭文件,然后將它與其他文件編譯版本鏈接,程序的管理更為便捷
**組織策略 可以把程序拆分為三個(gè)部分**
1. 頭文件:編寫函數(shù)原型 結(jié)構(gòu)聲明
eg:
```cpp
#ifndef STOCK_H_
#define STOCK_H_
struct polar
{
? ? double distance;
? ? double angle;
};
struct rect
{
? ? double x;
? ? double y;
};
polar rect_to_polar(rect xypos);
void show_polar(polar dapos);
#endif
```
2. 源代碼文件:函數(shù)定義
?
eg:
```cpp
#include <iostream>
#include<cmath>
#include "stock.h"
polar rect_to_polar(rect xypos) {
? ? using namespace std;
? ? polar answer;
? ? answer.distance = sqrt(xypos.x * xypos.x + xypos.y * xypos.y);
? ? answer.angle = atan2(xypos.x, xypos.y);
? ? return answer;
}
void show_polar(polar dapos) {
? ? using namespace std;
? ? cout << "angle" << dapos.angle << endl;
? ? cout << "distance" << dapos.distance << endl;
}
```
3. 源代碼文件:main()和其他使用這些函數(shù)的函數(shù)放在第三個(gè)文件
?
```cpp
#include <iostream>
#include "stock.h"
using namespace std;
int main() {
? ? rect rplace;
? ? polar pplace;
? ? cout << "enter the x and y values: ";
? ? while (cin >> rplace.x >> rplace.y) {
? ? ? ? pplace = rect_to_polar(rplace);
? ? ? ? show_polar(pplace);
? ? ? ? cout << "next two number(q to quit):";
? ? }
? ? cout << "bye!\n";
? ? return 0;
}
```
> 1.高效的組織策略,編寫另一程序,需要使用這些函數(shù)時(shí),只需包含頭文件,并將函數(shù)文件添加到項(xiàng)目列表或make列表中即可。
> 2.這種組織方式也是面向?qū)ο螅∣OP)的體現(xiàn)
**頭文件包含的內(nèi)容:**
* 函數(shù)原型
* 結(jié)構(gòu)聲明
* 類聲明
* 內(nèi)聯(lián)函數(shù)(~)
* 模板聲明(~)
頭文件編寫
```cpp
#ifndef HEAD_H_ ?//根據(jù)include名選擇名稱,并加上下劃線 以防止被其他地方定義
#define HEAD_H_
…… //file content
#endif
```
名稱空間 -ing
名稱可以是函數(shù)、變量、結(jié)構(gòu)、類以及類的成員,隨著項(xiàng)目的增大,名稱相互沖突的可能性也將增加
```cpp
namespace jack{
? ? double pail;
? ? void fetch();
? ? int pal;
? ? struct well{}
}
```
名稱空間是開放的(open),
1. ? .
```cpp
namespace jack{
? ? char name[10];
}
```
2. jack名稱空間為fetch()函數(shù)提供原型??梢栽谖募竺嬖俅问褂肑ack名稱空間定義這個(gè)函數(shù)
```cpp
namespace jack{
? ? void fetch(){
? ? ? ? ……
? ? }
}
```
using聲明和using編譯
* **using聲明**由using和被限定的名稱組成
*
`using jack::pail; ?// 一個(gè)using聲明`
? using聲明將特定的名稱添加到它所屬的聲明區(qū)域中。 ?
?
? ```cpp
? int main(){
? ? ? using jack::pail;
? ? ? cin >> pail;
? ? ? cin >> ::pail; //讀入進(jìn)去一個(gè)pail全局變量
? }
? ```
using聲明使一個(gè)名稱可用,而using編譯指令使所有名稱都可用。
* **using編譯指令**由using namespace和名稱空間組成
*
`using namespace jack; //一個(gè)using編譯聲明`
using namespace
**總結(jié):** 導(dǎo)入名稱時(shí),首選使用作用域解析運(yùn)算符或using聲明的方法。
### const成員函數(shù)
const關(guān)鍵字放在函數(shù)的括號(hào)后面 stock類中的函數(shù)聲明
`void show() const ?//函數(shù)聲明`
函數(shù)定義的開頭
`void stock :: show() const //函數(shù)定義 不被改變`
只要類不修改調(diào)用對象,就應(yīng)將其聲明為const
## effective C++
### 永遠(yuǎn)在使用對象之前先將它初始化
構(gòu)造函數(shù)做好使用成員初始列,而不要在構(gòu)造本體函數(shù)內(nèi)使用賦值操作
### 8-2法則
一個(gè)程序的80%的資源用于20%的代碼身上,80%執(zhí)行時(shí)間花在20%的代碼身上,80%執(zhí)行時(shí)間花在20%的代碼
8-2 法則告訴我們,如果東一塊西一塊的改善程序,病急亂投醫(yī),頭痛醫(yī)頭腳痛醫(yī)腳,不會(huì)有太大幫助。
枚舉類型 enum
定義:
enum 類型名{枚舉值表}
枚舉值表也叫枚舉元素列表,列出定義的枚舉類型的所有可用值,各個(gè)值之間用“,”分開。
`enum Suit{Diamonds,Hearts,Clubs};`
數(shù)組
c++的運(yùn)算符優(yōu)先要求使用括號(hào)
數(shù)組類比于指針
數(shù)組名是第一個(gè)元素的地址
int* a的類型是int* int a的類型是int
前者a是指向整型數(shù)據(jù)的指針,它的本質(zhì)是一個(gè)地址,后者就是一個(gè)數(shù)據(jù)了
`Dog* dog = new Dog;` 分配一片內(nèi)存 并把內(nèi)存的地址賦給 dog
### 無符號(hào)類型
不能存儲(chǔ)負(fù)數(shù)值的無符號(hào)變體,其優(yōu)點(diǎn)是可以增大變量能夠存儲(chǔ)的最大值
(short范圍-32768-32767,unsign short范圍0-65535)
### 指針表示動(dòng)態(tài)數(shù)組
使用new[]運(yùn)算符創(chuàng)建數(shù)組時(shí),將采用動(dòng)態(tài)聯(lián)遍,即將在運(yùn)行時(shí)為數(shù)組分配空間,其長度也將在運(yùn)行時(shí)設(shè)置
使用完成后,應(yīng)用delete[]釋放占用的內(nèi)存
```cpp
int size;
cin >>size;
int *arr = new int [size];
……
delete[] arr;
```
### 數(shù)組區(qū)間的函數(shù)
指定元素區(qū)間 可以通過傳遞兩個(gè)指針完成:一個(gè)指針標(biāo)識(shí)數(shù)組的開頭,另一個(gè)指針標(biāo)識(shí)數(shù)組的尾部
```c++
int sum_arr(const int *begin,const int *end); //函數(shù)聲明
int main(){
? ? int arr[10];
? ? int sum = sum_arr(arr,arr+3); //定義區(qū)間 ?
}
```
### const保護(hù)數(shù)組
為防止函數(shù)無意中修改數(shù)組的內(nèi)容,可在聲明形參時(shí)使用關(guān)鍵字**const**
`void show_array(const double ar[],int n)`
### 結(jié)構(gòu)體
```c++
struct typename {
? ? char name[10];
? ? int ages;
}
```
1. new 創(chuàng)建動(dòng)態(tài)結(jié)構(gòu)
`inflat *ps = new inlat;`
使用完成后要用**delete**釋放內(nèi)存 `delete ps;`
> ps -> price 也是指向結(jié)構(gòu)的price成員
> ps 是指向結(jié)構(gòu)的指針,則*ps就是指向的值--結(jié)構(gòu)本身
> (*ps)是一種結(jié)構(gòu) (*ps).name 是該結(jié)構(gòu)的name成員
## 函數(shù)
### 函數(shù)原型
原型可以幫助編譯器完成許多工作,降低程序出錯(cuò)的機(jī)率,具體有一下幾點(diǎn):
1. 編譯器正確處理函數(shù)返回值
2. 編譯器檢查使用的參數(shù)數(shù)目是否正確
3. 編譯器檢查使用參數(shù)類型是否正確
### ?#define的定義
(文本替換)
define 是宏定義,程序在預(yù)處理階段將用define定義的內(nèi)容進(jìn)行替換。程序在運(yùn)行時(shí),常量表中并沒有用define定義的常量,系統(tǒng)不會(huì)為它分配內(nèi)存
?1. #define定義一個(gè)標(biāo)識(shí)符來表示一個(gè)常量。
?特點(diǎn):定義的標(biāo)識(shí)符不占內(nèi)存,只是一個(gè)臨時(shí)的符號(hào),預(yù)編譯后這個(gè)符號(hào)就不存在了
? ? * 宏展開是在預(yù)處理階段完成的,這個(gè)階段把替換文本只看做一個(gè)字符串,并不會(huì)有任何的計(jì)算發(fā)生。
? ? * 宏其實(shí)就是簡單的文本替換。
定義標(biāo)識(shí)符的一般形式:
```c++
#define 標(biāo)識(shí)符 常量 //注意,最后沒有分量
```
2. 在大規(guī)模的開發(fā)過程中,特別是跨平臺(tái)和系統(tǒng)的軟件里,define最重要的的功能就是條件編譯
```cpp
#ifdef WINDOWS
……
#endif
#ifdef LINUX
……
#endif
```
可以在編譯的時(shí)候通過#define設(shè)置編譯環(huán)境。
### 函數(shù)指針
使用函數(shù)指針的三個(gè)步驟:
1. 聲明函數(shù)指針
2. 讓函數(shù)指針指向函數(shù)地址
3. 通過函數(shù)指針調(diào)用函數(shù)
**聲明函數(shù)指針**
```cpp
double pam(int) ?//函數(shù)原型
double (*f)(int) ? //函數(shù)指針
```
pam 替換為了(*f).由于pam是函數(shù)名 即(*f)也是函數(shù)名, f 是函數(shù)指針
**函數(shù)指針調(diào)用函數(shù)**
```cpp
//函數(shù)指針調(diào)用函數(shù)
f = pam;
double y = pam(2);
double x = (*f)(5);
```
```cpp
#include<iostream>
using namespace std;
double jack(int);
double rose(int);
void accrate(int lines, double(*pf)(int)); //聲明指針函數(shù)
int main() {
? ? int code;
? ? cin >> code;
? ? cout<<"jack和rose輸入"<<code<<"行代碼算花費(fèi)的時(shí)間"<<endl;
? ? accrate(code, jack);
? ? accrate(code, rose);
}
double jack(int n) {
? ? double sum = n * 0.5;
? ? return sum;
}
double rose(int n) {
? ? double sum = n * 0.7;
? ? return sum;
}
void accrate(int lines, double(*pf)(int)) {
? ? //double um = (*pf)(lines);
? ? cout << lines << " lines may have " << (*pf)(lines) << "mins" << endl;
}
```
### 回調(diào)函數(shù)
> 回調(diào)函數(shù)就是一個(gè)通過函數(shù)指針調(diào)用的函數(shù),如果你把函數(shù)的指針作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來調(diào)用其所指向的函數(shù)時(shí),我們就說回調(diào)函數(shù)
把一段可執(zhí)行的代碼像參數(shù)傳遞那樣傳給其他代碼,而這個(gè)代碼在某個(gè)時(shí)刻被調(diào)用執(zhí)行,叫做回調(diào)。
如果代碼立即被執(zhí)行就稱為**同步回調(diào)**,如果在之后晚點(diǎn)的某個(gè)時(shí)間在執(zhí)行,則稱為**異步回調(diào)**
回調(diào)函數(shù)的作用 ,**解耦**
```cpp
#include "../apue.h"
int Call_back_1(int x)
{
? ? printf("Hello,this is Call_back_1,the value is %d\n",x);
? ? return 0;
}
int Call_back_2(int x){
? ? printf("Hello,this is Call_back_2,the value is %d\n",x);
? ? return 0;
}
int Call_back_3(int x){
? ? printf("Hello,this is Call_back_3,the value is %d\n",x);
? ? return 0;
}
int Handle(int x,int (*Callback)(int x))
{
? ? printf("Entering Handle Function.\n");
? ? Callback(x);
? ? printf("Leaving Handle Function.\n");
? ? return 0;
}
int main(){
? ? int x = 1;
? ? int y = 2;
? ? int z = 3;
? ? printf("Entering Main Function.\n");
? ? Handle(x,Call_back_1);
? ? Handle(y,Call_back_2);
? ? Handle(z,Call_back_3);
? ? printf("Leaving Main Function.\n");
? ? return 0;
}
```
### 引用&
1. 形參需要修改實(shí)參時(shí)
2. 當(dāng)實(shí)參較大時(shí),如(數(shù)據(jù) 結(jié)構(gòu)體)傳遞引用 系統(tǒng)不會(huì)生成臨時(shí)變量 較小的內(nèi)存消耗
### 形參實(shí)參的三種傳值方式
?1. 按值傳遞
2. 按地址傳遞 形參改變實(shí)參
3. 按引用傳遞
```cpp
#include<iostream>
void swap1(int a, int b) {
? ? int temp;
? ? temp = a;
? ? a = b;
? ? b = temp;
}
void swap2(int* p, int* q) {
? ? int temp;
? ? temp = *p;
? ? *p = *q;
? ? *q = temp;
}
void swap3(int& a, int& b) {
? ? int temp;
? ? temp = a;
? ? a = b;
? ? b = temp;
}
int main() {
? ? int i = 10;
? ? int j = 20;
? ? //按值傳遞 ?
? ? swap1(i, j); //形參不會(huì)對實(shí)參進(jìn)行修改
? ? std::cout << "i的值是" << i << std::endl;
? ? std::cout << "j的值是" << j << std::endl;
? ? //按地址傳遞 ?
? ? swap2(&i, &j); //形參會(huì)對實(shí)參進(jìn)行修改
? ? std::cout << "i的值是" << i << std::endl;
? ? std::cout << "j的值是" << j << std::endl;
? ? //按引用傳遞 ?
? ? swap3(i, j); //形參不會(huì)對實(shí)參進(jìn)行修改
? ? std::cout << "i的值是" << i << std::endl;
? ? std::cout << "j的值是" << j << std::endl;
? ? return 0;
}
```
## STL模板
### vector容器
與數(shù)據(jù)相似,也成為單端數(shù)組(類比于棧)
**vector與普通的數(shù)組的區(qū)別**
數(shù)組時(shí)靜態(tài)空間,而vector可以動(dòng)態(tài)擴(kuò)展
**動(dòng)態(tài)擴(kuò)展**
并不是在原有的基礎(chǔ)上進(jìn)行拓展,而是找一個(gè)更大的空間,將原數(shù)據(jù)拷貝到新空間,釋放原空間
vector迭代器 支持隨機(jī)訪問的迭代器
vector四種構(gòu)造方法
1. 默認(rèn)構(gòu)造
2. 區(qū)間構(gòu)造
3. 拷貝構(gòu)造
4. n個(gè)元素構(gòu)造
```cpp
#include<iostream>
#include<vector>
using namespace std;
void printvector(vector<int> &v) {
? ? for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
? ? ? ? cout << *it << " ";
? ? }
? ? cout << endl;
}
void test() {
? ? //默認(rèn)構(gòu)造
? ? vector<int>v1;
? ? for (int i = 0; i < 50; i++) {
? ? ? ? v1.push_back(i);
? ? }
? ? printvector(v1);
? ? //通過區(qū)間的方式進(jìn)行構(gòu)造
? ? vector<int>v2(v1.begin(), v1.end());
? ? printvector(v2);
? ? //N個(gè)elem方式構(gòu)造
? ? vector<int>v3(10, 123);//(個(gè)數(shù),元素)
? ? printvector(v3);
? ? //拷貝構(gòu)造
? ? vector<int>v4(v3);
? ? printvector(v4);
```
**vector的增刪查**
```cpp
struct review
{
? ? string title;
? ? int rating;
};
bool Fillreview(review& re);
void printbook(vector<review>& b1);
int main() {
? ? vector<review>book;
? ? review temp;
? ? while (Fillreview( temp)) {
? ? ? ? book.push_back(temp);
? ? }
? ? printbook(book);
? ? vector<review>oldbook(book);
? ? printbook(oldbook);
? ? book.erase(book.begin() + 1, book.begin() + 3); //vector的刪除
? ? printbook(book);
? ? book.insert(book.begin(), oldbook.begin() + 1, oldbook.begin() + 2);//vector的插入
? ? printbook(book);
? ?
? ?
? ? book.swap(oldbook);
? ? printbook(book);
? ? return 0;
? ? system("pause");
}
bool Fillreview(review& re)
{
? ? cout << "please enter a book name" << endl;
? ? getline(cin,re.title);
? ? if (re.title == "quit")
? ? {
? ? ? ? return false;
? ? }
? ? else
? ? ? ? cin >> re.rating;
? ? if (!cin)
? ? ? ? return false;
? ? while (cin.get()!='\n')
? ? {
? ? ? ? continue;
? ? }
? ? return true;
}
void printbook(vector<review>& b1)
{
? ? for (vector<review>::iterator it =b1.begin();it!=b1.end();it++)
? ? {
? ? ? ? cout << (*it).rating <<" "<<(*it).title<< endl;
? ? }
? ? cout << "--------------------" << endl;
}
```
**支持隨機(jī)訪問的容器 都可以用標(biāo)準(zhǔn)算法sort進(jìn)行排序**
### list雙向循環(huán)鏈表
由于鏈表的存儲(chǔ)方式并不是連續(xù)的內(nèi)存空間,因此鏈表list中的迭代器只支持前移和后移,屬于雙向迭代器
list 不支持隨機(jī)存取
List有一個(gè)重要的性質(zhì),插入操作和刪除操作都不會(huì)造成原有l(wèi)ist迭代器的失效,這在vector是不成立的
STL中**list和vector是兩個(gè)最常使用的容器**,各有缺點(diǎn)
`list.reverse();` 雙向鏈表的反轉(zhuǎn)
`list.sort()` 雙向鏈表的排序
`font` 首元素
`back` 尾部元素
**list自定義類型排序**
> 自定義類型 類類型or結(jié)構(gòu)類型 要先指定類型規(guī)則
**語法**
```cpp
//指定排序規(guī)則 ? 如果年齡相等 按照體重排序
bool compareage(Person& p1, Person& p2) {
? ? if (p1.m_age == p2.m_age) {
? ? ? ? return p1.m_weight < p2.m_weight;
? ? }
? ? else
? ? {
? ? ? ? return p1.m_age < p2.m_age;
? ? }
? ?
}
```
```cpp
#include<iostream>
#include<list>
#include<string>
using namespace std;
class Person {
public:
? ? Person(string name, int age,float weight) {
? ? ? ? this->m_name = name;
? ? ? ? this->m_age = age;
? ? ? ? this->m_weight = weight;
? ? }
? ? string m_name;
? ? int m_age;
? ? float m_weight;
};
void printlist(list<Person>& p) {
? ? for (list<Person>::const_iterator it=p.begin();it!=p.end();it++)
? ? {
? ? ? ? cout << (*it).m_name << it->m_age <<" " << it->m_weight << " ";
? ? }
? ? cout << endl;
}
//指定排序規(guī)則 ? 如果年齡相等 按照體重排序
bool compareage(Person& p1, Person& p2) {
? ? if (p1.m_age == p2.m_age) {
? ? ? ? return p1.m_weight < p2.m_weight;
? ? }
? ? else
? ? {
? ? ? ? return p1.m_age < p2.m_age;
? ? }
? ?
}
void test() {
? ? Person p1("zhangsan", 56,50.2);
? ? Person p2("lisi", 16,53.2);
? ? Person p3("wangwu", 16,59.9);
? ? Person p4("zhaoliu", 17,45.9);
? ? Person p5("gouba", 19,49.3);
? ? list<Person>ll;
? ? ll.push_back(p1);
? ? ll.push_back(p2);
? ? ll.push_back(p3);
? ? ll.push_back(p4);
? ? ll.push_back(p5);
? ? printlist(ll);
? ? ll.sort(compareage);
? ? printlist(ll);
}
int main() {
? ? test();
? ? return 0;
}
```
### 關(guān)聯(lián)容器set,mutiset
所以的元素都會(huì)在插入時(shí)自動(dòng)排序
set與multiset屬于關(guān)聯(lián)容器,底層結(jié)構(gòu)是二叉樹實(shí)現(xiàn)
**區(qū)別**
1. set不允許容器有重復(fù)的元素
2. multiset允許容器有重復(fù)的元素
set的插入使用的是insert,沒有push_back這個(gè)方法
empty();
size();
swap();
**插入刪除**
insert()
erase(迭代器) erase(容器元素)
clear(); 清空
**查找和統(tǒng)計(jì)**
find(); //查找key是否存在,返回該元素的迭代器不存在 返回set.end()
cout(); 要么是0 要么是1
### set容器排序規(guī)則
set的默認(rèn)排序規(guī)則是從小到大,改變排序規(guī)則從大到小
利用仿函數(shù),改變排序規(guī)則
### map/multimap容器
map所有元素都是一對
第一個(gè)key值(索引的作用)第二個(gè)valu值(實(shí)值)
所有元素都會(huì)根據(jù)元素的鍵值自動(dòng)排序
關(guān)聯(lián)容器,二叉樹實(shí)現(xiàn)
可以通過key值快速的找到value值
map與multimap 的區(qū)別 是能不能插入重復(fù)的key值
```cpp
void printmap(map<int, int>& ma) {
? ? for (map<int,int>::const_iterator it =ma.begin();it!=ma.end();it++)
? ? {
? ? ? ? cout << "key= " << (*it).first << " value=" << (*it).second << endl;
? ? }
? ? cout << endl;
}
void test() {
? ? //map容器
? ? map<int, int>m; ? ?//k v ?創(chuàng)建map容器
? ? m.insert(pair<int, int>(1, 10));
? ? m.insert(pair<int, int>(2, 28));
? ? m.insert(pair<int, int>(4, 20));
? ? m.insert(pair<int, int>(6, 21));
? ? m.insert(pair<int, int>(9, 320));
? ? m.insert(make_pair(10, 22)); ? ? ? //make_pair 插入
? ? printmap(m);
? ? map<int, int>m2(m); ? //拷貝構(gòu)造函數(shù)
? ? printmap(m2);
? ? map<int, int>m3;
? ? m3 = m2; ? ? ? ? ?//賦值
? ? printmap(m3);
? ? cout << m[6] << endl; ? ? //可以使用[]查找;
? ? cout<<m.size()<<endl;
? ? //刪除
? ? m.erase(m.begin()); //按照迭代器刪除
? ? m.erase(6); ? //按照key值刪除
? ? printmap(m);
? ? }
```
查找 統(tǒng)計(jì)
`find()` 查找key值是否存在,不存在返回set.end;
```cpp
map<int, int>::iterator it = m.find(9);
? ? cout << (*it).first <<it->second<<endl;
```
cout() ?0or1
使用仿函數(shù)改變map的默認(rèn)排序 ?由大到小
> 仿函數(shù) 傳入的時(shí)候傳入一個(gè)數(shù)據(jù)類型,在類中重載了()函數(shù)
? 重載()
?
```cpp
class Mycompare {
public:
? ? bool operator()(int v1, int v2) const ?自定義排序規(guī)則
? ? {
? ? ? ? return v1 > v2;
? ? }
};
```
```cpp
void printmap(map<int, int,Mycompare>& ma) {
? ? for (map<int, int>::const_iterator it = ma.begin(); it != ma.end(); it++)
? ? {
? ? ? ? cout << "key= " << (*it).first << " value=" << (*it).second << endl;
? ? }
? ? cout << endl;
}
void test() {
? ? //map容器
? ? map<int, int,Mycompare>m; ? ?//k v ?創(chuàng)建map容器
? ? m.insert(pair<int, int>(1, 10));
? ? m.insert(pair<int, int>(2, 28));
? ? m.insert(pair<int, int>(4, 20));
? ? m.insert(pair<int, int>(6, 21));
? ? m.insert(pair<int, int>(9, 320));
? ? m.insert(make_pair(10, 22));
? ? printmap(m);
}
```
### 函數(shù)對象
重載函數(shù)調(diào)用操作符的類,其對象成為函數(shù)對象
對()重載的函數(shù) 也叫仿函數(shù)
```cpp
#include<iostream>
using namespace std;
//1. 函數(shù)對象在使用時(shí),可以像普通函數(shù)那樣調(diào)用,可以有參數(shù),可以有返回值
class Mycompare {
public:
? ? int operator()(int v1, int v2) {
? ? ? ? return v1 + v1;
? ? }
};
void test() {
? ? Mycompare myadd;
? ? cout << myadd(10, 10) << endl;
}
//2. 函數(shù)對象可以有自己的狀態(tài)
class Myprint {
public:
? ? Myprint() {
? ? ? ? count = 0;
? ? ? ? }
? ? void operator()(string test) {
? ? ? ? cout << test << endl;
? ? ? ? this->count++;
? ? }
? ? int count; ?//內(nèi)部自己的狀態(tài)
};
void test1() {
? ? Myprint myprint;
? ? myprint("helloworld");
? ? myprint("helloworld");
? ? myprint("helloworld");
? ? cout << "myprint調(diào)用次數(shù)" << myprint.count << endl;
}
void doprint(Myprint& mp, string test) {
? ? mp(test);
}
//3. 函數(shù)對象可以作為參數(shù)傳遞
void test2() {
? ? Myprint my1;
? ? doprint(my1, "hello C++");
}
```
#### 內(nèi)建仿函數(shù)
**算術(shù)仿函數(shù)**
```cpp
#include<iostream>
#include<functional> ? ?//使用內(nèi)建函數(shù)對象時(shí),需要引入頭文件 #include<functional>
using namespace std;
void test() {
? ? //negate 一元仿函數(shù) 取反函數(shù)
? ? negate<int>n;
? ? cout << n(50) << endl;
}
void test1() {
? ? //plus 二元仿函數(shù) 加法
? ? plus<int>p;
? ? cout << p(10, 20) << endl;
}
```
**關(guān)系仿函數(shù)**
自定義降序仿函數(shù)定價(jià)與`greater<int>()` -> 需要使用`#include<functional>`
自定義
```cpp
class Mycompare {
public:
? ? bool operator()(int v1, int v2) const ?自定義排序規(guī)則
? ? {
? ? ? ? return v1 > v2;
? ? }
};
```
### STL-常用算法
算法主要是由頭文件<algorithm> 最大的一個(gè),涉及比較、交換、查找、遍歷<functional>仿函數(shù) ?<numeric>
**常用遍歷算法**
`for_each(iterator_beg;iterator_end;函數(shù) 仿函數(shù));`
```cpp
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//仿函數(shù)
class Myprint {
public:
? ? ?void operator()(int val) {
? ? ? ? cout << val;
? ? }
};
void printv(int val) {
? ? cout << val<<endl;
}
void test() {
? ? vector<int>v1;
? ? for (int i=0;i<10;i++)
? ? {
? ? ? ? v1.push_back(i);
? ? }
? ? //for_each算法
? ? for_each(v1.begin(),v1.end(), printv);
? ? for_each(v1.begin(), v1.end(), Myprint());
}
```
`transform(v.begin(),v.end(),target.begin(),fun_函數(shù))`
> 搬運(yùn)的目標(biāo)容器必須提前開辟空間,否則無法正常搬運(yùn)
```cpp
class Transform {
public:
? ? int operator()(int v) {
? ? ? ? return v;
? ? }
};
class Print {
public:
? ? void operator()(int val) {
? ? ? ? cout << val << endl;
? ? }
};
void test() {
? ? vector<int>v1;
? ? for (int i=1;i<10;i++)
? ? {
? ? ? ? v1.push_back(i);
? ? }
? ? vector<int>target;
? ? target.resize(v1.size()); ?//目標(biāo)容器需要提前開辟空間
? ? transform(v1.begin(), v1.end(), target.begin(), Transform());
? ? for_each(target.begin(), target.end(), Print());
}
```
**常用的查找算法**
1. `find`
`find(iterator.beg(),iter.end(),value)`
find 可以在容器中找指定的元素,返回值是迭代器
自定義類型 需要寫仿函數(shù) 對"=="就行重載
```cpp
class Person {
public:
? ? Person(string name, int age) {
? ? ? ? this->m_name = name;
? ? ? ? this->m_age = age;
? ? }
? ? string m_name;
? ? int m_age;
? ? bool operator ==(Person p2 ) {
? ? ? ? if (this->m_age==p2.m_age&&this->m_name==p2.m_name)
? ? ? ? {
? ? ? ? ? ? return true;
? ? ? ? }
? ? }
};
```
2. `find_if`
按條件查找
` ? vector<Person>::iterator it =find_if(p.begin(), p.end(), fun_仿函數(shù));`
3. `binary_search`
二分查找 對于有序的數(shù)列
`bool binary_search(it.beg(),it.end(),查找值)`
```cpp
? ? bool ret = binary_search(v1.begin(), v1.end(), 8);
? ? cout << ret << endl;
```
4. `count`
統(tǒng)計(jì)自定義類型時(shí) 需要配合重載`operator==`
自定義數(shù)據(jù)類型 就在自定義的類型里面就行仿函數(shù)的定義
內(nèi)建型 就添加寫一個(gè)類對運(yùn)算符進(jìn)行重載
5. `count_if`
```cpp
class mix14 ?//謂詞
{
public:
? ? bool operator()(int v1) {
? ? ? ? return v1 > 12;
? ? }
};
? ? int num =count_if(v1.begin(), v1.end(), mix14());
```
**常用排序算法**
1. `sort(it.beg(),it.end(),謂詞)`
```cpp
class ree {
public:
? ? bool operator()(int v1, int v2) {
? ? ? ? return v1 > v2;
? ? }
};
? ? sort(v1.begin(), v1.end(), ree());
```
2. 洗牌算法
random_shuffle(it.beg(),it.end())
```cpp
? ? srand((unsigned int)time(NULL)); ? //實(shí)時(shí)時(shí)間
? ? vector<int>v1;
? ? for (int i=1;i<10;i++)
? ? {
? ? ? ? v1.push_back(i);
? ? }
? ? random_shuffle(v1.begin(), v1.end());
? ? for_each(v1.begin(), v1.end(), print);
```
3. **merge算法**
```cpp
void test() {
? ? vector<int>v1;
? ? vector<int>v2;
? ? for (int i=1;i<10;i++)
? ? {
? ? ? ? v1.push_back(i);
? ? ? ? v2.push_back(i + 2);
? ? }
? ? vector<int>target;
? ? target.reserve()
? ? target.resize(v1.size() + v2.size()); ? ? //目標(biāo)容器定義大小
? ?
? ? merge(v1.begin(), v1.end(), v2.begin(), v2.end(), target.begin());
? ? for_each(target.begin(), target.end(), myprint);
}
```
4. **reverse算法**
` ? reverse(target.begin(), target.end());` ? 容器元素反轉(zhuǎn)
常用的拷貝和替換算法
`copy` 容器內(nèi)指定范圍的元素拷貝到另一容器總·
```cpp
? ? vector<int>tar2;
? ? tar2.resize(6);
? ? copy(target.begin(), target.begin() + 6, tar2.begin());
```
`replace`
`replace(tar3.begin(), tar3.end(), 5, 500); ` //將區(qū)間的5 替換成500
`replace_if`
```cpp
//謂詞
class mix5 { ?
public:
? ? bool operator()(int val) {
? ? ? ? return val > 5;
? ? }
};
? ? replace_if(tar3.begin(), tar3.end(), mix5(), 3000);
```
兩個(gè)容器元素合并,并儲(chǔ)存在另一個(gè)容器