From 9290e4c051b5597359880a3433132daaaf92092c Mon Sep 17 00:00:00 2001 From: flykhan Date: Fri, 4 Aug 2023 09:28:07 +0800 Subject: [PATCH] =?UTF-8?q?stl=E7=AC=AC=E4=B8=80=E9=83=A8=E5=88=86:=20stri?= =?UTF-8?q?ng,=20vector,=20deque,=20stack?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- day9/readme.md | 468 +++++++++++++++++++++++++++++++++++ day9/stl_deque_demo/d1.cpp | 53 ++++ day9/stl_deque_demo/d2.cpp | 20 ++ day9/stl_deque_demo/d3.cpp | 41 +++ day9/stl_deque_demo/d4.cpp | 43 ++++ day9/stl_deque_demo/d5.cpp | 22 ++ day9/stl_deque_demo/d6.cpp | 18 ++ day9/stl_deque_demo/d7.cpp | 32 +++ day9/stl_deque_demo/d8.cpp | 37 +++ day9/stl_stack_demo/d1.cpp | 53 ++++ day9/stl_stack_demo/d2.cpp | 142 +++++++++++ day9/stl_stack_demo/d2_2.cpp | 158 ++++++++++++ day9/stl_string_demo/d1.cpp | 54 ++++ day9/stl_string_demo/d2.cpp | 28 +++ day9/stl_vector_demo/d10.cpp | 45 ++++ day9/stl_vector_demo/d11.cpp | 35 +++ day9/stl_vector_demo/d3.cpp | 28 +++ day9/stl_vector_demo/d4.cpp | 23 ++ day9/stl_vector_demo/d5.cpp | 28 +++ day9/stl_vector_demo/d6.cpp | 20 ++ day9/stl_vector_demo/d7.cpp | 36 +++ day9/stl_vector_demo/d8.cpp | 30 +++ day9/stl_vector_demo/d9.cpp | 34 +++ 23 files changed, 1448 insertions(+) create mode 100644 day9/readme.md create mode 100644 day9/stl_deque_demo/d1.cpp create mode 100644 day9/stl_deque_demo/d2.cpp create mode 100644 day9/stl_deque_demo/d3.cpp create mode 100644 day9/stl_deque_demo/d4.cpp create mode 100644 day9/stl_deque_demo/d5.cpp create mode 100644 day9/stl_deque_demo/d6.cpp create mode 100644 day9/stl_deque_demo/d7.cpp create mode 100644 day9/stl_deque_demo/d8.cpp create mode 100644 day9/stl_stack_demo/d1.cpp create mode 100644 day9/stl_stack_demo/d2.cpp create mode 100644 day9/stl_stack_demo/d2_2.cpp create mode 100644 day9/stl_string_demo/d1.cpp create mode 100644 day9/stl_string_demo/d2.cpp create mode 100644 day9/stl_vector_demo/d10.cpp create mode 100644 day9/stl_vector_demo/d11.cpp create mode 100644 day9/stl_vector_demo/d3.cpp create mode 100644 day9/stl_vector_demo/d4.cpp create mode 100644 day9/stl_vector_demo/d5.cpp create mode 100644 day9/stl_vector_demo/d6.cpp create mode 100644 day9/stl_vector_demo/d7.cpp create mode 100644 day9/stl_vector_demo/d8.cpp create mode 100644 day9/stl_vector_demo/d9.cpp diff --git a/day9/readme.md b/day9/readme.md new file mode 100644 index 0000000..5d53ece --- /dev/null +++ b/day9/readme.md @@ -0,0 +1,468 @@ +# STL(一) + +### 1. string 容器 + +> string 也是字符串的类型,可以理解时它是用于存放字符的容器。 + +#### 1.1 String 和 c 风格字符串对比 + +``` +1) char * 是一个指针,string 是一个类 +2) string 封装了很多实用的成员方法 + 查找 find,拷贝 copy,删除 delete 替换 replace,插入 insert +3) 不用考虑内存释放和越界 + string 管理 char*所分配的内存。每一次 string 的复制,取值都由 string 类负责维 +护,不用担心复制越界和取值越界等。 +``` + +#### 1.2 string 容器 api + +``` +// 构造函数 +string(); //创建一个空的字符串 例如: string str; +string(const string& str);//使用一个 string 对象初始化另一个 string 对象 +string(const char* s);//使用字符串 s 初始化 +string(int n, char c); //使用 n 个字符 c 初始化 + +// 赋值 +string& operator=(const char* s);//char*类型字符串 赋值给当前的字符串 +string& operator=(const string &s);//把字符串 s 赋给当前的字符串 +string& operator=(char c);//字符赋值给当前的字符串 +string& assign(const char *s);//把字符串 s 赋给当前的字符串 +string& assign(const char *s, int n); //把字符串 s 的前 n 个字符赋给当前的字 +符串 +string& assign(const string &s);//把字符串 s 赋给当前字符串 +string& assign(int n, char c);//用 n 个字符 c 赋给当前字符串 +string& assign(const string &s, int start, int n);//将 s 从 start 开始 n 个 +字符赋值给字符串 + +// 取值 +char& operator[](int n);//通过[]方式取字符 +char& at(int n);//通过 at 方法获取字符 + + +// 字符串拼接 +string& operator+=(const string& str);//重载+=操作符 +string& operator+=(const char* str);//重载+=操作符 +string& operator+=(const char c);//重载+=操作符 +string& append(const char *s);//把字符串 s 连接到当前字符串结尾 +string& append(const char *s, int n);//把字符串 s 的前 n 个字符连接到当前字符串结尾 +string& append(const string &s); //同 operator+=() +string& append(const string &s, int pos, int n);//把字符串 s 中从 pos 的 n 个字符连接到当前字符串结尾 +string& append(int n, char c);//在当前字符串结尾添加 n 个字符 c + +// 查找与替换 +int find(const string& str, int pos = 0) const; //查找 str 第一次出现位置, 从 pos 开始查找, 如果未查找到返回 -1 +int find(const char* s, int pos = 0) const; //查找 s 第一次出现位置,从 pos 开始查找 +int find(const char* s, int pos, int n) const; //从 pos 位置查找 s 的前 n个字符第一次位置 +int find(const char c, int pos = 0) const; //查找字符 c 第一次出现位置 +int rfind(const string& str, int pos = npos) const;//查找 str 最后一次位置,从 pos 开始查找 +int rfind(const char* s, int pos = npos) const;//查找 s 最后一次出现位置, 从 pos 开始查找 +int rfind(const char* s, int pos, int n) const;//从 pos 查找 s 的前 n 个字符最后一次位置 +int rfind(const char c, int pos = 0) const; //查找字符 c 最后一次出现位置 +string& replace(int pos, int n, const string& str); //替换从 pos 开始 n 个字符为字符串 str +string& replace(int pos, int n, const char* s); //替换从 pos 开始的 n 个字符为字符串 s + +// 比较 ,返回值 0:相等, 1:大于s, -1:小于s +int compare(const string &s) const;//与字符串 s 比较 +int compare(const char *s) const;//与字符串 s + +// 截取子字符串 +string substr(int pos = 0, int n = npos) const;//返回由 pos 开始的 n 个字符组成的字符串 + +// 插入与删除 +string& insert(int pos, const char* s); //插入字符串 +string& insert(int pos, const string& str); //插入字符串 +string& insert(int pos, int n, char c);//在指定位置插入 n 个字符 c +string& erase(int pos, int n = npos);//删除从pos 开始的 n 个 + +// 转成 char * +const char * c_str() 将当前字符串转成 char * + +// 获取字符串的长度 +int size(); +``` + +### 2. vector 容器 + +#### 2.1 vector 与数组的区别 + +vector 的结构类同于数组,数组是静态的,在定义时确定的数组的大小;而 vector 是动态的,添加元素时如果空间不足时,则会自动扩容器(2^n);整体来说,vector 比较灵活的,而且 vector 是类模板,可以存放任意类型的元素。 + +#### 2.2 vector 迭代器 + +> vector 维护一个线性空间(线性连续空间), vector 迭代器所需要的操作行为 是(\*,->, ++, --, +, -, +=, -=)运算符重载等。vector 支持随机存取,vector 提供的是随机访问迭代器(Random Access Iterator), 迭代器中的元素即为 vector 容器中的元素。 + +【重要说明】: vector 容器扩容之后,原迭代器则无效,需要重新获取获取器 + +``` +所谓动态增加大小,并不是在原空间之后续接新空间(因为无法保证原空间之后尚有可配置的空间),而是一块更大的内存空间,然后将原数据拷贝新空间,并释放原空间。 +因此,对 vector 的任何操作,一旦引起空间的重新配置,指向原vector的所有迭代器就都失效了。这是程序员容易犯的一个错误,务必小心。 +``` + +#### 2.3 vector 容器 api + +##### 3.3.1 构造函数 + +``` +// 构造函数 +vector v; //采用模板实现类实现,默认构造函数 +vector(v.begin(), v.end());//将 v[begin(), end())区间中的元素拷贝给本身。 +vector(n, elem);//构造函数将 n 个 elem 拷贝给本身。 +vector(const vector &vec);//拷贝构造函 +``` + +##### 3.3.2 赋值操作 + +```c++ +assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。 +assign(n, elem);//将 n 个 elem 拷贝赋值给本身。 +vector& operator=(const vector &vec);//重载等号操作符 +swap(vec);// 将 vec 与本身的元素互换 +``` + +##### 3.3.3 大小操作 + +```c++ +int size(); // 返回容器中元素的个数 +bool empty(); //判断容器是否为空, 返回bool值(0, 1) +void resize(int num); //重新指定容器的长度为 num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。 +void resize(int num, elem); //重新指定容器的长度为 num,若容器变长,则以 elem 值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。 +int capacity(); //容器的容量 +void reserve(int len); //容器预留 len 个元素长度,预留位置不初始化,元素不可访问。 +``` + +##### 3.3.4 存取操作 + +```c++ +at(int idx); //返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range 异常。 +operator[](int idx); //返回索引 idx 所指的数据,越界时,运行直接报错 +front(); //返回容器中第一个数据元素 +back(); //返回容器中最后一个数据元素 +``` + +##### 3.3.5 插入和删除 + +```c++ +insert(const_iterator pos, int count, T ele); //迭代器指向位置 pos 插入 count个元素 ele. +push_back(ele); //尾部插入元素 ele +pop_back();//删除最后一个元素 +erase(const_iterator start, const_iterator end); //删除迭代器从 start 到 end 之间的元素, 删除[start, end)区间的所有元素 +erase(const_iterator pos); //删除迭代器指向的元素 +clear(); //删除容器中所有元素 +``` + +#### 2.4 小技巧示例 + +##### 2.2.4.1 巧用 swap 收缩内存空间 + +> resize()+swap()实现 vector 收缩内存空间 + +```c++ +resize(n); +vector(v).swap(v); +``` + +### 3. deque 容器 + +#### 3.1 deque 基本概念 + +vector 容器是单向开口的连续内存空间,deque 则是一种双向开口的连续线性空间。 + +所谓的双向开口,意思是可以在头尾两端分别做元素的插入和删除操作,当然,vector 容器也可以在头尾两端插入元素,但是在其头部操作效率奇差,无法被接受。 + +qeque 容器和 vector 容器最大的差异: + +``` +1) 在于 deque 允许使用常数项时间对头端进行元素的插入和删除操作。 +2) 在于 deque 没有容量的概念,因为它是动态的以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。 +3) deque 没有必须要提供所谓的空间保留(reserve)功能 +4) 虽然deque容器也提供了 Random Access Iterator,但是它的迭代器并不是普通的指针,其复杂度和vector 不是一个量级,这当然影响各个运算的层面。因此,除非有必要,我们应该尽可能的使用vector,而不是deque。 +5)对 deque 进行的排序操作,为了最高效率,可将 deque 先完整的复制到一个 vector 中,对 vector 容器进行排序,再复制回 deque。 +``` + +#### 3.2 deque 实现原理 + +逻辑上,deque 容器是连续的空间, 是由一段一段的定量的连续空间构成。一旦有必要在 deque 前端或者尾端增加新的空间,便配置一段连续定量的空间,串接在 deque 的头端或者尾端。 + +deque 最大的工作就是维护这些分段连续的内存空间的整体性的假象,并提供随机存取的接口。 + +既然 deque 是分段连续内存空间,那么就必须有中央控制(map 实现的),维持整体连续的假象,数据结构的设计及迭代器的前进后退操作颇为繁琐。 + +中央控制: 连续小空间,由 map 实现,存放是地址,地址指向的另一个连续空间为缓冲区。 + +缓冲区:是 deque 的存储空间的主体。 + +#### 3.3 常用 API + +##### 3.3.1 构造函数 + +```c++ +deque deqT;//默认构造形式 +deque(beg, end);//构造函数将[beg, end)区间中的元素拷贝给本身。 +deque(n, elem);//构造函数将 n 个 elem 拷贝给本身。 +deque(const deque &deq);//拷贝构造函数。 +``` + +##### 3.3.2 赋值操作 + +```c++ +assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。 +assign(n, elem);//将 n 个 elem 拷贝赋值给本身。 +deque& operator=(const deque &deq); //重载等号运算符 +swap(deq);// 将 deq 与本身的元素互换 +``` + +##### 3.3.3 大小操作 + +```c++ +deque.size();//返回容器中元素的个数 +deque.empty();//判断容器是否为空 +deque.resize(num);//重新指定容器的长度为 num,若容器变长,则以默认值填充新位置。如果容器变短,则末尾超出容器长度的元素被删除。 +deque.resize(num, elem); //重新指定容器的长度为 num,若容器变长,则以 elem 值填充新位置,如果容器变短,则末尾超出容器长度的元素被删除。 +``` + +##### 3.3.4 双端插入和删除 + +```c++ +void push_back(elem);//在容器尾部添加一个数据 +void push_front(elem);//在容器头部插入一个数据 +void pop_back();//删除容器最后一个数据 +void pop_front();//删除容器第一个数据 +``` + +##### 3.3.5 数据存取 + +```c++ +at(idx);//返回索引 idx 所指的数据,如果 idx 越界,抛出 out_of_range。 +operator[]; //返回索引 idx 所指的数据,如果 idx 越界,不抛出异常,会直接出错。 +front();//返回第一个数据。 +back();//返回最后一个 +``` + +如:operator[] 操作数据,超出范围之后,则会直接报错并不抛出异常 + +> 【注意】 string 泛型的 deque 默认分配 16 个, int 默认 128 个 + +##### 3.3.6 插入操作 + +```c++ +void insert(iterator pos,T elem);//在 pos 位置插入一个 elem 元素的拷贝,返回新数据的位置。 +void insert(iterator pos,int n,T elem);//在 pos 位置插入 n 个 elem 数据,无返回值。 +void insert(iterator pos,iter_beg,iter_end);//在 pos 位置插入[beg,end)区间的数据,无返回值。 +``` + +##### 3.3.7 删除操作 + +```c++ +clear();//移除容器的所有数据 +iterator erase(iterator beg,iterator end);//删除[beg,end)区间的数据,返回下一个数据的位置。 +iterator erase(iterator pos);//删除 pos 位置的数据,返回下一个数据的位置。 +``` + +### 4 stack 容器 + +#### 4.1 stack 基本概念 + +stack 是一种先进后出(First In Last Out,FILO)的数据结构,它只有一个出口,stack 容器允许新增元素、移除元素、取得栈顶元素,但是除了最顶端外,没有任何其他方法可以存取 stack 的其他元素。换言之,stack 不允许有遍历行为。 + + + +#### 4.2 stack 没有迭代器 + +stack 所有元素的进出都必须符合”先进后出”的条件,只有 stack 顶端的元素,才有机会被外界取用。Stack 不提供遍历功能,也不提供迭代器。 + +#### 4.3 常用 API + +##### 4.3.1 构造函数 + +``` +stack stkT;//stack 采用模板类实现, stack 对象的默认构造形式: +stack(const stack &stk);//拷贝构造函数 +``` + +##### 4.3.2 赋值操作 + +``` +stack& operator=(const stack &stk);//重载等号操作符 +``` + +##### 4.3.3 数据存取 + +```c++ +void push(elem);//向栈顶添加元素 +void pop();//从栈顶移除第一个元素 +T top();//返回栈顶元素 +``` + +##### 4.3.4 大小操作 + +``` +empty();//判断堆栈是否为空 +size();//返回堆栈的大小 +``` + +#### + +案例: 人员的淘汰方式(业绩从高到低、后入职) + +```c++ +#include +#include +#include + +using namespace std; +class Worker; +class Date +{ + friend Worker; + friend ostream &operator<<(ostream &cout, Date &date) + { + cout << date.year << "年" << date.month << "月" << date.day << "日"; + return cout; + } + +private: + int year; + int month; + int day; + +public: + Date(int year, int month, int day) + { + this->year = year; + this->month = month; + this->day = day; + } + bool operator>(Date &other) + { + // cout << *this << " pk " << other << endl; + return year > other.year || (year == other.year && month > other.month) || (year == other.year && month == other.month && day > other.day); + } + bool operator<=(Date &other) + { + return year <= other.year && month <= other.month && day <= other.day; + } +}; +class Worker +{ +public: + string name; // 姓名 + Date *hire_date; // 入职时间 + double volume; // 业绩值 + +public: + Worker(const string &name, Date *hire_date, double volume) + { + this->name = name; + this->hire_date = hire_date; + this->volume = volume; + } + Worker(const Worker &other) + { + Date *hire_date = new Date(other.hire_date->year, other.hire_date->month, other.hire_date->day); + this->hire_date = hire_date; + this->name = other.name; + this->volume = other.volume; + } + Worker &operator=(const Worker &other) + { + this->hire_date->year = other.hire_date->year; + this->hire_date->month = other.hire_date->month; + this->hire_date->day = other.hire_date->day; + this->name = other.name; + this->volume = other.volume; + return *this; + } + + ~Worker() + { + if (hire_date) + delete hire_date; + hire_date = NULL; + } + + void show() + { + cout << "name=" << name << ",hire_date=" << *hire_date << ",volume=" << volume << endl; + } +}; + +void sortByHireDate(Worker *p, int size) +{ + for (int i = 0; i < size - 1; i++) + { + int min = i; + for (int j = i + 1; j < size; j++) + { + if (*(p[min].hire_date) > *(p[j].hire_date)) + { + min = j; + } + } + if (min != i) + { + // cout << p[i].name << " 和 " << p[min].name << " 交换数据" << endl; + Worker tmp = p[i]; // 拷贝构造函数 + p[i] = p[min]; // operator=重载 + p[min] = tmp; + } + } +} + +void sortByVolume(Worker *p, int size) +{ + for (int i = 0; i < size - 1; i++) + { + int min = i; + for (int j = i + 1; j < size; j++) + { + if (p[min].volume < p[j].volume) + { + min = j; + } + } + if (min != i) + { + // cout << p[i].name << " 和 " << p[min].name << " 交换数据" << endl; + Worker tmp = p[i]; // 拷贝构造函数 + p[i] = p[min]; // operator=重载 + p[min] = tmp; + } + } +} + +int main(int argc, char const *argv[]) +{ + Worker w1("disen", new Date(2020, 1, 15), 1000); + Worker w2("jack", new Date(2021, 1, 15), 100); + Worker w3("lucy", new Date(2020, 2, 15), 500); + Worker w4("mack", new Date(2020, 3, 25), 300); + Worker w5("judy", new Date(2022, 5, 18), 400); + Worker w6("rose", new Date(2023, 1, 10), 1200); + + Worker m[] = {w1, w2, w3, w4, w5, w6}; + // sortByHireDate(m, 6); + sortByVolume(m, 6); + vector v1(m, m + 6); + stack s1; + vector::iterator it = v1.begin(); + while (it != v1.end()) + { + (*it).show(); + s1.push(*it); + it++; + } + + // 辞退2位新来的员工 + // cout << "-----辞退2位新来的员工----" << endl; + cout << "-----业绩最差的2位员工----" << endl; + for (int i = 0; i < 2; i++) + { + s1.top().show(); + s1.pop(); + } + + return 0; +} +``` diff --git a/day9/stl_deque_demo/d1.cpp b/day9/stl_deque_demo/d1.cpp new file mode 100644 index 0000000..b2a992d --- /dev/null +++ b/day9/stl_deque_demo/d1.cpp @@ -0,0 +1,53 @@ +// deque 的使用 +// deque 是一个双端队列,可以在队列的头部和尾部进行插入和删除操作 + +// deque 的常用操作 +// push_back() 在队列尾部插入元素 +// push_front() 在队列头部插入元素 +// front() 访问队列头部元素 +// back() 访问队列尾部元素 +// pop_front() 删除队列头部元素 +// pop_back() 删除队列尾部元素 +// size() 队列的大小 +// empty() 队列是否为空 +// clear() 清空队列 +// erase() 删除指定位置的元素 +// insert() 在指定位置插入元素 +// operator[] 访问指定位置的元素 +// at() 访问指定位置的元素 +// begin() 返回指向队列头部的迭代器 +// end() 返回指向队列尾部的迭代器 +// rbegin() 返回指向队列尾部的逆向迭代器 +// rend() 返回指向队列头部的逆向迭代器 +// swap() 交换两个队列 +// emplace() 在指定位置构造元素 +// emplace_front() 在队列头部构造元素 +// emplace_back() 在队列尾部构造元素 +// resize() 改变队列的大小 +// assign() 赋值 +// get_allocator() 返回队列的配置器 +// max_size() 返回队列最大可以存储的元素数量 +// shrink_to_fit() 将内存减少到等于当前元素数量所需的大小 +// cbegin() 返回指向队列头部的常量迭代器 +// cend() 返回指向队列尾部的常量迭代器 + +#include +#include + +int main() +{ + std::deque dq; + + dq.push_back(1); // 在队列尾部插入元素 + dq.push_front(2); // 在队列头部插入元素 + + std::cout << "Front: " << dq.front() << std::endl; // 访问队列头部元素 + std::cout << "Back: " << dq.back() << std::endl; // 访问队列尾部元素 + + dq.pop_front(); // 删除队列头部元素 + dq.pop_back(); // 删除队列尾部元素 + + std::cout << "Size: " << dq.size() << std::endl; // 队列的大小 + + return 0; +} diff --git a/day9/stl_deque_demo/d2.cpp b/day9/stl_deque_demo/d2.cpp new file mode 100644 index 0000000..7480d1c --- /dev/null +++ b/day9/stl_deque_demo/d2.cpp @@ -0,0 +1,20 @@ +#include + +using namespace std; + +int main() +{ + int m[] = {1, 2, 3, 4, 5, 6}; + deque d1; + deque d2(m, m + 6); + + deque::iterator it = d2.begin(); + while (it != d2.end()) + { + cout << *it << " "; + it++; + } + cout << endl; + + return 0; +} diff --git a/day9/stl_deque_demo/d3.cpp b/day9/stl_deque_demo/d3.cpp new file mode 100644 index 0000000..4c7b530 --- /dev/null +++ b/day9/stl_deque_demo/d3.cpp @@ -0,0 +1,41 @@ +#include + +using namespace std; + +template +void print(deque &dq) +{ + typename deque::iterator it = dq.begin(); + while (it != dq.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int m[] = {1, 2, 3, 4, 5, 6}; + deque d1; + deque d2(m, m + 6); + + deque d4 = d2; // 拷贝构造函数: deque(const deque &deq) + print(d4); + + d1 = d2; // 赋值运算符: deque& operator=(const deque &deq) + print(d1); + + print(d2); + + deque d3(10, 1); // 10 个 1 + print(d3); + + cout << "d5.swap(d2):" << endl; + deque d5; + d5.swap(d2); + print(d5); + print(d2); + + return 0; +} diff --git a/day9/stl_deque_demo/d4.cpp b/day9/stl_deque_demo/d4.cpp new file mode 100644 index 0000000..ff90156 --- /dev/null +++ b/day9/stl_deque_demo/d4.cpp @@ -0,0 +1,43 @@ +#include +#include + +using namespace std; + +class Person +{ + friend void print(deque &dq); + +private: + string name; + int age; + +public: + Person(string name, int age) : name(name), age(age) {} +}; + +void print(deque &dq) +{ + deque::iterator it = dq.begin(); + while (it != dq.end()) + { + cout << (*it).name << ", " << (*it).age << endl; + ; + it++; + } +} + +int main() +{ + deque dq; + dq.push_front(Person("张三", 18)); + dq.push_back(Person("李四", 19)); + dq.push_front(Person("王五", 20)); + print(dq); + + cout << "--------" << endl; + dq.pop_back(); + dq.pop_front(); + print(dq); + + return 0; +} \ No newline at end of file diff --git a/day9/stl_deque_demo/d5.cpp b/day9/stl_deque_demo/d5.cpp new file mode 100644 index 0000000..ecb53fe --- /dev/null +++ b/day9/stl_deque_demo/d5.cpp @@ -0,0 +1,22 @@ +#include +#include + +using namespace std; + +int main() +{ + deque d1; + // d1.resize(5); + cout << "d1.size():" << d1.size() << ", d1.empty():" << d1.empty() << endl; + + try + { + cout << d1[15] << endl; + } + catch (...) + { + cout << "错误" << endl; + } + + return 0; +} \ No newline at end of file diff --git a/day9/stl_deque_demo/d6.cpp b/day9/stl_deque_demo/d6.cpp new file mode 100644 index 0000000..6074f3a --- /dev/null +++ b/day9/stl_deque_demo/d6.cpp @@ -0,0 +1,18 @@ +#include + +using namespace std; + +int main() +{ + deque d1(5, "disen"); + d1.push_front("jack"); + d1.push_back("mack"); + d1.insert(d1.begin() + 1, "lucy"); + cout << "first element is: " << d1.front() << endl; + cout << "last element is: " << d1.back() << endl; + + deque::iterator it = d1.begin(); + cout << "second element is: " << *(it + 1) << endl; + + return 0; +} diff --git a/day9/stl_deque_demo/d7.cpp b/day9/stl_deque_demo/d7.cpp new file mode 100644 index 0000000..6fa3557 --- /dev/null +++ b/day9/stl_deque_demo/d7.cpp @@ -0,0 +1,32 @@ +// deque 的插入操作 +#include + +using namespace std; + +template +void print(deque &dq) +{ + typename deque::iterator it = dq.begin(); + while (it != dq.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + deque d1(5, "disen"); + print(d1); + + d1.insert(d1.begin() + 1, "jack"); + print(d1); + + string m[] = {"a", "b", "c", "d", "e"}; + // 将 m 中的 bcd 插入到 d1 中的 第二个 disen 后面 + d1.insert(d1.begin() + 3, m + 1, m + 4); + print(d1); + + return 0; +} diff --git a/day9/stl_deque_demo/d8.cpp b/day9/stl_deque_demo/d8.cpp new file mode 100644 index 0000000..ad14713 --- /dev/null +++ b/day9/stl_deque_demo/d8.cpp @@ -0,0 +1,37 @@ +// deque 的删除操作 +#include + +using namespace std; + +template +void print(deque &dq) +{ + typename deque::iterator it = dq.begin(); + while (it != dq.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + string m[] = {"a", "b", "c", "d", "e"}; + deque dq(m, m + 5); + print(dq); + + deque::iterator del_it = dq.begin() + 1; + // for (int i = 0; i < 3; i++) + // { + // // dq.erase() 会删除当前元素并返回下一个元素的迭代器 + // del_it = dq.erase(del_it); + // } + + // 第二种删除方式 + dq.erase(del_it, del_it + 3); + + print(dq); + + return 0; +} diff --git a/day9/stl_stack_demo/d1.cpp b/day9/stl_stack_demo/d1.cpp new file mode 100644 index 0000000..497470c --- /dev/null +++ b/day9/stl_stack_demo/d1.cpp @@ -0,0 +1,53 @@ +// stack 没有迭代器:不支持遍历 +// 原因: 栈是一种特殊的容器,只能在栈顶进行插入和删除操作 + +// stack 常用接口 +// 1. push(elem); // 入栈 +// 2. pop(); // 出栈 +// 3. top(); // 返回栈顶元素 +// 4. empty(); // 判断栈是否为空 +// 5. size(); // 返回栈中元素的个数 +// 6. swap(stk1, stk2); // 交换两个栈 + +#include +#include + +using namespace std; + +int main() +{ + stack stk; + + for (int i = 0; i < 1000; i++) + { + stk.push(i); + } + + cout << "当前栈中元素个数:" << stk.size() << endl; + cout << "栈顶的元素: " << stk.top() << endl; + + // 只弹出 600 这个元素 + // 需要一个临时变量来保存弹出的元素 + stack tmp_stk; + while (stk.top() != 600) + { + tmp_stk.push(stk.top()); + stk.pop(); + } + cout << " ----------\n弹出 600 前的栈顶元素: " + << stk.top() << endl; + stk.pop(); + cout << "弹出 600 后的栈顶元素: " + << stk.top() + << endl + << " ----------\n"; + while (!tmp_stk.empty()) + { + stk.push(tmp_stk.top()); + tmp_stk.pop(); + } + cout << "当前栈中元素个数:" << stk.size() << endl; + cout << "栈顶的元素: " << stk.top() << endl; + + return 0; +} \ No newline at end of file diff --git a/day9/stl_stack_demo/d2.cpp b/day9/stl_stack_demo/d2.cpp new file mode 100644 index 0000000..17fb1a7 --- /dev/null +++ b/day9/stl_stack_demo/d2.cpp @@ -0,0 +1,142 @@ +#include +#include +#include + +using namespace std; + +class Date +{ + // 重载 << 以显示日期 + friend ostream &operator<<(ostream &out, const Date &date) + { + out << date.year << "年" << date.month << "月" << date.day << "日"; + return out; + } + +private: + int year; + int month; + int day; + +public: + Date(int y, int m, int d) : year(y), month(m), day(d) {} + +public: + bool operator<(const Date &date) const + { + // if (year < date.year) + // { + // return true; + // } + // else if (year == date.year) + // { + // if (month < date.month) + // { + // return true; + // } + // else if (month == date.month) + // { + // if (day < date.day) + // { + // return true; + // } + // } + // } + // return false; + return year < date.year || + (year == date.year && month < date.month) || + (year == date.year && month == date.month && day < date.day); + } + bool operator>(const Date &date) const + { + return year > date.year && month > date.month && day > date.day; + } +}; + +class Worker +{ + friend Worker &operator=(const Worker &other); + // { + // if (this != &other) + // { + // name = other.name; + // hire_date = other.hire_date; + // volume = other.volume; + // } + // return *this; + // } + +private: + string name; // 姓名 + Date hire_date; // 入职日期 + double volume; // 业绩 + +public: + Worker(const string &name, const Date &hire_date, double volume) + : name(name), hire_date(hire_date), volume(volume) {} + Worker(const Worker &other) + { + name = other.name; + hire_date = other.hire_date; + volume = other.volume; + } + ~Worker() + { + cout << "析构函数被调用" << endl; + } + +public: + void show() + { + cout << "name = " << name << ", hire_date = " << hire_date << ", volume = " << volume << endl; + } +}; + +Worker &operator=(const Worker &other) +{ + name = other.name; + hire_date = other.hire_date; + volume = other.volume; +} + +void sortByHireDate(Worker *p, int size) +{ + for (int i = 0; i < size - 1; i++) + int min = i; + for (int j = i + 1; j < size; i++) + { + if (p[min].hire_date > p[j].hire_date) + { + min = j; + } + } + if (min != i) + { + swap(p[min], p[i]); + // Worker tmp = p[i]; // 拷贝构造 + // p[i] = p[min]; // operator= 重载 + // p[min] = tmp; + } +} + +void sortByVolume(Worker *p, int size) +{ +} + +int main() +{ + Worker w1("disen", Date(2020, 1, 15), 1000); + Worker w2("zhangsan", Date(2020, 1, 16), 200); + Worker w3("lisi", Date(2020, 2, 17), 400); + Worker w4("wangwu", Date(2020, 2, 18), 900); + Worker w5("zhaoliu", Date(2020, 2, 18), 100); + + Worker wrks[] = {w1, w2, w3, w4, w5}; + + sortByHireDate(wrks, 5); // 先排序 + + // vector vec; + // vec.assign(wrks, wrks + 5); + + w1.show(); +} \ No newline at end of file diff --git a/day9/stl_stack_demo/d2_2.cpp b/day9/stl_stack_demo/d2_2.cpp new file mode 100644 index 0000000..ea79b93 --- /dev/null +++ b/day9/stl_stack_demo/d2_2.cpp @@ -0,0 +1,158 @@ +#include +#include +#include + +using namespace std; +class Worker; +class Date +{ + friend Worker; + friend ostream &operator<<(ostream &cout, Date &date) + { + cout << date.year << "年" << date.month << "月" << date.day << "日"; + return cout; + } + +private: + int year; + int month; + int day; + +public: + Date(int year, int month, int day) + { + this->year = year; + this->month = month; + this->day = day; + } + bool operator>(Date &other) + { + // cout << *this << " pk " << other << endl; + return year > other.year || (year == other.year && month > other.month) || (year == other.year && month == other.month && day > other.day); + } + bool operator<=(Date &other) + { + return year <= other.year && month <= other.month && day <= other.day; + } +}; +class Worker +{ +public: + string name; // 姓名 + Date *hire_date; // 入职时间 + double volume; // 业绩值 + +public: + Worker(const string &name, Date *hire_date, double volume) + { + this->name = name; + this->hire_date = hire_date; + this->volume = volume; + } + Worker(const Worker &other) + { + Date *hire_date = new Date(other.hire_date->year, other.hire_date->month, other.hire_date->day); + this->hire_date = hire_date; + this->name = other.name; + this->volume = other.volume; + } + Worker &operator=(const Worker &other) + { + this->hire_date->year = other.hire_date->year; + this->hire_date->month = other.hire_date->month; + this->hire_date->day = other.hire_date->day; + this->name = other.name; + this->volume = other.volume; + return *this; + } + + ~Worker() + { + if (hire_date) + delete hire_date; + hire_date = NULL; + } + + void show() + { + cout << "name=" << name << ",hire_date=" << *hire_date << ",volume=" << volume << endl; + } +}; + +void sortByHireDate(Worker *p, int size) +{ + for (int i = 0; i < size - 1; i++) + { + int min = i; + for (int j = i + 1; j < size; j++) + { + if (*(p[min].hire_date) > *(p[j].hire_date)) + { + min = j; + } + } + if (min != i) + { + // cout << p[i].name << " 和 " << p[min].name << " 交换数据" << endl; + Worker tmp = p[i]; // 拷贝构造函数 + p[i] = p[min]; // operator=重载 + p[min] = tmp; + } + } +} + +void sortByVolume(Worker *p, int size) +{ + for (int i = 0; i < size - 1; i++) + { + int min = i; + for (int j = i + 1; j < size; j++) + { + if (p[min].volume < p[j].volume) + { + min = j; + } + } + if (min != i) + { + // cout << p[i].name << " 和 " << p[min].name << " 交换数据" << endl; + Worker tmp = p[i]; // 拷贝构造函数 + p[i] = p[min]; // operator=重载 + p[min] = tmp; + } + } +} + +int main(int argc, char const *argv[]) +{ + Worker w1("disen", new Date(2020, 1, 15), 1000); + Worker w2("jack", new Date(2021, 1, 15), 100); + Worker w3("lucy", new Date(2020, 2, 15), 500); + Worker w4("mack", new Date(2020, 3, 25), 300); + Worker w5("judy", new Date(2022, 5, 18), 400); + Worker w6("rose", new Date(2023, 1, 10), 1200); + + Worker m[] = {w1, w2, w3, w4, w5, w6}; + // sortByHireDate(m, 6); + sortByVolume(m, 6); + vector v1(m, m + 6); + stack s1; + vector::iterator it = v1.begin(); + while (it != v1.end()) + { + (*it).show(); + s1.push(*it); + it++; + } + + // 辞退2位新来的员工 + // cout << "-----辞退2位新来的员工----" << endl; + cout << "-----业绩最差的2位员工----" << endl; + for (int i = 0; i < 2; i++) + { + s1.top().show(); + s1.pop(); + } + + return 0; +} \ No newline at end of file diff --git a/day9/stl_string_demo/d1.cpp b/day9/stl_string_demo/d1.cpp new file mode 100644 index 0000000..fec3bf8 --- /dev/null +++ b/day9/stl_string_demo/d1.cpp @@ -0,0 +1,54 @@ +// string 类型的常用方法 + +// string 与 char* 的区别 + +#include + +using namespace std; + +int main() +{ + string s1("ism "); + string s2("hhhsishg"); + + // 拼接 + // s1 += s2; + s1.append(s2); + + /****************** + // 修改指定位置的内容 + s1[0] = 'l'; + + // 替换 + // int c_pos = s1.find('h'); // 查找字符 h 的位置 + // s1.replace(c_pos, 1, "d"); // 替换字符 h 为 d + + // 替换所有的 h 为 d + int pos = s1.find('h'); + cout << "h pos = " << pos << endl; + // while (pos != string::npos) // npos 表示查找失败 + while (pos != -1) // -1 表示查找失败 + { + s1.replace(pos, 1, "d"); + pos = s1.find("h", pos + 1); + } + ******************/ + + // 查找 is 第一次和最后一次出现的位置 + int is_start = s1.find("is"); + int is_end = s1.rfind("is"); + cout << "is_start = " << is_start << endl; + cout << "is_end = " << is_end << endl; + + // 查找 is 的长度 + string s3("is"); + cout << "is 的长度: " << s3.size() << endl; + + // 清空内容(保留开始和结束的 is) + // s1.replace(is_start, is_end - is_start + 2, ""); + s1.erase(is_start + 2, is_end - is_start - 2); + + cout << s1 << endl; + + return 0; +} diff --git a/day9/stl_string_demo/d2.cpp b/day9/stl_string_demo/d2.cpp new file mode 100644 index 0000000..b2365c7 --- /dev/null +++ b/day9/stl_string_demo/d2.cpp @@ -0,0 +1,28 @@ +#include + +using namespace std; + +int main() +{ + string s1 = "linux c/c++中指针与引用是课程的重点知识"; + s1.replace(s1.find('/'), 1, "//"); + cout << s1 << endl; + + s1.erase(2, 5); // 删除从下标为2开始的5个字符 + s1.insert(2, 5, '*'); // 在下标为2的位置插入5个字符* + + // s1.replace(2, 5, "*****"); // 从下标为2开始的5个字符替换为5个字符* + // s1.replace(2, 5, "*****", 2, 3); // 从下标为2开始的5个字符替换为从下标为2开始的3个字符 + + cout << s1 << endl; + + string::iterator it = s1.begin(); + while (it != s1.end()) + { + cout << *it << " "; // 中文字符迭代器无法识别,会输出乱码,因为中文字符 UTF-8 占用3个字节 + it++; + } + cout << endl; + + return 0; +} diff --git a/day9/stl_vector_demo/d10.cpp b/day9/stl_vector_demo/d10.cpp new file mode 100644 index 0000000..f25df5b --- /dev/null +++ b/day9/stl_vector_demo/d10.cpp @@ -0,0 +1,45 @@ + +// vector 的删除操作 +#include + +using namespace std; + +template +void print(vector &v) +{ + typename vector::iterator it = v.begin(); + while (it != v.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + print(v1); + + vector::iterator it = v1.begin(); + v1.insert(it, 1, 10); // 在 it 位置插入 1 个 10 + print(v1); + + it = v1.begin(); // 重新获取迭代器,因为之前的迭代器已经失效(插入后迭代器首地址变了) + v1.erase(it); // 删除 it 位置的元素 + print(v1); + + it = v1.begin(); + v1.erase(it, it + 2); // 删除 [it, it+2) 位置的元素 + print(v1); + + // 清空 + v1.clear(); + v1.empty(); // 判断是否为空 + cout << "清空后:" << endl; + print(v1); + cout << "size: " << v1.size() << " capacity: " << v1.capacity() << endl; // size: 0 capacity: 8 + + return 0; +} diff --git a/day9/stl_vector_demo/d11.cpp b/day9/stl_vector_demo/d11.cpp new file mode 100644 index 0000000..5c4384d --- /dev/null +++ b/day9/stl_vector_demo/d11.cpp @@ -0,0 +1,35 @@ + +// vector 的删除操作 +#include + +using namespace std; + +template +void print(vector &v) +{ + typename vector::iterator it = v.begin(); + while (it != v.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + print(v1); + + vector::iterator it = v1.begin(); + v1.insert(it, 1, 10); // 在 it 位置插入 1 个 10 + print(v1); + + v1.resize(0); // 缩小 + vector(v1).swap(v1); // 重新分配内存 + print(v1); + cout << "size: " << v1.size() << " capacity: " << v1.capacity() << endl; // size: 2 capacity: 8 + + return 0; +} diff --git a/day9/stl_vector_demo/d3.cpp b/day9/stl_vector_demo/d3.cpp new file mode 100644 index 0000000..5615993 --- /dev/null +++ b/day9/stl_vector_demo/d3.cpp @@ -0,0 +1,28 @@ +// vector 的使用 + +#include + +using namespace std; + +int main() +{ + vector v1; + // int mSize = v1.size(); // 获取容器中元素的个数 + int mCapacity = v1.capacity(); // 获取容器的容量 + int cnt = 0; // 扩容次数 + cout << "初始容量: " << mCapacity << endl; + for (int i = 0; i < 1000; i++) + { + v1.push_back(i); // 向容器中添加元素 + // cout << "size = " << v1.size() << " capacity = " << v1.capacity() << endl; + if (mCapacity != v1.capacity()) + { + + mCapacity = v1.capacity(); + cout << "第" << ++cnt << "次扩容, " + << "当前容量为: " << v1.capacity() << endl; + } + } + + return 0; +} diff --git a/day9/stl_vector_demo/d4.cpp b/day9/stl_vector_demo/d4.cpp new file mode 100644 index 0000000..98ab88c --- /dev/null +++ b/day9/stl_vector_demo/d4.cpp @@ -0,0 +1,23 @@ +#include + +using namespace std; + +int main() +{ + int arr[] = {1, 2, 3, 4, 5, 9}; // 静态数组 + // vector v1(arr, arr + 5); // 动态数组,通过静态数组初始化 + // vector v1(arr, arr + sizeof(arr) / sizeof(arr[0])); // 动态数组,通过静态数组初始化 + + // 使用 assign 方法初始化 + vector v1; + v1.assign(arr, arr + sizeof(arr) / sizeof(arr[0])); + + vector::iterator it = v1.begin(); // 迭代器 + while (it != v1.end()) + { + cout << *it << " "; + it++; + } + + return 0; +} diff --git a/day9/stl_vector_demo/d5.cpp b/day9/stl_vector_demo/d5.cpp new file mode 100644 index 0000000..3c8513b --- /dev/null +++ b/day9/stl_vector_demo/d5.cpp @@ -0,0 +1,28 @@ +#include + +using namespace std; + +template +void print(vector &v) +{ + typename vector::iterator it = v.begin(); + while (it != v.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + vector v2(5, 1.2f); + v1.swap(v2); + + print(v1); + print(v2); + + return 0; +} diff --git a/day9/stl_vector_demo/d6.cpp b/day9/stl_vector_demo/d6.cpp new file mode 100644 index 0000000..8af4a9c --- /dev/null +++ b/day9/stl_vector_demo/d6.cpp @@ -0,0 +1,20 @@ +#include + +using namespace std; + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + cout << "size: " << v1.size() << endl; + cout << "capacity: " << v1.capacity() << endl; + cout << "first addr: " << &v1[0] << endl; + + v1.resize(20); // 重新指定容器的长度 + cout << "size: " << v1.size() << endl; + cout << "capacity: " << v1.capacity() << endl; + // 调整前后首地址会发生变化 + cout << "first addr: " << &v1[0] << endl; + + return 0; +} diff --git a/day9/stl_vector_demo/d7.cpp b/day9/stl_vector_demo/d7.cpp new file mode 100644 index 0000000..d582345 --- /dev/null +++ b/day9/stl_vector_demo/d7.cpp @@ -0,0 +1,36 @@ +#include + +using namespace std; + +template +void print(vector &v) +{ + typename vector::iterator it = v.begin(); + while (it != v.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + + v1.resize(10, 9); // 重新指定容器的长度,并用9填充 + print(v1); + + vector v2; + v2.reserve(3); // 预留足够的空间避免频繁扩容导致的首地址变化 + // v2.resize(2); // resize 也可以预留空间,但是不会填充 + v2.push_back(1); + cout << "first addr: " << &v2[0] << endl; + v2.push_back(2); + cout << "first addr: " << &v2[0] << endl; + v2.push_back(3); + cout << "first addr: " << &v2[0] << endl; + + return 0; +} diff --git a/day9/stl_vector_demo/d8.cpp b/day9/stl_vector_demo/d8.cpp new file mode 100644 index 0000000..6a663dd --- /dev/null +++ b/day9/stl_vector_demo/d8.cpp @@ -0,0 +1,30 @@ +#include + +using namespace std; + +template +void print(vector &v) +{ + typename vector::iterator it = v.begin(); + while (it != v.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + + print(v1); + + cout << "first element is: " << v1.front() << endl; + cout << "first element addr is: " << &v1.front() << endl; // 与 day9/d7.cpp 中的 first addr 不同 + cout << "last element is: " << v1.back() << endl; + cout << "last element addr is: " << &v1.back() << endl; // 与 day9/d7.cpp 中的 first addr 不同 + + return 0; +} diff --git a/day9/stl_vector_demo/d9.cpp b/day9/stl_vector_demo/d9.cpp new file mode 100644 index 0000000..7c44b9f --- /dev/null +++ b/day9/stl_vector_demo/d9.cpp @@ -0,0 +1,34 @@ + +// vector 的插入操作 +#include + +using namespace std; + +template +void print(vector &v) +{ + typename vector::iterator it = v.begin(); + while (it != v.end()) + { + cout << *it << " "; + it++; + } + cout << endl; +} + +int main() +{ + int arr1[5] = {1, 2, 3, 4, 5}; + vector v1(arr1, arr1 + 5); + print(v1); + + vector::iterator it = v1.begin(); + v1.insert(it, 1, 10); // 在 it 位置插入 1 个 10 + print(v1); + + vector::iterator it2 = v1.begin(); + v1.insert(it2, 2, 9); // 在 it 位置插入 2 个 9,之前的元素会向后移动 + print(v1); + + return 0; +}