导读:本文是C++数据结构学习系列的第一篇,主要讲解STL中最常用的两个容器——vector动态数组和string字符串容器。这些内容是C++编程的基础,也是算法竞赛和面试中高频考察的知识点。

目录

一、vector容器

vector是C++ STL中最常用的容器之一,它是一个动态数组,可以自动扩展容量。与普通数组相比,vector不需要预先指定大小,可以动态地添加和删除元素。

1.1 vector的创建方法

#include<bits/stdc++.h>
using namespace std;

int main() {
    // 1. 创建空数组
    vector<int> vec;
    vec.push_back(1);  // 空数组只能通过push_back添加元素
    vec.push_back(2);

    // 2. 创建数组指定元素个数(默认初始化为0)
    int n = 10;
    vector<int> vec1(n);       // 10个元素,默认值为0
    vector<int> vec2(n, -1);   // 10个元素,全部初始化为-1

    // 3. 拷贝构造——使用已存在的数组创建新数组
    vector<int> vec3(vec2);    // 拷贝vec2的所有元素

    // 4. 使用已存在数组的一部分创建新数组
    vector<int> vec4(vec1.begin() + 4, vec1.end()); // 从索引4到末尾

    // 5. 列表初始化
    vector<int> vec5 = {1, 2, 3, 4, 5, 6};

    return 0;
}

创建方式汇总表:

创建方式 代码示例 说明
空数组 vector<int> vec; 需要push_back添加元素
指定大小 vector<int> vec(n); 默认初始化为0
指定大小和值 vector<int> vec(n, val); 所有元素初始化为val
拷贝构造 vector<int> vec2(vec1); 复制vec1的所有元素
区间构造 vector<int> vec(vec1.begin(), vec1.end()); 复制指定区间
列表初始化 vector<int> vec = {1,2,3}; C++ 11特性

1.2 vector与输入

定长输入:

#include<iostream>
#include<vector>
using namespace std;
int main() {
    int n;
    cin >> n;
    vector<int> vec;
    for (int i = 0; i < n; i++) {
        int x;
        cin >> x;
        vec.push_back(x);
    }
    // 或者使用指定大小的vector直接通过下标输入
    vector<int> vec1(n);
    for (int i = 0; i < n; i++) {
        cin >> vec1[i];
    }
    return 0;
}

不定长输入:

// 结束输入方法:输入非数字字符或Ctrl+Z(添加EOF结束符)
vector<int> vec;
int x;
while (cin >> x) {
    vec.push_back(x);
}

1.3 vector常用函数

函数名 作用
size() 返回元素数量
empty() 判断是否为空
push_back() 在末尾添加元素
pop_back() 移除最后一个元素
front() 返回第一个元素
back() 返回最后一个元素
begin() / end() 返回首/尾迭代器
clear() 清空所有元素
insert() 在指定位置插入元素
erase() 删除指定元素
resize() 改变元素数量
reserve() 预分配容量
capacity() 返回当前容量
swap() 交换两个vector
vector<int> vec(10, 0);

vec.push_back(1);   // 末尾插入元素1
vec.pop_back();     // 删除末尾元素(空数组不能pop_back)

vec.capacity();      // 返回当前容量
vec.resize(5);      // 保留前5个元素,容量不变
vec.reserve(20);    // 预分配容量为20(容量无法改小)

1.4 vector的迭代器

迭代器是指向容器中元素的"指针",可以用来遍历容器。

#include<iostream>
#include<vector>
using namespace std;
int main() {
    vector<int> vec = {1, 2, 3, 4, 5, 6};
    vector<int>::iterator begin_i = vec.begin();
    vector<int>::iterator end_i = vec.end();

    // 通过迭代器遍历
    for (vector<int>::iterator i = begin_i; i < end_i; i++) {
        cout << *i << " ";  // 解引用获取元素值
    }
    return 0;
}

1.5 vector的增强for循环

C++11引入的范围for循环,写法更简洁:

vector<int> vec = {1, 2, 3, 4, 5, 6};
// 增强for循环(auto自动推导类型)
for (auto i : vec) {
    cout << i << " ";
}

1.6 vector的sort排序

sort()函数在<algorithm>头文件中,默认升序排序。自定义排序有三种方式:

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

// 方式1:比较函数
bool cmp(int a, int b) {
    return a > b;  // 从大到小
}

// 方式2:函数对象(仿函数)
class cmp1 {
public:
    bool operator()(int a, int b) {
        return a > b;  // 从大到小
    }
};

int main() {
    vector<int> vec = {2, 1, 4, 3, 6, 5, 7, 8, 9};

    // sort(vec.begin(), vec.end(), cmp);       // 方式1
    // sort(vec.begin(), vec.end(), cmp1());    // 方式2

    // 方式3:lambda表达式(推荐)
    sort(vec.begin(), vec.end(), [=](int a, int b) {
        return a > b;  // 从大到小
    });

    /*
        lambda格式:[] () {}
        []: 捕获外部变量
            [=]: 值捕获(只读)
            [&]: 引用捕获(可读写)
        (): 参数列表
        {}: 函数体
    */

    for (auto i : vec) {
        cout << i << " ";
    }
    return 0;
}

LeetCode实战:977. 有序数组的平方

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        for (int i = 0; i < nums.size(); i++) {
            nums[i] *= nums[i];  // 先求平方
        }
        sort(nums.begin(), nums.end());  // 再排序
        return nums;
    }
};

