C++学习笔记(九)

2021/12/31 C++

# 一、Vector容器

# 1.1基本概念

vector数据结构和数组非常类似,也称为单端数组

vector与普通数组的区别在于:数组是静态空间,然而vector是可以动态扩展

  • 动态扩展:并不是在原有空间之后续接新空间,而是找到更大的内存空间然后将原始数据拷贝到新空间然后释放原有空间
image-20211229194354307

# 1.2vector构造函数

  • vector<T> v;采用模板实现类实现,默认构造函数
  • victor(v.begin(), v.end());将v[begin(), end()]区间中的元素拷贝给本身
  • victor(n, elem);构造函数将n个elem拷贝给自身
  • vector(const vector &vec);拷贝构造函数
#include "iostream"
#include "vector"
using namespace std;

void printVector(vector<int> &vec) {
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        cout << *it << " ";
    }
    cout << endl;
}

int main() {
    // 默认构造
    vector<int> v1;
    for (int i = 0; i < 10; ++i) {
        v1.push_back(i);
    }
    printVector(v1);

    // 通过区间方式进行构造
    vector<int> v2(v1.begin(), v1.end());
    printVector(v2);

    // n个elem方式构造
    vector<int> v3(10, 100);
    printVector(v3);

    // 拷贝构造
    vector<int> v4(v3);
    printVector(v4);
}

# 1.3vector赋值操作

  • vector &operator = (const vector &vec);重载等号操作符
  • assign(beg, end);将[beg, end]区间中的数据拷贝赋值给本身
  • assign(n, elem);将n个elem拷贝赋值给本身
#include "iostream"
#include "vector"
using namespace std;

void printVector(vector<int> &vec) {
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        cout << *it << " ";
    }
    cout << endl;
}

int main() {
    vector<int> v1;
    for (int i = 0; i < 10; ++i) {
        v1.push_back(i);
    }
    printVector(v1);

    vector<int> v2;
    v2 = v1;
    printVector(v2);

    vector<int> v3;
    v3.assign(v1.begin(), v1.end());
    printVector(v3);

    vector<int> v4;
    v4.assign(10, 100);
    printVector(v4);
}

# 1.4vector容量操作

  • empty()判断是否为空
  • capacity()容器的容量
  • size()返回容器中元素的个数
  • resize(int num)重新制定容量的长度为num,如果变长则用默认值0填充新位置,如果变短,超出的部分元素被删除
  • resize(int num, elem)重新制定容量长度为num,如果变长则用elem值填充新位置,如果变短,超出的部分元素被删除
//
// Created by Jacob Lee on 2021/12/29.
//
#include "iostream"
#include "vector"
using namespace std;

void printVector(vector<int> &vec) {
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        cout << *it << " ";
    }
    cout << endl;
}

int main() {
    vector<int> v1;
    for (int i = 0; i < 10; ++i) {
        v1.push_back(i);
    }
    printVector(v1);

    if (v1.empty()) {
        cout << "空" << endl;
    } else {
        cout << "非空" << endl;
    }

    int cap = v1.capacity();
    cout << cap << endl;

    int size = v1.size();
    cout << size << endl;

    // 重新制定大小
    v1.resize(15);
    printVector(v1);

    // 重新制定大小(重载)
    v1.resize(20, 1);
    printVector(v1);
}

# 1.5vector插入删除

  • push_back(ele)在尾部插入元素
  • pop_back()删除最后一个元素
  • insert(const_iterator pos, ele)迭代器指向位置pos插入元素ele
  • insert(const_iterator pos, int count, ele)迭代器指向位置pos插入count个元素ele
  • erase(const_iterator pos)删除迭代器指向的元素
  • erase(const_iterator pos, const_iterator end)删除迭代器从start到end之间的元素
  • clear()删除容器中所有元素

# 1.6数据存取

  • at(int idx)获取索引idx位置数据
  • operator[idx]获取索引idx位置数据
  • front()返回容器第一个数据
  • back()返回容器最后一个数据

# 1.7容器互换

  • swap(vec)将vec与本身的元素互换
#include "iostream"
#include "vector"
using namespace std;

void printVector(vector<int> &vec) {
    for (vector<int>::iterator it = vec.begin(); it != vec.end(); it++) {
        cout << *it << " ";
    }
    cout << endl;
}

int main() {
    vector<int> v1;
    for (int i = 0; i < 10; ++i) {
        v1.push_back(i);
    }
    printVector(v1);

    vector<int> v2;
    for (int i = 10; i < 20; ++i) {
        v2.push_back(i);
    }
    printVector(v2);

    v1.swap(v2);
    printVector(v1);
    printVector(v2);
}

巧妙地使用swap可以收缩内存空间

# 1.8vector预留空间

用于减少vector在动态扩展容量时的扩展次数

  • reserve(int len)容器中预留len个元素长度,预留的位置不可以进行初始化,元素不可以访问

# 二、Deque容器

# 2.1基本概念

双端数组,可以在头端进行插入删除操作

