网站建设 自查表,建筑材料网站建设,wordpress插件取消,萍乡企业做网站文件操作
程序运行时产生的数据属于临时数据#xff0c;程序一旦运行结束都会被释放
通过文件可以将数据持久化
c中对文件操作需要包含
文件类型分为两种
文本文件#xff1a;文件以ASCII码形式存储在计算机中二进制文件#xff1a;文件以文本的二进制存储在计算机中程序一旦运行结束都会被释放
通过文件可以将数据持久化
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 fstreamusing namespace std;void test() {// 创建流对象ofstream ofs;ofs.open(/Users/mac/CLionProjects/c_overwrite/text.txt,ios::out);ofs姓名张三endl;ofs性别男endl;ofs年龄18endl;// 关闭文件ofs.close();}int main(int arg, char *argv[]) {test();return 0;
}读文件
#include iostream
#include fstreamusing 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) {coutbufendl;}*//// 第二种/*char buf[1024] {0};while (ifs.getline(buf, sizeof(buf))) {cout buf endl;}*//// 第三种/*string buf;while (getline(ifs,buf)){coutbufendl;}*//// 第四种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 fstreamusing 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提供两种模版机制函数模版和类模版
函数模版
函数模版作用
建立一个通用函数其函数返回值类型和形参类型可以不具体制定用一个虚拟的类型来代表
语法
templatetypename T
函数声明或定义解释
template — 声明创建模版
typename — 表明后面的符号是一种数据类型也可以用class替换
#include iostreamusing namespace std;templatetypename 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 显示指定类型mySwapdouble(c, d);cout a b endl;return 0;
}注意事项
自动类型推导必须推导出已知的数据类型T才可以使用模版必须要确定出T的数据类型才可以使用
练习
#include iostreamusing namespace std;templatetypename 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 iostreamusing namespace std;/// 普通函数
int myAdd1(int a, int b) {return a b;
}
/// 函数模版
templatetypename 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 myAdd2int(a, c) endl;return 0;
}
总结建议使用显示类型的方式调用函数模版应为自己可以确定通用类型
普通函数与函数模版调用的规则
如果函数模版和普通函数都可以实现优先调用普通函数可以通过空模版参数列表来强制调用函数模版函数模版也可以发生重载如果函数模版可以产生更好的匹配优先调用函数模版
#include iostreamusing namespace std;void myPrint(int a, int b) {cout 调用普通函数 endl;
}templatetypename T
void myPrint(int a, int b) {cout 调用模版函数 endl;
}int main() {int a 20;int b 20;myPrint(a, b);myPrintvoid(a, b);int c c;int d d;myPrintchar(c, d);return 0;
}总结一句话调用函数模版时传递类型参数否则自己都不清楚掉哪个
模版具体化
模版局限性
模版并不是万能的有些特定数据类型需要用具体化方式做特殊实现
#include iostreamusing namespace std;class Person {string name;
public:Person(string name) : name(name) {};string getName() {return name;}
};templatetypename 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 iostreamusing namespace std;templateclass 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() {Personstring, int p(张三, 3);p.showInfo();return 0;
}类模版与函数模版区别
类模版没有自动类型推导的使用方式类模版在模版参数列表中可以有默认参数
类模版中成员函数创建时机
普通类成员函数一开始就可以创建类模版中的成员函数在调用时才创建
#include iostreamusing namespace std;class Person {public:void showPerson1() {cout show person1 endl;}
};templateclass T
class MyClass {T obj;public:void showInfo1() {obj.showPerson1();}void showInfo2() {obj.showPerson2();}
};int main() {MyClassPerson mc;mc.showInfo1();/// 编译报错
// mc.showInfo2();return 0;
}
类模版对象做函数参数
三种方式
指定转入方式 – 直接显示对象的数据类型参数模版化 – 将对象中的参数变为模版进行传递整个类模版化 – 将这个对象类型 模版化进行传递
#include iostreamusing namespace std;templateclass 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(Personstring, int p) {p.showPerson();
}/// 2 参数化模版
templateclass T1, class T2
void print2(PersonT1, T2 p) {cout typeid(T1).name() endl;p.showPerson();
}/// 3 整个类模版化
templateclass T
void print3(T p) {cout typeid(T).name() endl;p.showPerson();
}int main() {Personstring, int p1(孙悟空, 3);print1(p1);Personstring, int p2(八届, 3);print2(p1);Personstring, int p3(唐僧, 3);print3(p3);return 0;
}
总结常用的是指定传入类型
类模版与继承
当子类继承的父类是一个类模版是子类在声明的时候要指定出父类中T的类型如果不指定编译器无法给子类分配内存如果想灵活指定出父类中T的类型子类也需要变为类模版
#include iostreamusing namespace std;templateclass T
class Base {T m;
};/// 此时才能计算出子类占用多少内存空间
class Son : public Baseint {};/// 如果想要灵活指定父类T类型子类也需要变类模版templateclass T1, class T2
class Son2 : public BaseT1 {T2 n;
};int main() {return 0;
}
成员函数的类外实现
#include iostreamusing namespace std;templateclass T1, class T2
class Person {
public:T1 name;T2 age;Person(T1 name, T2 age);void showPerson();
};
/// 类外构造
templateclass T1, class T2
PersonT1, T2::Person(T1 name, T2 age) {this-name name;this-age age;
}/// 类外成员函数
templateclass T1, class T2
void PersonT1, T2::showPerson() {cout name age endl;
}int main() {return 0;
}
类模版份文件编写
问题
类模版中成员函数创建时间是在调用阶段导致份文件编写时链接不到
解决
方式一直接包含.cpp源文件方式二将声明和实现写到同一个文件中并更改后缀名为.hpp,hpp是约定的名称并不是强制
第二种方式代码
person.hpp
#include iostream
#include person.h
using namespace std;templateclass T1, class T2
class Person {
public:T1 name;T2 age;Person(T1 name, T2 age);void showPerson();
};templateclass T1, class T2
PersonT1, T2::Person(T1 name, T2 age) {this-name name;this-age age;
}/// 类外成员函数
templateclass T1, class T2
void PersonT1, T2::showPerson() {cout name age endl;
}main.cpp
#include iostream
/// 第一种解决方式 直接包含源文件
//#include person.cpp
#include person.hpp
using namespace std;int main() {Personstring ,int p(zhangsan,89);p.showPerson();return 0;
}类模版与友元
#include iostreamusing namespace std;templateclass T
class Color;templateclass T
void printInfo2(ColorT c) {cout (c.c) endl;
}templateclass T
class Color {/// 全局函数类内实现friend void printInfo1(ColorT c) {cout c.c endl;};/// 类外实现比较麻烦friend void printInfo2(ColorT c);private:T c;
public:Color(T c) : c(c) {};
};int main() {Colorstring c(red);printInfo1(c);printInfo2(c);
// Personstring, 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 vectorusing namespace std;void myPrint(int value) {cout value endl;
}void test1() {vectorint v;v.push_back(10);v.push_back(20);v.push_back(30);/// 第一种/* vectorint::iterator itBegin v.begin();/// 起始迭代器vectorint::iterator itEnd v.end();/// 结束迭代器while (itBegin ! itEnd) {cout *itBegin endl;itBegin;}*//// 第二种/*for (vectorint::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 vectorusing 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 vectorusing namespace std;int main() {/// 追加操作string str hello world;string s1 world;strs1;strc;/// 类似提供 append 唯一的不同str.append(hellowlro ,3,5);coutstrendl;return 0;
}查找和替换
#include iostream
#include vectorusing namespace std;int main() {/// 追加操作string str hello world d;/// 查找 从左查 第一次出现的位置还有一个位置的参数int dIndex str.find(d);coutdIndexendl;/// 查找 从右查 第一次出现的位置还有一个位置的参数int rdIndex str.rfind(d);coutrdIndexendl;/// 替换str.replace(0,1,aaaa);coutstrendl;return 0;
}string 字符串比较
比较方式 字符串比较是按字符的ASCI码进行对比 返回0 返回 1 返回 -1
#include iostream
#include vectorusing namespace std;int main() {/// 字符串比较是否相等string a 中国;string b 中国;couta.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 vectorusing namespace std;int main() {string str hello world;str.insert(0,aaa);str.insert(0,bbb,2);/// 后边这个参数感觉着实意义不大指定插入几个字符coutstrendl;str.erase(0,3);coutstrendl;return 0;
}获取子串
#include iostream
#include vectorusing namespace std;int main() {/// 一个中文 三个字符string str 中国力量;string s1 str.substr(0,3);couts1endl;return 0;
}vector
功能
vector数据结构和数组非常相似也称为单端数组
vector与普通数组区别
不同之处在于数组是静态空间而vector可以动态扩展
动态扩展
并不是在原空间后续接新空间而是找更大的内存空间然后将原数据拷贝新空间释放原空间
vector容器的迭代器是支持随机访问的迭代器
构造函数
vector v
vector(v.begin(),v.end())
vector(n,element)
vector(const vector vec)
#include iostream
#include vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}
}int main() {/// 1vectorint v1;for (int i 0; i 10; i) {v1.push_back(i);}/// 2vectorint v2(v1.begin(),v1.end());/// 3vectorint v3(10,100);/// 4vectorint v4(v3);printVector(v3);return 0;
}赋值
#include iostream
#include vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}
}int main() {vectorint v1;for (int i 0; i 10; i) {v1.push_back(i);}vectorint v2(10,100);/// 运算符重载v1 v2;/// 指定迭代器v1.assign(v2.begin(),v2.end());/// n个elemv1.assign(10,101);printVector(v1);return 0;
}
容量和大小
#include iostream
#include vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}
}int main() {vectorint v1;for (int i 0; i 33; i) {v1.push_back(i);}/// 是否为空coutv1.empty()endl;/// 容量: 每次扩容为上一次的2倍coutv1.capacity()endl;/// 大小coutv1.size()endl;/// 重新指定大小
// v1.resize(15);printVector(v1);return 0;
}
插入与删除
#include iostream
#include vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}
}int main() {vectorint v1;for (int i 0; i 10; i) {/// 尾部插入v1.push_back(i);}/// 尾部删除v1.pop_back();/// 指定pos插入vectorint::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 vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}
}int main() {vectorint v1;for (int i 0; i 10; i) {v1.push_back(i);}/// 1 获取数据int i3 v1.at(3);int i4 v1[4];couti4endl;/// 2 获取收尾元素int front v1.front();int back v1.back();printVector(v1);return 0;
}
互换容器
#include iostream
#include vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}cout endl;
}int main() {/*vectorint v1;for (int i 0; i 10; i) {v1.push_back(i);}vectorint v2;for (int i 10; i 20; i) {v2.push_back(i);}v1.swap(v2);printVector(v1);printVector(v2);*//// 利用swap巧妙收缩vectorint v;for (int i 0; i 10000; i) {v.push_back(i);}cout 容量 v.capacity() endl;cout 大小 v.size() endl;v.resize(3);vectorint(v).swap(v);// 互换以size为准cout 容量 v.capacity() endl;cout 大小 v.size() endl;return 0;
}预留空间
#include iostream
#include vectorusing namespace std;void printVector(vectorint v) {for (vectorint::iterator it v.begin(); it ! v.end(); it) {cout *it ;}cout endl;
}int main() {/// 利用swap巧妙收缩vectorint 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
dequebeg,end deqT
dequen,ele deqT
dequeconst deque deq deqT
#include iostream
#include vector
#include dequeusing namespace std;void printDeque(const dequeint d) {for (dequeint::const_iterator it d.begin(); it ! d.end(); it) {cout *it ;}cout endl;
}int main() {dequeint deq;for (int i 0; i 10; i){deq.push_back(i);}dequeint d1(deq.begin(),deq.end());dequeint d2(10,100);dequeint d3(d2);printDeque(d3);return 0;
}
赋值操作
#include iostream
#include vector
#include dequeusing namespace std;void printDeque(const dequeint d) {for (dequeint::const_iterator it d.begin(); it ! d.end(); it) {cout *it ;}cout endl;
}int main() {dequeint 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 dequeusing namespace std;void printDeque(const dequeint d) {for (dequeint::const_iterator it d.begin(); it ! d.end(); it) {cout *it ;}cout endl;
}int main() {dequeint deq;for (int i 0; i 10; i){deq.push_back(i);}coutdeq.size()endl;coutdeq.empty()endl;deq.resize(3);deq.resize(22,2);printDeque(deq);return 0;
}插入和删除
#include iostream
#include vector
#include dequeusing namespace std;void printDeque(const dequeint d) {for (dequeint::const_iterator it d.begin(); it ! d.end(); it) {cout *it ;}cout endl;
}int main() {dequeint 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());dequeint::iterator it deq.begin();*it 10;deq.erase(it);printDeque(deq);return 0;
}存取
#include iostream
#include vector
#include dequeusing namespace std;void printDeque(const dequeint d) {for (dequeint::const_iterator it d.begin(); it ! d.end(); it) {cout *it ;}cout endl;
}int main() {dequeint 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 dequeusing namespace std;void printDeque(const dequeint d) {for (dequeint::const_iterator it d.begin(); it ! d.end(); it) {cout *it ;}cout endl;
}int main() {dequeint 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 stackusing namespace std;int main() {stackint stk;stackint stk1(stk);stk1 stk;stk.push(3);stk.push(4);stk.pop();stk.top();coutstk.empty()endl;coutstk.size()endl;return 0;
}queue
#include iostream
#include vector
#include deque
#include stack
#include queueusing namespace std;int main() {queueint q;queueint 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
listbeg,end l
listn,ele l
listconst list lis l
赋值和交换
#include iostream#include listusing namespace std;void printList(const listint l){for (listint::const_iterator it l.begin(); it ! l.end(); it){cout*it ;}coutendl;
}int main() {listint l;l.push_back(3);l.push_back(3);l.push_back(3);listint l1 l;coutl1.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 listusing 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 listPerson pList) {for (listPerson::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);listPerson pList {p1, p2, p3, p4, p5, p6};pList.sort(comparePerson);printList(pList);return 0;
}
set/multiset
自动排序
本质关联式容器底层二叉树
set/multiset 区别
set 不允许有重复元素
multiset 允许存在重复元素
#include iostream#include setusing namespace std;void printSet(const setint sets) {for (setint::const_iterator it sets.begin(); it ! sets.end(); it) {cout *it ;}cout endl;
}int main() {setint s1;s1.insert(1);s1.insert(2);s1.insert(3);s1.insert(4);printSet(s1);/// 大小setint 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 setusing namespace std;void printSet(const setint sets) {for (setint::const_iterator it sets.begin(); it ! sets.end(); it) {cout *it ;}cout endl;
}int main() {pairstring,int p(tom,23);coutp.first p.secondendl;pairstring,int p1 make_pair(jeery,23);coutp1.first p1.secondendl;return 0;
}
排序
重写内置类型排序规则
#include iostream#include setusing namespace std;class MyCompare{
public:bool operator()(int v1,int v2){return v1 v2;}
};int main() {setint,MyCompare s1;s1.insert(20);s1.insert(30);s1.insert(40);s1.insert(20);s1.insert(10);for ( setint,MyCompare::iterator it s1.begin(); it ! s1.end(); it){cout*it ;}return 0;
}自定义类型
#include iostream#include setusing 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);setPerson, MyCompare s;s.insert(p1);s.insert(p2);s.insert(p3);s.insert(p4);s.insert(p5);s.insert(p6);for (setPerson, MyCompare::iterator it s.begin(); it ! s.end(); it) {it-showInfo();}return 0;
}
map/multimap
简介
map中所有的元素都是pairpair中第一个元素为key(键值)起到索引作用第二个为value(实值)所有的元素会根据元素的键值自动排序
本质关联式容器二叉树
优点快速查找value
map和multimap区别key是否重复
#include iostream#include map
#include fstreamusing namespace std;void printMap(mapint, string m) {for (mapint, string::iterator it m.begin(); it ! m.end(); it) {cout it-first it-second endl;}}int main() {mapint, string m;m.insert(pairint, string(1, 10));m.insert(pairint, string(2, 20));m.insert(pairint, string(3, 30));mapint, string m1(m);mapint, string m2 m;printMap(m);m.size();m.empty();m.swap(m1);m.clear();m.erase(m.begin());m.erase(m.begin(),m.end());coutm[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桶元素因此可以算得上空间换时间的策略