最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊

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

2022-10-26 10:56 作者:Ctrl_CVa  | 我要投稿

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è)容器


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

分享到微博請遵守國家法律
佛教| 绥芬河市| 玉林市| 昭苏县| 云浮市| 南乐县| 怀化市| 特克斯县| 南岸区| 精河县| 揭阳市| 绥德县| 惠水县| 兴仁县| 崇明县| 都昌县| 禹州市| 婺源县| 云和县| 临西县| 辉县市| 连城县| 南涧| 璧山县| 长汀县| 丰城市| 棋牌| SHOW| 庆城县| 黄龙县| 建瓯市| 任丘市| 左权县| 察雅县| 敖汉旗| 龙胜| 乌拉特后旗| 广宁县| 太保市| 华阴市| 星座|