1.7 vector创建二维数组

#include<iostream>
#include<vector>
using namespace std;

int main() {
    int n = 10;

    // 创建空二维数组
    vector<vector<int>> vec1;

    // 创建n*n的二维数组,初始化为1
    vector<vector<int>> vec2(n, vector<int>(n, 1));
    cout << vec2[0][1] << endl;  // 访问元素

    // 遍历输出
    for (int i = 0; i < vec2.size(); i++) {
        for (int j = 0; j < vec2[i].size(); j++) {
            cout << vec2[i][j] << " ";
        }
        cout << endl;
    }

    // 增强for循环遍历
    for (auto i : vec2) {
        for (auto j : i) {
            cout << j << " ";
        }
        cout << endl;
    }
    return 0;
}

LeetCode实战:59. 螺旋矩阵 II

class Solution {
public:
    vector<vector<int>> vec;
    vector<vector<int>> generateMatrix(int n) {
        vec.resize(n, vector<int>(n));
        int t = 0, b = n - 1;  // 上下边界
        int l = 0, r = n - 1;  // 左右边界

        for (int num = 1; num <= n * n; ) {
            for (int i = l; i <= r; i++) vec[t][i] = num++;  // 从左到右
            t++;
            for (int i = t; i <= b; i++) vec[i][r] = num++;  // 从上到下
            r--;
            for (int i = r; i >= l; i--) vec[b][i] = num++;  // 从右到左
            b--;
            for (int i = b; i >= t; i--) vec[i][l] = num++;  // 从下到上
            l++;
        }
        return vec;
    }
};

二、string字符串容器

string是C++ STL中的字符串容器,封装了C语言中的字符数组,提供了丰富的字符串操作方法。

2.1 cin输入

cin读取字符串时,遇到空格、制表符、回车即停止。

#include<bits/stdc++.h>
using namespace std;

int main() {
    vector<string> vec;
    string s;

    // 定长输入
    int n; cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> s;
        vec.push_back(s);
    }

    // 不定长输入
    while (cin >> s) {
        vec.push_back(s);
    }

    for (auto i : vec) {
        cout << i << endl;
    }
    return 0;
}

2.2 getline输入

getline可以读取整行字符串,包括空格。

#include<bits/stdc++.h>
using namespace std;

int main() {
    vector<string> vec;
    string s;

    // 读取一行(包括空格)
    getline(cin, s);
    cout << s << endl;

    // 不定行数输入
    while (getline(cin, s)) {
        vec.push_back(s);
    }

    for (auto i : vec) {
        cout << i << endl;
    }
    return 0;
}

2.3 cin与getline混合输入

当先使用cin再使用getline时,必须在cin之后使用cin.ignore()清除缓冲区中的换行符。

#include<bits/stdc++.h>
using namespace std;

int main() {
    vector<string> vec;
    string s;
    int n; cin >> n;

    // 关键:清除cin留下的换行符
    cin.ignore();

    for (int i = 0; i < n; i++) {
        getline(cin, s);
        vec.push_back(s);
    }
    for (auto i : vec) {
        cout << i << endl;
    }
    return 0;
}

2.4 string常用处理函数

函数 作用 示例
push_back(c) 尾部插入字符 s.push_back('a');
insert(pos, str) 指定位置插入 s.insert(2, "abc");
erase(pos, len) 删除指定位置字符 s.erase(4, 2);
find(str) 查找子串位置 s.find("cd");
substr(pos, len) 截取子串 s.substr(4, 4);
pop_back() 删除末尾字符 s.pop_back();
clear() 清空字符串 s.clear();
isdigit(c) 判断是否为数字 isdigit(s[0]);
isalpha(c) 判断是否为字母 isalpha(s[0]);

字符串查找与截取示例:

string s = "abcd1234abcd!@#";

// find()查找
cout << s.find('d') << endl;       // 输出3
cout << s.find("cd") << endl;      // 输出3
cout << s.find('y') << endl;        // 未找到,返回一个很大的数

// 判断查找结果
size_t pos;
if ((pos = s.find('!')) != string::npos) {
    cout << "找到了,位置:" << pos << endl;
}

// substr()截取
string s1 = s.substr(4);      // 从下标4截取到最后
string s2 = s.substr(4, 4);   // 从下标4截取4个字符 -> "1234"

// erase()删除
s.erase(4);                    // 从下标4删除到最后
s.erase(4, 15);                // 从下标4删除15个字符

LeetCode实战:151. 反转字符串中的单词

class Solution {
public:
    // 去除多余空格
    void remove(string &s) {
        int index = 0;
        for (int i = 0; i < s.size(); ) {
            if (s[i] == ' ') i++;
            else {
                if (index != 0) s[index++] = ' ';
                while (i < s.size() && s[i] != ' ') {
                    s[index++] = s[i++];
                }
            }
        }
        s.erase(index);
    }

    string reverseWords(string s) {
        remove(s);
        reverse(s.begin(), s.end());  // 先整体翻转
        int start = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == ' ') {
                reverse(s.begin() + start, s.begin() + i);  // 再翻转每个单词
                start = i + 1;
            }
        }
        reverse(s.begin() + start, s.end());  // 翻转最后一个单词
        return s;
    }
};

更多推荐