c++基础2
文件操作
程序运行时产生的数据属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
c++中对文件操作需要包含
文件类型分为两种
- 文本文件:文件以ASCII码形式存储在计算机中
- 二进制文件:文件以文本的二进制存储在计算机中,用户一般不能直接读懂他们
操作文件三大类:
- ofstream:写操作
- ifstream:读操作
- fstream:读写操作
写文件
步骤:
-
包含头文件
#include
-
创建流对象
ofstream ofs;
-
打开文件
ofs.open(“文件路径”,打开方式)
-
写数据
ofs<<“写入的数据”;
-
关闭文件
ofs.close();
打开方式 | |
---|---|
ios::in | 读文件 |
ios::out | 写文件 |
ios::ate | 初始位置:文件尾部 |
ios::app | 追加 |
ios::trunc | 如果文件存在先删除,在创建 |
ios::binary | 二进制 |
注意:文件打开方式可以配合使用,利用 | 操作符
例如:用二进制方式写文件 ios::binary | ios::out
#include "iostream"
#include "fstream"using namespace std;void test() {// 创建流对象ofstream ofs;ofs.open("/Users/mac/CLionProjects/c_overwrite/text.txt",ios::out);ofs<<"姓名:张三"<<endl;ofs<<"性别:男"<<endl;ofs<<"年龄:18"<<endl;// 关闭文件ofs.close();}int main(int arg, char *argv[]) {test();return 0;
}
读文件
#include "iostream"
#include "fstream"using namespace std;void testWrite() {// 创建流对象ofstream ofs;ofs.open("/Users/mac/CLionProjects/c_overwrite/text.txt", ios::out);ofs << "姓名:张三" << endl;ofs << "性别:男" << endl;ofs << "年龄:18" << endl;// 关闭文件ofs.close();}void testRead() {try {ifstream ifs;ifs.open("/Users/mac/CLionProjects/c_overwrite/text.txt");if (!ifs.is_open()) {throw -1;}/// 第一种/* char buf[1024] = {0};while (ifs >> buf) {cout<<buf<<endl;}*//// 第二种/*char buf[1024] = {0};while (ifs.getline(buf, sizeof(buf))) {cout << buf << endl;}*//// 第三种/*string buf;while (getline(ifs,buf)){cout<<buf<<endl;}*//// 第四种char c;while ((ifs.get()) != EOF) { /// end of filecout << c;}ifs.close();} catch (int b) {switch (b) {case -1:cout << "打开失败" << endl;}} catch (...) {cout << "读取失败" << endl;}}int main(int arg, char *argv[]) {testRead();return 0;
}
读写二进制
#include "iostream"
#include "fstream"using namespace std;class Person {
public:char name[64];int age;};void testWrite() {ofstream ofs("/Users/mac/CLionProjects/c_overwrite/person.txt", ios::out | ios::binary);Person p = {"张三", 18};ofs.write((const char *) &p, sizeof(Person));ofs.close();}void testRead() {ifstream ifs("/Users/mac/CLionProjects/c_overwrite/person.txt", ios::in | ios::binary);if (!ifs.is_open()) {cout << "文件打开失败" << endl;return;}Person p;ifs.read((char *) &p, sizeof(p));cout << p.name << " " << p.age << endl;
}int main(int arg, char *argv[]) {testRead();return 0;
}
模版
模版就是建立通用模具,大大提供复用性
函数模版
- c++ 另一种编程思想称为泛型编程,主要利用的技术就是模版
- c++提供两种模版机制:函数模版和类模版
函数模版
函数模版作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法
template<typename T>
函数声明或定义
解释
template — 声明创建模版
typename — 表明后面的符号是一种数据类型,也可以用class替换
#include "iostream"using namespace std;template<typename T>
void mySwap(T &a, T &b) {T temp = a;a = b;b = temp;
}
int main() {int a = 1;int b = 9;double c = 3.3;double d = 2.3;/// 1. 自动类型推导mySwap(a, b);/// 2 显示指定类型mySwap<double>(c, d);cout << a << " " << b << endl;return 0;
}
注意事项
- 自动类型推导,必须推导出已知的数据类型T才可以使用
- 模版必须要确定出T的数据类型,才可以使用
练习
#include "iostream"using namespace std;template<typename T>
void mySort(T arr[], int len) { /// 数组的这个长度必须传for (int i = 0; i < len; ++i) {T &cur = arr[i];for (int j = i + 1; j < len; ++j) {if (arr[j] < cur) {T temp = cur;cur = arr[j];arr[j] = temp;}}}}int main() {int arr[] = {3, 2, 3, 4, 2, 1,};int len = sizeof(arr) / sizeof(arr[0]);mySort(arr, len);for (int i = 0; i < len; ++i) {cout << arr[i] << " ";}cout << endl;char arr1[] = {'d', 'a', 'f', 'e', 'b', 'c',};int len1 = sizeof(arr1) / sizeof(arr1[0]);mySort(arr1, len1);for (int i = 0; i < len1; ++i) {cout << arr1[i] << " ";}return 0;
}
注意
- 普通函数调用可以发生隐式类型转换
- 函数模版 自动类型推导,不可以发生隐式类型转换
- 函数模版 显示指定类型,可以发生隐式类型转换
#include "iostream"using namespace std;/// 普通函数
int myAdd1(int a, int b) {return a + b;
}
/// 函数模版
template<typename T>
T myAdd2(T a, T b) {return a + b;
}
int main() {int a = 10;int b = 20;cout << myAdd1(a, b) << endl;char c = 'c';cout << myAdd1(a, c) << endl;cout << myAdd2(a, b) << endl;/// 编译报错
// cout << myAdd2(a, c) << endl;cout << myAdd2<int>(a, c) << endl;return 0;
}
总结:建议使用显示类型的方式,调用函数模版,应为自己可以确定通用类型
普通函数与函数模版调用的规则
- 如果函数模版和普通函数都可以实现,优先调用普通函数
- 可以通过空模版参数列表来强制调用函数模版
- 函数模版也可以发生重载
- 如果函数模版可以产生更好的匹配优先调用函数模版
#include "iostream"using namespace std;void myPrint(int a, int b) {cout << "调用普通函数" << endl;
}template<typename T>
void myPrint(int a, int b) {cout << "调用模版函数" << endl;
}int main() {int a = 20;int b = 20;myPrint(a, b);myPrint<void>(a, b);int c = 'c';int d = 'd';myPrint<char>(c, d);return 0;
}
总结:一句话,调用函数模版时,传递类型参数,否则,自己都不清楚掉哪个
模版具体化
模版局限性
模版并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
#include "iostream"using namespace std;class Person {string name;
public:Person(string name) : name(name) {};string getName() {return name;}
};template<typename T>
bool myCompare(T &a, T &b) {if (a == b) {return true;} else {return false;}
}template<>
bool myCompare(Person &a, Person &b) {if (a.getName() == b.getName()) {return true;} else {return false;}
}int main() {int a = 10;int b = 10;cout << myCompare(a, b) << endl;Person p("z");Person p1("z");cout << myCompare(p, p1) << endl;return 0;
}
类模版
类模版作用:
建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型代表
#include "iostream"using namespace std;template<class NameType, class AgeType = int>
class Person {
public:Person(NameType name, AgeType age) : name(name), age(age) {}public:NameType name;AgeType age;void showInfo() {cout << name << " " << age << endl;}
};int main() {Person<string, int> p("张三", 3);p.showInfo();return 0;
}
类模版与函数模版区别
- 类模版没有自动类型推导的使用方式
- 类模版在模版参数列表中可以有默认参数
类模版中成员函数创建时机
- 普通类成员函数一开始就可以创建
- 类模版中的成员函数在调用时才创建
#include "iostream"using namespace std;class Person {public:void showPerson1() {cout << "show person1" << endl;}
};template<class T>
class MyClass {T obj;public:void showInfo1() {obj.showPerson1();}void showInfo2() {obj.showPerson2();}
};int main() {MyClass<Person> mc;mc.showInfo1();/// 编译报错
// mc.showInfo2();return 0;
}
类模版对象做函数参数
三种方式:
- 指定转入方式 – 直接显示对象的数据类型
- 参数模版化 – 将对象中的参数变为模版进行传递
- 整个类模版化 – 将这个对象类型 模版化进行传递
#include "iostream"using namespace std;template<class T1 = string, class T2 = int>
class Person {
public:T1 name;T2 age;Person(T1 name, T2 age) : name(name), age(age) {};void showPerson() {cout << name << " " << age << endl;}};/// 1 指定传入类型
void print1(Person<string, int> &p) {p.showPerson();
}/// 2 参数化模版
template<class T1, class T2>
void print2(Person<T1, T2> &p) {cout << typeid(T1).name() << " " << endl;p.showPerson();
}/// 3 整个类模版化
template<class T>
void print3(T &p) {cout << typeid(T).name() << " " << endl;p.showPerson();
}int main() {Person<string, int> p1("孙悟空", 3);print1(p1);Person<string, int> p2("八届", 3);print2(p1);Person<string, int> p3("唐僧", 3);print3<>(p3);return 0;
}
总结:常用的是,指定传入类型
类模版与继承
- 当子类继承的父类是一个类模版是,子类在声明的时候,要指定出父类中T的类型
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也需要变为类模版
#include "iostream"using namespace std;template<class T>
class Base {T m;
};/// 此时才能计算出,子类占用多少内存空间
class Son : public Base<int> {};/// 如果想要灵活指定父类T类型,子类也需要变类模版template<class T1, class T2>
class Son2 : public Base<T1> {T2 n;
};int main() {return 0;
}
成员函数的类外实现
#include "iostream"using namespace std;template<class T1, class T2>
class Person {
public:T1 name;T2 age;Person(T1 name, T2 age);void showPerson();
};
/// 类外构造
template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->name = name;this->age = age;
}/// 类外成员函数
template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << name << " " << age << endl;
}int main() {return 0;
}
类模版份文件编写
问题
类模版中成员函数创建时间是在调用阶段,导致份文件编写时链接不到
解决
- 方式一:直接包含.cpp源文件
- 方式二:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制
第二种方式代码
person.hpp
#include "iostream"
#include "person.h"
using namespace std;template<class T1, class T2>
class Person {
public:T1 name;T2 age;Person(T1 name, T2 age);void showPerson();
};template<class T1, class T2>
Person<T1, T2>::Person(T1 name, T2 age) {this->name = name;this->age = age;
}/// 类外成员函数
template<class T1, class T2>
void Person<T1, T2>::showPerson() {cout << name << " " << age << endl;
}
main.cpp
#include "iostream"
/// 第一种解决方式 直接包含源文件
//#include "person.cpp"
#include "person.hpp"
using namespace std;int main() {Person<string ,int> p("zhangsan",89);p.showPerson();return 0;
}
类模版与友元
#include "iostream"using namespace std;template<class T>
class Color;template<class T>
void printInfo2(Color<T> &c) {cout << (c.c) << endl;
}template<class T>
class Color {/// 全局函数类内实现friend void printInfo1(Color<T> c) {cout << c.c << endl;};/// 类外实现,比较麻烦friend void printInfo2(Color<T> &c);private:T c;
public:Color(T c) : c(c) {};
};int main() {Color<string> c("red");printInfo1(c);printInfo2(c);
// Person<string, int> p("zhangsan", 89);
// p.showPerson();return 0;
}
总结: 建议全局函数类内实现 实现简单,类外实现,要让编译器看到
STL的诞生
- 长久以来,软件届一直希望建立一种可复用的东西
- C++的面向对象和泛型编程思想,目的就是复用性的提升
- 大多数情况下,数据结构和算法都没有一套标准,导致被迫从事大量重复工作
- 为了建立数据结构和算法的一套标准,诞生了STL
基本概念
STL(Standard Template Library,标准模版库)
STL从广义上分为:容器(container) 算法(algorithm) 迭代器(iterator)
容器和算法之间通过迭代器进行无缝连接
STL几乎所有的代码都采用了模版类和模版函数
6大组件
STL大体分为6大组件:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
- 容器:各种数据结构,存放数据
- 算法:各种常用算法
- 迭代器:扮演了容器与算法之间的胶合剂
- 仿函数:行为类似函数,可作为算法的某种策略
- 适配器:一种用来修饰容器或者仿函数或者迭代器接口的东西
- 空间配置器:负责空间的配置和管理
容器、算法、迭代器
-
容器
数据、链表、树、队列、集合、映射表等
分类:
序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置
关联式容器:二叉树结构,各元素之间没有严格的物理上的顺序关系
-
算法:问题之解法也
分类:
质变算法:运算过程期间会更改元素的内容。例如拷贝、替换、删除等等
非质变算法:运算过程中不会更改期间的元素。例如查找、计算、遍历、寻找极值
-
迭代器:容器和算法之间粘合剂
每个容器都有自己专属的迭代器
迭代器使用非常类似于指针,初学阶段可以理解为指针
种类 功能 支持运算 输入迭代器 只读访问 只读, ++ == != 输出迭代器 只写访问 只写,++ 前向迭代器 读写操作,并能向前推进 读写,++ == != 双向迭代器 读写操作,并能向前和向后操作 读写,++ – 随机迭代器 读写操作,功能最强迭代器 读写,++ – [n] -n < <= > >= 容器初识
#include "iostream" #include "vector"using namespace std;void myPrint(int value) {cout << value << endl; }void test1() {vector<int> v;v.push_back(10);v.push_back(20);v.push_back(30);/// 第一种/* vector<int>::iterator itBegin = v.begin();/// 起始迭代器vector<int>::iterator itEnd = v.end();/// 结束迭代器while (itBegin != itEnd) {cout << *itBegin << endl;itBegin++;}*//// 第二种/*for (vector<int>::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++) {cout << *itBegin << endl;}*//// 第三种for_each(v.begin(), v.end(), myPrint);}int main() {test1();return 0; }
string
本质:
string 是c++风格的字符串,而string本质上是一个类
string 和 char* 区别:
char* 是一个指针
string是一个类,类内封装了char*,管理整个字符串,是一个char*型的容器
构造
string();
string(const char* s);
string(const string& str);
拷贝构造
string(int n ,char c);
赋值
#include "iostream"
#include "vector"using namespace std;int main() {/// 赋值操作string str = "hello world";str = 'c';string str1 = str;str.assign("assign");str.assign(str);str.assign("hfsfs",3);cout << str << endl;return 0;
}
追加
#include "iostream"
#include "vector"using namespace std;int main() {/// 追加操作string str = "hello world";string s1 = "world";str+=s1;str+='c';/// 类似提供 append 唯一的不同str.append("hellowlro ",3,5);cout<<str<<endl;return 0;
}
查找和替换
#include "iostream"
#include "vector"using namespace std;int main() {/// 追加操作string str = "hello world d";/// 查找 从左查 第一次出现的位置,还有一个位置的参数int dIndex = str.find("d");cout<<dIndex<<endl;/// 查找 从右查 第一次出现的位置,还有一个位置的参数int rdIndex = str.rfind("d");cout<<rdIndex<<endl;/// 替换str.replace(0,1,"aaaa");cout<<str<<endl;return 0;
}
string 字符串比较
比较方式
-
字符串比较是按字符的ASCI码进行对比
= 返回0
> 返回 1
< 返回 -1
#include "iostream"
#include "vector"using namespace std;int main() {/// 字符串比较是否相等string a = "中国";string b = "中国";cout<<a.compare(b)<<endl;return 0;
}
string获取修改字符
int main() {/// 获取单个字符,中文不适用的string a = "中国力量,中国标准,中国制造";cout << a[0] << endl;cout << a.at(0) << endl;return 0;
}
string插入
#include "iostream"
#include "vector"using namespace std;int main() {string str = "hello world";str.insert(0,"aaa");str.insert(0,"bbb",2);/// 后边这个参数,感觉着实意义不大(指定插入几个字符)cout<<str<<endl;str.erase(0,3);cout<<str<<endl;return 0;
}
获取子串
#include "iostream"
#include "vector"using namespace std;int main() {/// 一个中文 三个字符string str = "中国力量";string s1 = str.substr(0,3);cout<<s1<<endl;return 0;
}
vector
功能:
vector数据结构和数组非常相似,也称为单端数组
vector与普通数组区别
不同之处在于数组是静态空间,而vector可以动态扩展
动态扩展:
并不是在原空间后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间
vector容器的迭代器是支持随机访问的迭代器
构造函数
vector v
vector(v.begin(),v.end())
vector(n,element)
vector(const vector &vec)
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}
}int main() {/// 1vector<int> v1;for (int i = 0; i < 10; ++i) {v1.push_back(i);}/// 2vector<int> v2(v1.begin(),v1.end());/// 3vector<int> v3(10,100);/// 4vector<int> v4(v3);printVector(v3);return 0;
}
赋值
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}
}int main() {vector<int> v1;for (int i = 0; i < 10; ++i) {v1.push_back(i);}vector<int> v2(10,100);/// 运算符重载v1 = v2;/// 指定迭代器v1.assign(v2.begin(),v2.end());/// n个elemv1.assign(10,101);printVector(v1);return 0;
}
容量和大小
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}
}int main() {vector<int> v1;for (int i = 0; i < 33; ++i) {v1.push_back(i);}/// 是否为空cout<<v1.empty()<<endl;/// 容量: 每次扩容为上一次的2倍cout<<v1.capacity()<<endl;/// 大小cout<<v1.size()<<endl;/// 重新指定大小
// v1.resize(15);printVector(v1);return 0;
}
插入与删除
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}
}int main() {vector<int> v1;for (int i = 0; i < 10; ++i) {/// 尾部插入v1.push_back(i);}/// 尾部删除v1.pop_back();/// 指定pos插入vector<int>::iterator begin = v1.begin();v1.insert(begin, 100);/// 插入两个v1.insert(begin, 2, 200);/// 删除v1.erase(begin);/// 删除迭代器从start到end
// v1.erase(begin,v1.end());v1.clear();printVector(v1);return 0;
}
数据存取
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}
}int main() {vector<int> v1;for (int i = 0; i < 10; ++i) {v1.push_back(i);}/// 1 获取数据int i3 = v1.at(3);int i4 = v1[4];cout<<i4<<endl;/// 2 获取收尾元素int front = v1.front();int back = v1.back();printVector(v1);return 0;
}
互换容器
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {/*vector<int> v1;for (int i = 0; i < 10; ++i) {v1.push_back(i);}vector<int> v2;for (int i = 10; i < 20; ++i) {v2.push_back(i);}v1.swap(v2);printVector(v1);printVector(v2);*//// 利用swap巧妙收缩vector<int> v;for (int i = 0; i < 10000; ++i) {v.push_back(i);}cout << "容量 " << v.capacity() << endl;cout << "大小 " << v.size() << endl;v.resize(3);vector<int>(v).swap(v);// 互换以size为准cout << "容量 " << v.capacity() << endl;cout << "大小 " << v.size() << endl;return 0;
}
预留空间
#include "iostream"
#include "vector"using namespace std;void printVector(vector<int> &v) {for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {/// 利用swap巧妙收缩vector<int> v;/// 利用reserve 预留空间v.reserve(100000);int num = 0;// 统计开辟次数int *p = NULL;for (int i = 0; i < 100000; ++i) {v.push_back(i);if (p != &v[0]) {p = &v[0];num++;}}cout << num << endl;return 0;
}
deque
双端数组
deque与vector区别
- vector对于头部的插入删除效率低,数据量大,效率低
- deque相对而言,对头部的插入数据比vector块
- vector访问元素是的速度会比deque块,这和两者内部实现有关
deque内部工作原理
deque内部有个中空器,维护每段缓冲区的内容,缓冲区中存放真实数据
中空器维护的是每个缓冲区的地址,是的使用deque时像一片连续的内存地址
deque容器的迭代器也是支持随机访问的
构造函数
deque deqT
deque<beg,end> deqT
deque<n,ele> deqT
deque<const deque &deq> deqT
#include "iostream"
#include "vector"
#include "deque"using namespace std;void printDeque(const deque<int> &d) {for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {deque<int> deq;for (int i = 0; i < 10; ++i){deq.push_back(i);}deque<int > d1(deq.begin(),deq.end());deque<int > d2(10,100);deque<int > d3(d2);printDeque(d3);return 0;
}
赋值操作
#include "iostream"
#include "vector"
#include "deque"using namespace std;void printDeque(const deque<int> &d) {for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {deque<int> deq;for (int i = 0; i < 10; ++i){deq.push_back(i);}deq = deq;deq.assign(deq.begin(),deq.end());deq.assign(10,100);printDeque(deq);return 0;
}
大小操作
#include "iostream"
#include "vector"
#include "deque"using namespace std;void printDeque(const deque<int> &d) {for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {deque<int> deq;for (int i = 0; i < 10; ++i){deq.push_back(i);}cout<<deq.size()<<endl;cout<<deq.empty()<<endl;deq.resize(3);deq.resize(22,2);printDeque(deq);return 0;
}
插入和删除
#include "iostream"
#include "vector"
#include "deque"using namespace std;void printDeque(const deque<int> &d) {for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {deque<int> deq;for (int i = 0; i < 10; ++i){deq.push_back(i);}///两端deq.push_back(3);deq.push_front(3);deq.pop_back();deq.pop_back();// 指定位置deq.insert(deq.begin(),32);deq.insert(deq.begin(),2,32);
// deq.insert(3,deq.begin(),deq.end());
// deq.clear();deq.erase(deq.begin(),deq.end());deque<int>::iterator it = deq.begin();*it = 10;deq.erase(it);printDeque(deq);return 0;
}
存取
#include "iostream"
#include "vector"
#include "deque"using namespace std;void printDeque(const deque<int> &d) {for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {deque<int> deq;for (int i = 0; i < 10; ++i){deq.push_back(i);}deq.at(3);deq[3] = 3;deq.front();deq.back();printDeque(deq);return 0;
}
排序
#include "iostream"
#include "vector"
#include "deque"using namespace std;void printDeque(const deque<int> &d) {for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {deque<int> deq;for (int i = 0; i < 10; ++i) {deq.push_back(i);}deq.at(3);deq[3] = 10;sort(deq.begin(), deq.end());printDeque(deq);return 0;
}
stack
先进后出
#include "iostream"
#include "vector"
#include "deque"
#include "stack"using namespace std;int main() {stack<int> stk;stack<int> stk1(stk);stk1 = stk;stk.push(3);stk.push(4);stk.pop();stk.top();cout<<stk.empty()<<endl;cout<<stk.size()<<endl;return 0;
}
queue
#include "iostream"
#include "vector"
#include "deque"
#include "stack"
#include "queue"using namespace std;int main() {queue<int> q;queue<int> q1(q);q1 = q;q.push(3);q.push(4);q.pop();q.back();q.front();cout << q.empty() << endl;cout << q.size() << endl;return 0;
}
list
功能:链式存储
链表:是一种物理存储单元上非连续的存储结构,数据元素顺序是通过链表中的指针链接实现的
链表的组成:链表是由一系列节点组成
节点的组成:数据域 和 指针域
STL中的链表是一个双向循环链表
构造
list l
list<beg,end> l
list<n,ele> l
list<const list &lis> l
赋值和交换
#include "iostream"#include "list"using namespace std;void printList(const list<int> &l){for (list<int>::const_iterator it= l.begin(); it != l.end(); it++){cout<<*it<<" ";}cout<<endl;
}int main() {list<int> l;l.push_back(3);l.push_back(3);l.push_back(3);list<int> l1 = l;cout<<l1.size()<<endl;l1.push_back(4);printList(l);printList(l1);l.swap(l1);printList(l);printList(l1);return 0;
}
大小操作
size()
empty()
resize(num)
resize(num,elem)
插入删除
remove(elem)
删除指定的值
数据存取
front()
back()
反转和排序
reverse()
sort()
#include "iostream"#include "list"using namespace std;class Person {string name;int age;int height;
public:Person(string name, int age, int height) : name(name), age(age), height(height) {}
public:void showInfo() const {cout << name << " " << age << " " << height << endl;}int getAge(){return age;}int getHeight(){return height;}
};void printList(const list<Person> &pList) {for (list<Person>::const_iterator it = pList.begin(); it != pList.end(); it++) {it->showInfo();}
}
bool comparePerson(Person &p1,Person &p2){if(p1.getAge() == p2.getAge()){return p1.getHeight()<p2.getHeight();}return p1.getAge() < p2.getAge() ;
}int main() {Person p1("张三", 20, 130);Person p2("李四", 20, 120);Person p3("王五", 24, 130);Person p4("赵六", 32, 90);Person p5("天气", 10, 120);Person p6("王八", 20, 180);list<Person> pList = {p1, p2, p3, p4, p5, p6};pList.sort(comparePerson);printList(pList);return 0;
}
set/multiset
自动排序
本质:关联式容器,底层二叉树
set/multiset 区别:
set 不允许有重复元素
multiset 允许存在重复元素
#include "iostream"#include "set"using namespace std;void printSet(const set<int> &sets) {for (set<int>::const_iterator it = sets.begin(); it != sets.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {set<int> s1;s1.insert(1);s1.insert(2);s1.insert(3);s1.insert(4);printSet(s1);/// 大小set<int> s2;cout << s1.size() << endl;cout << s1.empty() << endl;s2.swap(s1);/// 插入删除s1.clear();
// s1.erase(3);// 位置s1.erase(2);// 元素/// 查找和统计s1.find(2);s1.count(2);return 0;
}
对组
#include "iostream"#include "set"using namespace std;void printSet(const set<int> &sets) {for (set<int>::const_iterator it = sets.begin(); it != sets.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {pair<string,int> p("tom",23);cout<<p.first<<" "<<p.second<<endl;pair<string,int> p1 = make_pair("jeery",23);cout<<p1.first<<" "<<p1.second<<endl;return 0;
}
排序
重写内置类型排序规则
#include "iostream"#include "set"using namespace std;class MyCompare{
public:bool operator()(int v1,int v2){return v1 > v2;}
};int main() {set<int,MyCompare> s1;s1.insert(20);s1.insert(30);s1.insert(40);s1.insert(20);s1.insert(10);for ( set<int,MyCompare>::iterator it = s1.begin(); it != s1.end(); it++){cout<<*it<<" ";}return 0;
}
自定义类型
#include "iostream"#include "set"using namespace std;class Person {string name;int age;int height;
public:Person(string name, int age, int height) : name(name), age(age), height(height) {}public:void showInfo() const {cout << name << " " << age << " " << height << endl;}int getAge() const {return age;}int getHeight() const {return height;}
};class MyCompare {
public:bool operator()(const Person &v1, const Person &v2) {return v1.getAge() > v2.getAge();}
};int main() {Person p1("张三", 20, 130);Person p2("李四", 20, 120);Person p3("王五", 24, 130);Person p4("赵六", 32, 90);Person p5("天气", 10, 120);Person p6("王八", 20, 180);set<Person, MyCompare> s;s.insert(p1);s.insert(p2);s.insert(p3);s.insert(p4);s.insert(p5);s.insert(p6);for (set<Person, MyCompare>::iterator it = s.begin(); it != s.end(); it++) {it->showInfo();}return 0;
}
map/multimap
简介
- map中所有的元素都是pair
- pair中第一个元素为key(键值),起到索引作用,第二个为value(实值)
- 所有的元素会根据元素的键值自动排序
本质:关联式容器,二叉树
优点:快速查找value
map和multimap区别:key是否重复
#include "iostream"#include "map"
#include "fstream"using namespace std;void printMap(map<int, string> &m) {for (map<int, string>::iterator it = m.begin(); it != m.end(); it++) {cout << it->first << " " << it->second << endl;}}int main() {map<int, string> m;m.insert(pair<int, string>(1, "10"));m.insert(pair<int, string>(2, "20"));m.insert(pair<int, string>(3, "30"));map<int, string> m1(m);map<int, string> m2 = m;printMap(m);m.size();m.empty();m.swap(m1);m.clear();m.erase(m.begin());m.erase(m.begin(),m.end());cout<<m[2]<<endl;m.find(2);m.count(2);return 0;
}
这些api不要硬记,记住底层的结构即可,方法大同小异
容器总结
序列容器
List封装链表,Vector封装了数组
Vector:向量
相当于一个数组,在内存中分配一块连续的内存空间进行存储。支持不指定vector大小的存储。STL内部实现时,首先分配一个非常大的内存空间预备进行存储,即capacity()函数返回的大小,当超过此分配的空间时在整体重新分配一块内存地址,这个人以vector可以不指定vector即一个连续内存的大小的感觉。通常此默认的内存分配能完成大部分情况下的存储优点:1. 连续内存,向数组一样操作2. 随机访问方便,支持[]和at3. 节省空间缺点:1. 插入删除效率低2. 只能在vector的最后进行push和pop,不能在vector的头进行push和pop3. size > capacity 时,重新分配、拷贝与释放List:双向链表
每个节点都包括一个信息块、一个前驱指针Pre、一个后驱指针Post。可以不分配必须的内存大小,方便的进行添加和删除操作。使用的是非连续的内存空间进行存储优点:1. 不使用连续内存完成动态操作2. 在内部方便的进行插入和删除操作3. 可在两端进行push、pop缺点:1. 不能进行内部的随机访问,即不支持[]和at2. 相对vector占用内存多deque:双端队列
deque是在功能上合并了vector和list优点:1. 随机访问方便,即支持[]和at2. 在内部方便的进行插入和删除操作3. 可在两端进行push、pop使用区别1. 如果需要高效随机存取,而不在乎插入和删除的效率,使用vector2. 如果需要大量的插入和删除,而不关心随机存取,则应使用list3. 如果需要随机存取,而且关心两端数据的插入和删除,则应使用deque
关联容器
Map、Set属于标准关联容器,使用了非常高效的平衡检索二叉树:红黑树,他的插入删除效率比其他容器高是因为不需要做内存拷贝和内存移动,而直接替换指向节点的指针即可Set和Vector在于Set不包含重复数据。Set和Map的区别在于Set只含有Key,而Map有一个Key和Key对应的Value两个元素Map和Hash_Map的区别是Hash_Map使用了Hash算法来加快查找过程,但是需要更多的内存来存放这些hash桶元素,因此可以算得上空间换时间的策略
相关文章:
c++基础2
文件操作 程序运行时产生的数据属于临时数据,程序一旦运行结束都会被释放 通过文件可以将数据持久化 c中对文件操作需要包含 文件类型分为两种 文本文件:文件以ASCII码形式存储在计算机中二进制文件:文件以文本的二进制存储在计算机中&a…...
虚拟机VMware,linux,centos,如何将项目部署到服务器上面
vmware 是安装虚拟机的软件,centos是系统,linux是系统内核 将本地项目上线到服务器上面,如何实现呢? 准备好服务器,可以选择阿里云服务器 首先需要搭建环境,运行的主要环境是jdktomcatmysql; 通过远程连接…...
R语言 BPNN 反向传播神经网络
##BPNN-neuronet set.seed(123) folds <- createFolds(y=data$Groups,k=10) 建一个放auc值的空向量 auc<-as.numeric() Errorrate<-as.numeric() accuracy<-as.numeric() sensitivity<-as.numeric() specificity<-as.numeric() roc <- vector("li…...

