C++學(xué)習(xí)四:高級(jí)

STL容器相關(guān)

一、vector向量

// Java的集合框架 非常強(qiáng)大  相當(dāng)于  C++  STL(標(biāo)準(zhǔn)模板庫(kù)) #include <iostream>
// TODO STL 是“Standard Template Library”的縮寫,中文譯為“標(biāo)準(zhǔn)模板庫(kù)”。STL 是 C++ 標(biāo)準(zhǔn)庫(kù)的一部分,不用單獨(dú)安裝。
// STL 有很多很多的容器
// C ++ vector 向量 容器 (內(nèi)部:封裝動(dòng)態(tài)大小數(shù)組作為容器,能夠存放任意的動(dòng)態(tài)數(shù)組【數(shù)據(jù)結(jié)構(gòu)】)
#include <iostream>
#include <vector> // 引入 vector 容器的支持
using namespace std;
int main() {
    vector<int> vector1;
    vector<int> vector2(10); // 指定10的空間大小
    vector<int> vector3(10, 0); // 有了10個(gè)值了 每個(gè)值都是0
    vector<int> vector4;
    // vector4.begin() 迭代器 插入到前面
    // vector4.end() 迭代器 插入到后面
    // 插入數(shù)據(jù)
    vector4.insert(vector4.begin(), 40);
    vector4.insert(vector4.begin(), 60);
    vector4.insert(vector4.begin(), 80);
    vector4.insert(vector4.begin(), 100);
    vector4.insert(vector4.begin(), 200);

    // 第一個(gè)  200 100 80 60 40
    cout << " 修改前:vector4.front():" << vector4.front() << endl;  
    vector4.front() = 99; // 默認(rèn)修改第一個(gè)
    cout << " 修改后:vector4.front():" << vector4.front() << endl; 

    // 最后一個(gè)
    cout << " 修改前:vector4.back():" << vector4.back() << endl;
    vector4.back() = 777; // 默認(rèn)修改最后 99 100 80 60 777
    cout << " 修改后:vector4.back():" << vector4.back() << endl;

    vector4.erase(vector4.begin()); // 移除第一個(gè)元素(內(nèi)部:通過(guò)迭代器的位置 進(jìn)行移除)  刪除 100 80 60 777

    // 循環(huán)打印,默認(rèn) 從大到小輸出
    for (int i = 0; i < vector4.size(); ++i) { 
        cout << "item:" << vector4[i] << endl; //100 80 60 777
    }

    // KT的類型推到  相當(dāng)于 C++ auto
    /*var a = 10;
    var b = 30.4f;
    var c = "";*/

    // 迭代器 循環(huán)遍歷
    // auto Kotlin自帶類型推導(dǎo)
    // for (vector<int>::iterator iteratorVar = vector4.begin(); iteratorVar != vector4.end(); iteratorVar++) {
    for (auto iteratorVar = vector4.begin(); iteratorVar != vector4.end(); iteratorVar++) {
        // 迭代器 當(dāng)中指針操作  iteratorVar++
        cout << "迭代器:" << *iteratorVar << endl;
    }
    return 0;
}

二、stack棧

//  先進(jìn)后出
#include <iostream>
#include <stack>
using namespace std;
// NDK開(kāi)發(fā)者 幾乎用不到
int main() {
    stack<int> stackVar;

    // 壓棧(注意:stack無(wú)法指定那個(gè)位置去壓棧)
    stackVar.push(30);
    stackVar.push(60);
    stackVar.push(90);
    //90 60 30

    // [] 角標(biāo)是不行的,內(nèi)部沒(méi)有重載此運(yùn)算符
    /*for (int i = 0; i < stackVar.size(); ++i) {
        // cout << stackVar[i] << endl;
        // cout << stackVar.at() << endl;
    }*/

    // 他根本就沒(méi)有迭代器
    // 開(kāi)發(fā)者 自己組裝 迭代器 遍歷
    /*for (stack<int>::iterator; i < ; ++i) {
    }*/

    // 慎用,為什么? 元素被彈完了
    // 這種方式是可以的,手槍把子彈全部打完【會(huì)把元素清空】
    while (!stackVar.empty()) {
        int top = stackVar.top(); // top == 獲取棧頂?shù)脑?        cout << "獲取棧頂?shù)脑兀? << top << endl; // 永遠(yuǎn)拿 90
        stackVar.pop(); // 把棧頂?shù)脑?彈出去  【刪除】
    }
    /*int top = stackVar.top();
    cout << top << endl;*/
    return 0;
}

三、隊(duì)列queue