image-20211230101511543

deque与vector的区别:

  • vector对于头部的插入删除效率太低了,数据量越大,效率越低
  • deque对头部的插入删除速度会比vector快
  • vector访问元素的速度会比deque快,这和两者的内部实现有关
image-20211230102108933

deque的内部实现原理:

  • deque内部有一个中控器,维护着每一段缓冲区中的内容,缓冲区中存放的是真实的数据
  • 中控器维护的是每一个缓冲区的地址,使得使用deque时像一片连续的内存空间

deque容器的迭代器也是支持随机访问的

# 2.2deque构造函数

  • deque<T>默认构造函数
  • deque(beg, end)构造函数将[beg, end)区间中的元素拷贝给自身
  • deque(n, elem)构造函数将n个elem元素拷贝给自身
  • deque(const deque &deq)拷贝构造函数
#include "iostream"
#include "deque"
using namespace std;

void printDeque(const deque<int> &deq) {
    for (deque<int>::const_iterator it = deq.begin(); it != deq.end(); it++) {
        cout << * it << " ";
    }
    cout << endl;
}

int main() {
    deque<int> d1;
    for (int i = 0; i < 10; ++i) {
        d1.push_back(i);
    }
    printDeque(d1);

    deque<int> d2(d1.begin(), d1.end());
    printDeque(d2);

    deque<int> d3(10, 100);
    printDeque(d3);

    deque<int> d4(d3);
    printDeque(d4);
}

# 2.3deque赋值操作

  • deque& operator = (const deque &deq);重载等号操作符
  • assign(beg, end)将[beg, end]区间中的数据拷贝赋值给本身
  • assign(n, elem)将n个elem拷贝赋值给本身

# 2.4deque大小操作

  • empty()判断是否为空
  • size()返回容器中元素的个数
  • resize(int num)重新制定容量的长度为num,如果变长则用默认值0填充新位置,如果变短,超出的部分元素被删除
  • resize(int num, elem)重新制定容量长度为num,如果变长则用elem值填充新位置,如果变短,超出的部分元素被删除

# 2.5插入和删除

两端插入操作:

  • push_back(elem)在容器尾部添加一个元素
  • push_front(elem)在容器头部添加一个元素
  • pop_back()删除容器最后一个数据
  • pop_front()删除容器第一个数据

指定位置操作:

  • insert(pos, elem)在pos位置插入一个elem元素的拷贝,返回新数据的位置
  • insert(pos, n, elem)在pos位置插入n个elem数据,无返回值
  • insert(pos, beg, end)在pos位置插入[beg, end]区间的数据,无返回值
  • clear()清空容器的所有元素
  • erase(beg, end)删除[beg, end]区间的数据,返回下一个数据的位置
  • erase(pos)删除pos位置的数据,返回下一个数据的位置

# 2.6数据存取

  • at(int idx)获取索引idx位置数据
  • operator[idx]获取索引idx位置数据
  • front()返回容器第一个数据
  • back()返回容器最后一个数据

# 2.7deque排序

利用算法实现对deque容器进行排序

算法:sort(iterator beg, iterator end)对beg和end区间内所有元素进行排序

# 三、简单案例

#include "iostream"
#include "string"
#include "vector"
#include "deque"
#include "algorithm"
#include "ctime"
using namespace std;

class Person {
public:
    string m_Name;
    int m_Score;
    // 构造函数
    Person(string name, int score): m_Name(name), m_Score(score) {}
};

// 创建选手
void createPerson(vector<Person> &v) {
    string nameSpeed = "ABCDE";
    for (int i = 0; i < 5; i++) {
        string name = "Player";
        name += nameSpeed[i];
        // cout << name << endl;
        int score = 0;
        Person p(name, score);
        // 将创建的对象放入容器中
        v.push_back(p);
    }
}

// 测试打印
void printVector(const vector<Person> &v) {
    for (vector<Person>::const_iterator it = v.begin(); it != v.end(); it++) {
        cout << "选手" << it->m_Name << "的分数是:" << it->m_Score << endl;
    }
}

// 打分函数
void setScore(vector<Person> &v) {
    for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) {
        // 存放分数至deque容器中
        deque<int> d;
        for (int i = 0; i < 10; i++) {
            // 给定随机分
            int score = rand() % 41 + 60;
            d.push_back(score);
        }
        sort(d.begin(), d.end());
        // 去除最高分最低分
        d.pop_back();
        d.pop_front();
        // 取平均分
        int sum = 0;
        for (deque<int>::iterator dit = d.begin(); dit != d.end(); dit++) {
            sum += *dit;
        }
        int avg = sum / d.size();

        // 将平均分赋值给选手
        it->m_Score = avg;
    }
}

int main() {
    // 添加随机数种子
    srand((unsigned int) time(NULL));
    // 创建选手
    vector<Person> v;
    // 给选手打分
    createPerson(v);
    setScore(v);
    // 显示最后得分
    printVector(v);
    return 0;
}