回归预测 | MATLAB实现TCN-BiGRU时间卷积双向门控循环单元多输入单输出回归预测
回归预测 | MATLAB实现TCN-BiGRU时间卷积双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现TCN-BiGRU时间卷积双向门控循环单元多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 
【【51单片机LCD1602模块介绍】】
LCD1602的介绍 显示容量16x2 每个字符是5x7的点阵 VDD 是电源正极 4.5-5.5v VO 是对比度调节电压 RS 数据/指令 选择 1为数据0为指令 RW 读写选择1是读 0为写 E 使能 1为数据有效 下降沿执行命令 D0-D7 数据输入输出 A 背光电源正极 K 背光电源负极 LCD1602的操作流程 1.初始…...
【Nginx11】Nginx学习:HTTP核心模块(八)文件处理
Nginx学习:HTTP核心模块(八)文件处理 继续我们的 HTTP 核心模块之旅。今天主要是文件相关的一些处理操作,包括 DirectIO、文件缓存以及 sendfile 相关的配置。这三个配置中,大家应该会见过 sendfile ,但是另…...

STM32MP157驱动开发——按键驱动(休眠与唤醒)
文章目录 “休眠-唤醒”机制:APP执行过程内核函数休眠函数唤醒函数 休眠与唤醒方式的按键驱动程序(stm32mp157)驱动程序框架button_test.cgpio_key_drv.cMakefile修改设备树文件编译测试 “休眠-唤醒”机制: 当应用程序必须等待某个事件发生,…...
全面解析 SOCKS5 代理与 HTTP 代理的对比与应用
一、 SOCKS5 代理与 HTTP 代理的基本原理 SOCKS5 代理:SOCKS5 是一种网络协议,它可以在传输层(Transport Layer)代理 TCP 和 UDP 请求。SOCKS5 代理不解析请求内容,而是直接将数据中转至目标服务器,支持更广…...
STM32 HEX文件和BIN文件格式区别keil中的配置与生成
一、区别 HEX 文件: 是包括地址信息的,在烧写或下载HEX文件的时候,一般都不需要用户指定地址,因为HEX文件内部的信息已经包括了地址。HEX文件是用ASCII来表示二进制的数值。例如一般8-BIT的二进制数值0x3F,用ASCII来表示就需要分别表示字符3和字符F,每个字符需要一个BYTE…...
RabbitMQ优先级队列的使用
RabbitMQ优先级队列的使用 生产者 public class PriorityQueue {public static void Send(){string path AppDomain.CurrentDomain.BaseDirectory;string tag path.Split(/, \\).Last(s > !string.IsNullOrEmpty(s));Console.WriteLine($"这里是 {tag} 启动了。。&…...

MAC 推送证书不受信任
配置推送证书的时候,一打开就变成不受信任,搜了很多解决版本。 由于苹果修改相关规定,推送证书 打开Apple PKI - Apple 下载AppleWWDRCA文件,选择G4,双击安装之后,证书已经变为受信任。 AppleWWDRCA(Apple Worldwid…...
Gitee创建分支
在使用Gitee进行代码托管时,分支是一个非常重要的概念。它可以让我们在不同的开发阶段、不同的团队成员之间协作开发,提高团队工作效率。因此,下面将介绍如何在Gitee仓库中建立分支。 一、在Gitee上创建新的分支 在讲解如何在Gitee上创建新…...

集群间ssh配置免密登录
ssh免密配置,可以将ssh生成的密钥分发给目标主机,之后再用ssh访问目标主机时就无需输入密码 下面我们来配置用centos71免密登录centos72主机 使用下面指令生成一个密钥 ssh-keygen其中会提示,是否输入密码短语,这里不输入&#…...

YOLOV8改进:CVPR 2023 | SCConv: 即插即用的空间和通道重建卷积
1.该文章属于YOLOV5/YOLOV7/YOLOV8改进专栏,包含大量的改进方式,主要以2023年的最新文章和2022年的文章提出改进方式。 2.提供更加详细的改进方法,如将注意力机制添加到网络的不同位置,便于做实验,也可以当做论文的创新点。 2.涨点效果:添加 SCConv,经过测试,有效涨点。…...

人员定位安全管控系统:提升安全管理水平的智能解决方案
在当今社会,人员安全管理成为各行各业关注的焦点。为了保障人员的安全和提高管理效率,人员定位安全管控系统应运而生。 人员定位安全管控系统采用多种定位技术来实现对人员位置的准确定位,如GPS(全球定位系统)、Wi-Fi…...

数据结构(二)
目录 Trie树 并查集 堆 Trie树 作用:用来高效地存储和查找字符串集合的数据结构 基本形式: 模板代码如下: #include<iostream> using namespace std;const int N 100010;//idx代表当前用到哪个下标 //既是根节点,又是空节点 //cnt存储的是以当前点结尾的…...
logback 自定义log字段(MDC)推送到logstash(spring boot + logback+ logstash)
直接上代码: 1.创建FIlter,往 MDC 里面追加内容 WebFilter Component public class LogBackFilter implements Filter {Overridepublic void init(FilterConfig filterConfig) throws ServletException {}Overridepublic void doFilter(ServletRequest…...
1253. 重构 2 行二进制矩阵
1253. 重构 2 行二进制矩阵 给你一个 2 行 n 列的二进制数组: 矩阵是一个二进制矩阵,这意味着矩阵中的每个元素不是 0 就是 1。第 0 行的元素之和为 upper。第 1 行的元素之和为 lower。第 i 列(从 0 开始编号)的元素之和为 cols…...

安全—01day
文章目录 1. 编码1.1 ASCLL编码1.2 URL编码1.3 Unicode编码1.4 HTML编码1.5 Base64编码 2. form表单2.1 php接收form表单2.2 python接收form表单 1. 编码 1.1 ASCLL编码 ASCII 是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。它是最通用的…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...
上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式
简介 在我的 QT/C 开发工作中,合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式:工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...