//先進(jìn)先出
#include <iostream>
#include <queue> // 隊(duì)列支持(內(nèi)部:基本上 鏈表 、 數(shù)組 )
using namespace std;
int main() {
    queue<int> queueVar;

    queueVar.push(20);
    queueVar.push(40);
    queueVar.push(60);
    //20 40 60 
    // 第一個(gè)元素是誰(shuí) 20  FIFO 原則
    cout << " 修改前: queueVar.front():" << queueVar.front() << endl;
    queueVar.front() = 88;  //88 40 60 
    cout << " 修改后: queueVar.front():" << queueVar.front() << endl;

    // 最后一個(gè)
    cout << " 修改前: queueVar.back():" << queueVar.back() << endl;
    queueVar.back() = 88; // 88 40 88
    cout << " 修改后: queueVar.back():" << queueVar.back() << endl;

    // 沒(méi)有找到 角標(biāo)
    /*for (int i = 0; i < 9; ++i) {
        queueVar[i];
    }*/

    // 他根本就沒(méi)有迭代器
    /*for (queue<int>::iterator; i < ; ++i) {
    }*/

    // 慎用,為什么? 前面的元素全部被消費(fèi)完了
    while (!queueVar.empty()) {
        cout << "while1:" << queueVar.front() << endl;
        queueVar.pop(); // 把前面的元素 給消費(fèi)掉  【刪除】
    }
    return 0;
}

四、list

/ / Java:ArrayList采用Object[]數(shù)組,   C++的list 內(nèi)部:采用鏈表
#include <iostream>
#include <list> // list容器的支持
using namespace std;
int main() {
    list<int> listVar;

    // 插入操作
    listVar.push_front(50); // 插入到前面   明確
    listVar.push_back(60); // 插入到后面
    listVar.insert(listVar.begin(), 70); // 插入到前面  靈活
    listVar.insert(listVar.end(), 80); // 插入到后面
    //70 50 60 80
    // 修改操作
    listVar.back() = 88;
    listVar.front() = 55;

    // 刪除
    listVar.erase(listVar.begin()); // 刪除最前面的 55
    listVar.erase(listVar.end()); // 刪除最后面的 88

    // list 迭代器
    // 不用通過(guò)角標(biāo)去訪問(wèn),也不能修改   遍歷
    for (list<int>::iterator it = listVar.begin(); it != listVar.end() ; it ++) {
        cout << *it << endl;
    }
    return 0;
}

五、set

// set(內(nèi)部:紅黑樹(shù)結(jié)構(gòu)),會(huì)對(duì)你存入的數(shù)據(jù)進(jìn)行排序,但是絕對(duì)不允許元素相同

#include <iostream>
#include <set>
using namespace std;
int main() {
    set<int, less<int>> setVar; //  __x < __y 從小到大,默認(rèn)情況下 就是 less
    // 添加參數(shù),不需要用迭代器,也不需要指定位置
    setVar.insert(1);
    setVar.insert(3);
    setVar.insert(2);
    setVar.insert(4);

    // 重復(fù)插入,并不會(huì)報(bào)錯(cuò)  std::pair<iterator, bool>
    pair<set<int, less<int>>::iterator, bool> res = setVar.insert(8);

    // res.first 獲取第一個(gè)元素 迭代器   當(dāng)前迭代器   最后一個(gè)位置
    // res.second 獲取第二個(gè)元素 bool
    bool insert_success = res.second;
    if (insert_success) {
        cout << "恭喜你,插入成功" << endl;
    } else {
        cout << "哎,插入失敗.." << endl;
    }

    // 全部遍歷  auto 自動(dòng)推到
    for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
        cout << *it << endl;
    }
    return 0;
}

六、謂詞

// 謂詞 設(shè)計(jì)對(duì)象的排序
#include <iostream>
#include <set>
using namespace std;
class Person {
public:
    string name;
    int id;
    Person(string name, int id) : name(name), id(id) {}
};

// C++ 都是一些常規(guī)的 謂詞  不能滿足功能, 模仿C++源碼的謂詞 自定義謂詞 解決這個(gè)問(wèn)題

// C++締造者寫的這個(gè)源碼 沒(méi)有對(duì)象比較的功能 【系統(tǒng)源碼謂詞 做不到對(duì)象比較功能】
// bool operator()(const _Tp& __x, const _Tp& __y) const { return __x < __y; }

// 我們就自定義這個(gè)功能  【自定義謂詞 沒(méi)有達(dá)到謂詞的標(biāo)準(zhǔn)】
bool doCompareAction(const Person& person1, const Person& person2) {
    return person1.id < person2.id;
};

// 真正的謂詞
struct doCompareAction2 {
public:
    bool operator() (const Person& __x, const Person& __y) {
        return __x.id < __y.id;
    }
};

struct doCompareAction3 {
public:
    bool operator() (const Person& __x, const Person& __y) {
        return __x.id > __y.id;
    }
};

int main() {
    // 默認(rèn)是 less  return 對(duì)象1 < 對(duì)象2;

    set<Person, doCompareAction2> setVar;

    // set<Person, doCompareAction3> setVar;

    // 構(gòu)建對(duì)象
    Person p1 ("Snake", 1);
    Person p2 ("kevin", 2);
    Person p3 ("Derry", 3);

    // 把構(gòu)建的對(duì)象 插入到 set 容器里面去
    setVar.insert(p1);
    setVar.insert(p2);
    setVar.insert(p3);

    // name string  ---  c_str() ---->   char *
    for (set<Person>::iterator it = setVar.begin(); it != setVar.end() ; it ++) {
        cout << it->name.c_str() << " , " << it->id << endl;
    }
    return 0;
}

