程序运行时产生的数据属于临时数据,程序一旦运行结束都会被释放
通过文件可以将数据持久化
c++中对文件操作需要包含
文件类型分为两种
操作文件三大类:
步骤:
包含头文件
#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<<"姓名:张三"<
#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<
#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;
}
模版就是建立通用模具,大大提供复用性
函数模版作用:
建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表
语法
template
函数声明或定义
解释
template — 声明创建模版
typename — 表明后面的符号是一种数据类型,也可以用class替换
#include "iostream"
using namespace std;
template
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(c, d);
cout << a << " " << b << endl;
return 0;
}
注意事项
练习
#include "iostream"
using namespace std;
template
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
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(a, c) << endl;
return 0;
}
总结:建议使用显示类型的方式,调用函数模版,应为自己可以确定通用类型
普通函数与函数模版调用的规则
#include "iostream"
using namespace std;
void myPrint(int a, int b) {
cout << "调用普通函数" << endl;
}
template
void myPrint(int a, int b) {
cout << "调用模版函数" << endl;
}
int main() {
int a = 20;
int b = 20;
myPrint(a, b);
myPrint(a, b);
int c = 'c';
int d = 'd';
myPrint(c, d);
return 0;
}
总结:一句话,调用函数模版时,传递类型参数,否则,自己都不清楚掉哪个
模版局限性
模版并不是万能的,有些特定数据类型,需要用具体化方式做特殊实现
#include "iostream"
using namespace std;
class Person {
string name;
public:
Person(string name) : name(name) {};
string getName() {
return name;
}
};
template
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 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 p("张三", 3);
p.showInfo();
return 0;
}
#include "iostream"
using namespace std;
class Person {
public:
void showPerson1() {
cout << "show person1" << endl;
}
};
template
class MyClass {
T obj;
public:
void showInfo1() {
obj.showPerson1();
}
void showInfo2() {
obj.showPerson2();
}
};
int main() {
MyClass mc;
mc.showInfo1();
/// 编译报错
// mc.showInfo2();
return 0;
}
三种方式:
#include "iostream"
using namespace std;
template
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 &p) {
p.showPerson();
}
/// 2 参数化模版
template
void print2(Person &p) {
cout << typeid(T1).name() << " " << endl;
p.showPerson();
}
/// 3 整个类模版化
template
void print3(T &p) {
cout << typeid(T).name() << " " << endl;
p.showPerson();
}
int main() {
Person p1("孙悟空", 3);
print1(p1);
Person p2("八届", 3);
print2(p1);
Person p3("唐僧", 3);
print3<>(p3);
return 0;
}
总结:常用的是,指定传入类型
#include "iostream"
using namespace std;
template
class Base {
T m;
};
/// 此时才能计算出,子类占用多少内存空间
class Son : public Base {
};
/// 如果想要灵活指定父类T类型,子类也需要变类模版
template
class Son2 : public Base {
T2 n;
};
int main() {
return 0;
}
#include "iostream"
using namespace std;
template
class Person {
public:
T1 name;
T2 age;
Person(T1 name, T2 age);
void showPerson();
};
/// 类外构造
template
Person::Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
/// 类外成员函数
template
void Person::showPerson() {
cout << name << " " << age << endl;
}
int main() {
return 0;
}
问题
类模版中成员函数创建时间是在调用阶段,导致份文件编写时链接不到
解决
第二种方式代码
person.hpp
#include "iostream"
#include "person.h"
using namespace std;
template
class Person {
public:
T1 name;
T2 age;
Person(T1 name, T2 age);
void showPerson();
};
template
Person::Person(T1 name, T2 age) {
this->name = name;
this->age = age;
}
/// 类外成员函数
template
void Person::showPerson() {
cout << name << " " << age << endl;
}
main.cpp
#include "iostream"
/// 第一种解决方式 直接包含源文件
//#include "person.cpp"
#include "person.hpp"
using namespace std;
int main() {
Person p("zhangsan",89);
p.showPerson();
return 0;
}
#include "iostream"
using namespace std;
template
class Color;
template
void printInfo2(Color &c) {
cout << (c.c) << endl;
}
template
class Color {
/// 全局函数类内实现
friend void printInfo1(Color c) {
cout << c.c << endl;
};
/// 类外实现,比较麻烦
friend void printInfo2(Color &c);
private:
T c;
public:
Color(T c) : c(c) {};
};
int main() {
Color c("red");
printInfo1(c);
printInfo2(c);
// Person p("zhangsan", 89);
// p.showPerson();
return 0;
}
总结: 建议全局函数类内实现 实现简单,类外实现,要让编译器看到
基本概念
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 v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
/// 第一种
/* vector::iterator itBegin = v.begin();/// 起始迭代器
vector::iterator itEnd = v.end();/// 结束迭代器
while (itBegin != itEnd) {
cout << *itBegin << endl;
itBegin++;
}*/
/// 第二种
/*for (vector::iterator itBegin = v.begin(); itBegin != v.end(); itBegin++) {
cout << *itBegin << endl;
}*/
/// 第三种
for_each(v.begin(), v.end(), myPrint);
}
int main() {
test1();
return 0;
}
本质:
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<
查找和替换
#include "iostream"
#include "vector"
using namespace std;
int main() {
/// 追加操作
string str = "hello world d";
/// 查找 从左查 第一次出现的位置,还有一个位置的参数
int dIndex = str.find("d");
cout<
string 字符串比较
比较方式
字符串比较是按字符的ASCI码进行对比
= 返回0
> 返回 1
< 返回 -1
#include "iostream"
#include "vector"
using namespace std;
int main() {
/// 字符串比较是否相等
string a = "中国";
string b = "中国";
cout<
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<
获取子串
#include "iostream"
#include "vector"
using namespace std;
int main() {
/// 一个中文 三个字符
string str = "中国力量";
string s1 = str.substr(0,3);
cout<
功能:
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 &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
}
int main() {
/// 1
vector v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
/// 2
vector v2(v1.begin(),v1.end());
/// 3
vector v3(10,100);
/// 4
vector v4(v3);
printVector(v3);
return 0;
}
赋值
#include "iostream"
#include "vector"
using namespace std;
void printVector(vector &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
}
int main() {
vector v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
vector v2(10,100);
/// 运算符重载
v1 = v2;
/// 指定迭代器
v1.assign(v2.begin(),v2.end());
/// n个elem
v1.assign(10,101);
printVector(v1);
return 0;
}
容量和大小
#include "iostream"
#include "vector"
using namespace std;
void printVector(vector &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
}
int main() {
vector v1;
for (int i = 0; i < 33; ++i) {
v1.push_back(i);
}
/// 是否为空
cout<
插入与删除
#include "iostream"
#include "vector"
using namespace std;
void printVector(vector &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
}
int main() {
vector v1;
for (int i = 0; i < 10; ++i) {
/// 尾部插入
v1.push_back(i);
}
/// 尾部删除
v1.pop_back();
/// 指定pos插入
vector::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 &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
}
int main() {
vector v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
/// 1 获取数据
int i3 = v1.at(3);
int i4 = v1[4];
cout<
互换容器
#include "iostream"
#include "vector"
using namespace std;
void printVector(vector &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
/*vector v1;
for (int i = 0; i < 10; ++i) {
v1.push_back(i);
}
vector v2;
for (int i = 10; i < 20; ++i) {
v2.push_back(i);
}
v1.swap(v2);
printVector(v1);
printVector(v2);*/
/// 利用swap巧妙收缩
vector v;
for (int i = 0; i < 10000; ++i) {
v.push_back(i);
}
cout << "容量 " << v.capacity() << endl;
cout << "大小 " << v.size() << endl;
v.resize(3);
vector(v).swap(v);// 互换以size为准
cout << "容量 " << v.capacity() << endl;
cout << "大小 " << v.size() << endl;
return 0;
}
预留空间
#include "iostream"
#include "vector"
using namespace std;
void printVector(vector &v) {
for (vector::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
/// 利用swap巧妙收缩
vector 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与vector区别
deque内部工作原理
deque内部有个中空器,维护每段缓冲区的内容,缓冲区中存放真实数据
中空器维护的是每个缓冲区的地址,是的使用deque时像一片连续的内存地址
deque容器的迭代器也是支持随机访问的
构造函数
deque deqT
deque
deque
deque
#include "iostream"
#include "vector"
#include "deque"
using namespace std;
void printDeque(const deque &d) {
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
deque deq;
for (int i = 0; i < 10; ++i){
deq.push_back(i);
}
deque d1(deq.begin(),deq.end());
deque d2(10,100);
deque d3(d2);
printDeque(d3);
return 0;
}
赋值操作
#include "iostream"
#include "vector"
#include "deque"
using namespace std;
void printDeque(const deque &d) {
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
deque 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 &d) {
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
deque deq;
for (int i = 0; i < 10; ++i){
deq.push_back(i);
}
cout<
插入和删除
#include "iostream"
#include "vector"
#include "deque"
using namespace std;
void printDeque(const deque &d) {
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
deque 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::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 &d) {
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
deque 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 &d) {
for (deque::const_iterator it = d.begin(); it != d.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
deque 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;
}
先进后出
#include "iostream"
#include "vector"
#include "deque"
#include "stack"
using namespace std;
int main() {
stack stk;
stack stk1(stk);
stk1 = stk;
stk.push(3);
stk.push(4);
stk.pop();
stk.top();
cout<
#include "iostream"
#include "vector"
#include "deque"
#include "stack"
#include "queue"
using namespace std;
int main() {
queue q;
queue 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;
}
功能:链式存储
链表:是一种物理存储单元上非连续的存储结构,数据元素顺序是通过链表中的指针链接实现的
链表的组成:链表是由一系列节点组成
节点的组成:数据域 和 指针域
STL中的链表是一个双向循环链表
构造
list l
list
list
list
赋值和交换
#include "iostream"
#include "list"
using namespace std;
void printList(const list &l){
for (list::const_iterator it= l.begin(); it != l.end(); it++){
cout<<*it<<" ";
}
cout< l;
l.push_back(3);
l.push_back(3);
l.push_back(3);
list l1 = l;
cout<
大小操作
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 &pList) {
for (list::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() pList = {
p1, p2, p3, p4, p5, p6
};
pList.sort(comparePerson);
printList(pList);
return 0;
}
自动排序
本质:关联式容器,底层二叉树
set/multiset 区别:
set 不允许有重复元素
multiset 允许存在重复元素
#include "iostream"
#include "set"
using namespace std;
void printSet(const set &sets) {
for (set::const_iterator it = sets.begin(); it != sets.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
set s1;
s1.insert(1);
s1.insert(2);
s1.insert(3);
s1.insert(4);
printSet(s1);
/// 大小
set 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 &sets) {
for (set::const_iterator it = sets.begin(); it != sets.end(); it++) {
cout << *it << " ";
}
cout << endl;
}
int main() {
pair p("tom",23);
cout< p1 = make_pair("jeery",23);
cout<
排序
重写内置类型排序规则
#include "iostream"
#include "set"
using namespace std;
class MyCompare{
public:
bool operator()(int v1,int v2){
return v1 > v2;
}
};
int main() {
set s1;
s1.insert(20);
s1.insert(30);
s1.insert(40);
s1.insert(20);
s1.insert(10);
for ( set::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 s;
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
s.insert(p5);
s.insert(p6);
for (set::iterator it = s.begin(); it != s.end(); it++) {
it->showInfo();
}
return 0;
}
简介
本质:关联式容器,二叉树
优点:快速查找value
map和multimap区别:key是否重复
#include "iostream"
#include "map"
#include "fstream"
using namespace std;
void printMap(map &m) {
for (map::iterator it = m.begin(); it != m.end(); it++) {
cout << it->first << " " << it->second << endl;
}
}
int main() {
map m;
m.insert(pair(1, "10"));
m.insert(pair(2, "20"));
m.insert(pair(3, "30"));
map m1(m);
map m2 = m;
printMap(m);
m.size();
m.empty();
m.swap(m1);
m.clear();
m.erase(m.begin());
m.erase(m.begin(),m.end());
cout<
这些api不要硬记,记住底层的结构即可,方法大同小异
容器总结
序列容器
List封装链表,Vector封装了数组
Vector:向量
相当于一个数组,在内存中分配一块连续的内存空间进行存储。支持不指定vector大小的存储。STL内部实现时,首先分配一个非常大的内存空间预备进行存储,即capacity()函数返回的大小,当超过此分配的空间时在整体重新分配一块内存地址,这个人以vector可以不指定vector即一个连续内存的大小的感觉。通常此默认的内存分配能完成大部分情况下的存储
优点:
1. 连续内存,向数组一样操作
2. 随机访问方便,支持[]和at
3. 节省空间
缺点:
1. 插入删除效率低
2. 只能在vector的最后进行push和pop,不能在vector的头进行push和pop
3. size > capacity 时,重新分配、拷贝与释放
List:双向链表
每个节点都包括一个信息块、一个前驱指针Pre、一个后驱指针Post。可以不分配必须的内存大小,方便的进行添加和删除操作。使用的是非连续的内存空间进行存储
优点:
1. 不使用连续内存完成动态操作
2. 在内部方便的进行插入和删除操作
3. 可在两端进行push、pop
缺点:
1. 不能进行内部的随机访问,即不支持[]和at
2. 相对vector占用内存多
deque:双端队列
deque是在功能上合并了vector和list
优点:
1. 随机访问方便,即支持[]和at
2. 在内部方便的进行插入和删除操作
3. 可在两端进行push、pop
使用区别
1. 如果需要高效随机存取,而不在乎插入和删除的效率,使用vector
2. 如果需要大量的插入和删除,而不关心随机存取,则应使用list
3. 如果需要随机存取,而且关心两端数据的插入和删除,则应使用deque
关联容器
Map、Set属于标准关联容器,使用了非常高效的平衡检索二叉树:红黑树,他的插入删除效率比其他容器高是因为不需要做内存拷贝和内存移动,而直接替换指向节点的指针即可
Set和Vector在于Set不包含重复数据。Set和Map的区别在于Set只含有Key,而Map有一个Key和Key对应的Value两个元素
Map和Hash_Map的区别是Hash_Map使用了Hash算法来加快查找过程,但是需要更多的内存来存放这些hash桶元素,因此可以算得上空间换时间的策略