首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ STL 容器完整學習筆記:string、vector、deque、list、set、map 等核心用法

     編輯:關於C++

1. string 字串操作

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

void string_basics() {
    string s1 = "craig david";
    string s2("7 days");
    string s3 = s2;
    string s4(10, 'a');           // "aaaaaaaaaa"
    cout << s4 << endl;
}

void string_traversal() {
    string s1 = "craig david";
    // 1. 陣列式
    for (int i = 0; i < s1.length(); ++i) cout << s1[i] << endl;
    // 2. 迭代器
    for (auto it = s1.begin(); it != s1.end(); ++it) cout << *it << " ";
    cout << endl;
    // 3. at() 含邊界檢查
    try {
        for (int i = 0; i < s1.length() + 3; ++i) cout << s1.at(i) << " ";
    } catch (...) { cout << "例外" << endl; }
}

void string_conversion() {
    string s1 = "walking away";
    const char* c = s1.c_str();   // string → C 字串
    printf("%s\n", c);

    char arr[50] = {0};
    s1.copy(arr, 4, 0);           // 複製前 4 字元到 char 陣列
    cout << arr << endl;          // "walk"
}

void string_concat() {
    string s1 = "alan", s2 = "jackson";
    string s3 = s1 + s2;
    s3.append(" pray");           // "alanjackson pray"
    cout << s3 << endl;
}

void string_find_replace() {
    string s1 = "apple google apple iphone";
    int idx = s1.find("google", 0); // 6

    // 統計 "apple" 出現次數
    int cnt = 0, pos = s1.find("apple", 0);
    while (pos != string::npos) {
        ++cnt; pos += 5; pos = s1.find("apple", pos);
    }

    // 替換第一個 "apple" 為 "jobs"
    s1.replace(0, 5, "jobs");
    // 替換所有 "apple"
    pos = s1.find("apple", 0);
    while (pos != string::npos) {
        s1.replace(pos, 5, "jobs");
        pos += 5; pos = s1.find("apple", pos);
    }
}

void string_erase_insert() {
    string s1 = "apple google apple iphone";
    auto it = find(s1.begin(), s1.end(), 'g');
    s1.erase(it);                 // 刪除單一字元
    s1.insert(0, "macos");        // 開頭插入
    s1.insert(s1.length(), " facebook"); // 結尾插入
    cout << s1 << endl;
}

void string_case_convert() {
    string s1 = "JASON";
    transform(s1.begin(), s1.end(), s1.begin(), ::tolower); // "jason"
    transform(s1.begin(), s1.end(), s1.begin(), ::toupper); // "JASON"
}

2. vector 動態陣列

#include <vector>

void printVector(const vector<int>& v) {
    for (int i = 0; i < v.size(); ++i) cout << v[i] << endl;
}

void vector_basics() {
    vector<int> v1;
    v1.push_back(20); v1.push_back(40); v1.push_back(15); v1.push_back(7);
    vector<int> v2 = v1;                    // 複製建構
    vector<int> v3(v1.begin(), v1.begin()+2); // 部分複製
    printVector(v3);
}

void vector_modify() {
    vector<int> v1 = {20, 40, 15, 7};
    v1.front() = 11;  // 修改首元素
    v1.back() = 90;   // 修改尾元素
    v1.pop_back();    // 刪除尾元素
    while (!v1.empty()) {
        cout << "末尾: " << v1.back() << endl;
        v1.pop_back();
    }
}

void vector_array_access() {
    vector<int> v1 = {20, 40, 15, 7};
    v1[2] += 10;                      // 隨機存取
    vector<int> v2(10);               // 預設大小 10
    for (int i = 0; i < v2.size(); ++i) v2[i] = i + 1;
    printVector(v2);
}

void vector_iterators() {
    vector<int> v1 = {20, 40, 15, 7};
    // 正向
    for (auto it = v1.begin(); it != v1.end(); ++it) cout << *it << endl;
    // 反向
    for (auto it = v1.rbegin(); it != v1.rend(); ++it) cout << *it << endl;
}

void vector_erase_insert() {
    vector<int> v1(10);
    iota(v1.begin(), v1.end(), 1);    // 1..10

    auto it = v1.begin() + 3;
    v1.erase(it);                     // 刪除單一位置
    v1.erase(v1.begin(), v1.begin()+3); // 刪除區間 [begin, begin+3)

    // 邊遍歷邊刪除(注意 erase 返回下一個有效迭代器)
    for (auto it = v1.begin(); it != v1.end(); ) {
        if (*it == 5) it = v1.erase(it);
        else ++it;
    }

    v1.insert(v1.begin() + 2, 100);   // 插入單一元素
    v1.insert(v1.end() - 1, 200);
    printVector(v1);
}

3. deque 雙向佇列

#include <deque>

void printDeque(const deque<int>& q) {
    for (int i = 0; i < q.size(); ++i) cout << q[i] << endl;
}

void deque_demo() {
    deque<int> d1;
    d1.push_back(2); d1.push_back(10); // 尾部插入
    d1.push_front(-90); d1.push_front(-30); // 頭部插入
    printDeque(d1);

    // 查找 -90 的索引
    auto it = find(d1.begin(), d1.end(), -90);
    if (it != d1.end()) {
        cout << "索引: " << distance(d1.begin(), it) << endl;
    }
}

4. stack / queue / priority_queue

#include <stack>
#include <queue>
#include <functional>