七、線程

1、基礎(chǔ)
#include <iostream>
#include <pthread.h> 
using namespace std;

// void *(*)(void *)
void * customPthreadTask(void * pVoid) { // 異步線程  相當(dāng)于Java的Thread.run函數(shù)一樣
    // C++轉(zhuǎn)換static_cast  轉(zhuǎn)換指針操作的
    int * number = static_cast<int *>(pVoid); // pVoid==number int的地址,所以我用int*接收,很合理
    cout << "異步線程執(zhí)行了:" << *number << endl;

    return 0; // 必須返回
}

int main() {
    int number = 9527;
    /**
      int pthread_create (pthread_t *,  // 參數(shù)一:線程ID
                        const pthread_attr_t *, // 參數(shù)二:線程屬性
                        void *(*)(void *), // 參數(shù)三:函數(shù)指針的規(guī)則
                        void *); // 參數(shù)四:給函數(shù)指針傳遞的內(nèi)容,void * 可以傳遞任何內(nèi)容
     */
    pthread_t pthreadID; // 線程ID,每個(gè)線程都需要有的線程ID

    pthread_create(&pthreadID, 0, customPthreadTask, &number);

    return 0;
}

2、pthread的3種情況

//  第一種情況,main函數(shù)只要結(jié)束,不等異步線程,全部結(jié)束
//  第二種情況,我們開(kāi)發(fā)者,千萬(wàn)不要讓 main函數(shù)睡眠的方式,去等待異步線程
//  第三種情況,main函數(shù)一直等待 異步線程,只有異步線程執(zhí)行完成后,我在執(zhí)行 join后面的代碼
#include <iostream>
#include <pthread.h> // Derry Cygwin 有 pthreads支持
#include <unistd.h>
using namespace std;
// void *(*)(void *)
void * runTask(void * pVoid) { // 異步線程  子線程
    int number = *static_cast<int *>(pVoid);
    cout << "異步線程執(zhí)行了:" << number << endl;

    for (int i = 0; i < 10; ++i) {
        cout << "run:" << i << endl;
        sleep(1);
    }
    return 0;
}

int main() {
    int number = 999;

    pthread_t  pthreadID;
    pthread_create(&pthreadID, 0, runTask, &number);

    // 為了演示第二種情況
    // sleep(3); // main函數(shù)只 異步線程三秒鐘

    // 異步線程在執(zhí)行的過(guò)程中,我們的main函數(shù) 相當(dāng)于 阻塞在這里不動(dòng)了,只有異步線程執(zhí)行完成后,我才開(kāi)始執(zhí)行join后面的代碼
    pthread_join(pthreadID, 0);

    cout << "main函數(shù)即將彈棧..." << endl;
    return 0;
}

3、鎖

// C++ 互斥鎖 == Java版本(synchronize) 多線程操作的安全  持有內(nèi)置鎖
#include <iostream>
#include <pthread.h>
#include <queue>
#include <unistd.h> // sleep(秒)
using namespace std;

queue<int> queueData; // 定義一個(gè)全局的隊(duì)列,用于 存儲(chǔ)/獲取

pthread_mutex_t mutex; // 定義一個(gè)互斥鎖

// void *(*)(void *)
void * task(void * pVoid) {
    /*synchronize(鎖) {
        // code
    }*/

    pthread_mutex_lock(&mutex); // 鎖住

    cout << "異步線程-當(dāng)前線程的標(biāo)記是:" << *static_cast<int *>(pVoid) << "異步線程" << endl;

    if (!queueData.empty()) { // 有元素
        printf("異步線程-獲取隊(duì)列的數(shù)據(jù):%d\n", queueData.front());
        queueData.pop(); // 把數(shù)據(jù)彈出去,刪除的意思
    } else { // 沒(méi)有元素
        printf("異步線程-隊(duì)列中沒(méi)有數(shù)據(jù)了\n");
    }
    // sleep(0.2);
    pthread_mutex_unlock(&mutex); // 解鎖
    return 0;
}

int main()
{
    // 初始化 互斥鎖
    pthread_mutex_init(&mutex, NULL);

    // 給隊(duì)列 初始化數(shù)據(jù) 手動(dòng)增加數(shù)據(jù)進(jìn)去
    for (int i = 10001; i < 10011; ++i) {
        queueData.push(i);
    }

    // 一次性定義10個(gè)線程
    pthread_t pthreadIDArray[10];
    for (int i = 0; i < 10; ++i) {
        pthread_create(&pthreadIDArray[i], 0, task, &i);

        // 不能使用 join,如果使用(就變成順序的方式,就沒(méi)有多線程的意義了,所以不能寫join)
        // pthread_join(pthreadIDArray[i], 0);
    }

    // main函數(shù)等 異步線程
    sleep(12);
    // 銷毀 互斥鎖
    pthread_mutex_destroy(&mutex);
    cout << "main函數(shù)即將彈棧..." << endl;
    // 每次運(yùn)行 效果都不同:1,8,9,10,3,2,5,8
    // 每次運(yùn)行 效果都是錯(cuò)亂
    return 0;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容