void stack_demo() {
    stack<int> s;
    for (int i = 0; i < 10; ++i) s.push(i+1);
    while (!s.empty()) { cout << s.top() << endl; s.pop(); }
}

void queue_demo() {
    queue<int> q;
    q.push(78); q.push(18); q.push(20); q.push(33);
    while (!q.empty()) { cout << q.front() << endl; q.pop(); }
}

void priority_queue_demo() {
    // 最大堆(預設)
    priority_queue<int> pq1;
    pq1.push(12); pq1.push(3); pq1.push(40); pq1.push(15);
    while (!pq1.empty()) { cout << pq1.top() << endl; pq1.pop(); }

    // 最小堆
    priority_queue<int, vector<int>, greater<int>> pq2;
    pq2.push(12); pq2.push(3); pq2.push(40); pq2.push(15);
    while (!pq2.empty()) { cout << pq2.top() << endl; pq2.pop(); }
}

5. 關聯式容器:list、set、map、multimap

list 雙向鏈結串列

#include <list>

void printList(const list<int>& lst) {
    for (auto it = lst.begin(); it != lst.end(); ++it) cout << *it << endl;
}

void list_demo() {
    list<int> lst;
    for (int i = 0; i < 10; ++i) lst.push_back(i);
    lst.push_front(80); lst.push_front(90);

    // list 不支援隨機存取,不可 it + 3
    auto it = lst.begin(); ++it; // 第二個元素
    lst.erase(it);               // 刪除單一
    lst.erase(lst.begin(), next(lst.begin(), 3)); // 刪除區間
    lst.remove(5);               // 依值刪除所有 5
    lst.insert(next(lst.begin()), 100); // 指定位置插入
    printList(lst);
}

set / multiset

#include <set>
#include <functional>

void printSet(const set<int>& s) {
    for (auto it = s.begin(); it != s.end(); ++it) cout << *it << endl;
}

void set_demo() {
    set<int> s;
    for (int i = 0; i < 10; ++i) s.insert(i+1);
    s.insert(20); s.insert(15); s.insert(15); // 重複值被忽略

    auto it = s.begin(); ++it; s.erase(it); // 刪除第二個

    // 自訂排序:由大到小
    set<int, greater<int>> s2;
    s2.insert(10); s2.insert(5); s2.insert(20); s2.insert(99);
    // 99, 20, 10, 5

    // 自訂類別排序
    struct Teacher { char* name; int age; };
    struct AgeCmp { bool operator()(const Teacher& a, const Teacher& b) { return a.age < b.age; } };
    set<Teacher, AgeCmp> s3;
    s3.insert({"jack", 18}); s3.insert({"rose", 20}); s3.insert({"jason", 22});
    // 依年齡排序,相同年齡視為相同(不會插入)

    // 查找範圍
    auto range = s.equal_range(4); // pair<lower_bound, upper_bound>
}

map

#include <map>
#include <string>

void printMap(const map<int, string>& m) {
    for (auto it = m.begin(); it != m.end(); ++it)
        cout << it->first << "," << it->second << endl;
}

void map_demo() {
    map<int, string> m;
    m.insert({1, "jack"});
    m.insert(make_pair(2, "rose"));
    m.insert(map<int,string>::value_type(3, "jason"));
    m[4] = "alan"; // 運算子[]:不存在則插入,存在則覆蓋

    // 刪除
    auto it = m.begin(); ++it; m.erase(it);

    // 檢查插入結果
    auto res = m.insert({3, "alan"});
    if (res.second) cout << "成功" << endl; else cout << "失敗(key已存在)" << endl;

    // equal_range 查找
    auto range = m.equal_range(2);
    if (range.first != m.end()) {
        cout << range.first->first << range.first->second << endl; // key=2
        cout << range.second->first << range.second->second << endl; // key>2
    }
}

multimap:一對多關係

struct Employee { char* name; int age; };

void multimap_demo() {
    multimap<string, Employee> dept;
    dept.insert({"開發", {"擱淺", 20}});
    dept.insert({"開發", {"彪哥", 20}});
    dept.insert({"財務", {"小穎", 16}});
    dept.insert({"財務", {"rose", 20}});

    // 遍歷所有
    for (auto it = dept.begin(); it != dept.end(); ++it)
        cout << it->first << "," << it->second.name << "," << it->second.age << endl;

    // 僅取得「財務」部門員工
    int cnt = dept.count("財務");
    auto it = dept.find("財務");
    for (int i = 0; i < cnt && it != dept.end(); ++it, ++i)
        cout << it->first << "," << it->second.name << "," << it->second.age << endl;
}

6. 深拷貝與淺拷貝問題

含指標成員的類別若未自訂拷貝建構函數與指派運算子,預設淺拷貝會導致雙重釋放錯誤:

class Employee {
    char* name;
    int age;
public:
    Employee(const char* n, int a) {
        name = new char[strlen(n)+1];
        strcpy(name, n);
        age = a;
    }
    ~Employee() { delete[] name; }

    // 深拷貝建構函數
    Employee(const Employee& obj) {
        name = new char[strlen(obj.name)+1];
        strcpy(name, obj.name);
        age = obj.age;
    }
    // 深拷貝指派運算子
    Employee& operator=(const Employee& obj) {
        if (this != &obj) {
            delete[] name;
            name = new char[strlen(obj.name)+1];
            strcpy(name, obj.name);
            age = obj.age;
        }
        return *this;
    }
};

將此類物件放入 vector 時,push_back 會觸發拷貝建構,深拷貝確保各物件擁有獨立記憶體,析構時不會重複釋放。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved