C++模板和STL
模板
函数模板的定义
例:
#include <iostream>
using namespace std;
//函数模板,"T"类型形参
template <typename T> //推荐使用typename
//template <class T>
T max(T x, T y){
return x<y?y:x;
}
int main(void){
int i1=100,i2=200;
// "<>"指明函数模板需要的类型实参
// "()"指明函数的调用实参
cout<<::max<int>(i1,i2)<<endl;
double d1=1.23,d2=4.56;
cout<<::max<double>(d1,d2)<<endl;
string s1="world",s2 = "hello";
cout<<::max<string>(s1,s2)<<endl;
char str1[] = "world";
char str2[] = "hello";
cout<<::max<string>(str1,str2)<<endl;
return 0;
}
函数模板的使用
模板实例化
类型参数
参考代码:
#include <iostream>
using namespace std;
template <typename T>
T add(T x,T y){
return x+y;
}
class Complex{ //复数
public:
Complex(int r,int i):m_r(r),m_i(i){}
//cout<<c1==>operator<<(cout,c1)
friend ostream& operator<<(ostream& os,const Complex& c){
os<<c.m_r<<"+" <<c.m_i<<"i";
return os;
}
//重载+ (成员函数形式)
//c1+c2 ==>c1.operator(c2)
const Complex operator+(const Complex& c)const{
Complex res(m_r+c.m_r,m_i+c.m_i);
return res;
}
private:
int m_r;
int m_i;
};
int main(void){
cout<<add<int>(123,456)<<endl;
cout<<add<double>(1.23,4.56)<<endl;
Complex c1(1,2);
Complex c2(3,4);
cout<<c1<<","<<c2<<endl;
cout<<add<Complex>(c1,c2)<<endl; //4+6i
}
二次编译
函数模板的隐式推断
参考代码:07deduce.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename A,typename V>
void func1(A arg){
V var;
cout <<"调用参数类型:"<<typeid(arg).name()<<endl;
cout <<"局部变量类型:"<<typeid(var).name()<<endl;
}
template <typename T>
void func2(T x,T y){
cout<<"参数x类型:"<<typeid(x).name()<<endl;
cout<<"参数y类型: "<<typeid(y).name()<<endl;
}
template <typename T1,typename T2>
T1 func3(T2 x){
T1 y;
cout <<"参数x类型:"<<typeid(x).name()<<endl;
cout <<"返回y类型:"<<typeid(y).name()<<endl;
return y;
}
int main(void){
//func1(100); //error
func1<int,int>(11); //ok
//func2(100,1.23); //error
func2<int>(100,1.23); //显示推断。隐式转换
func2<double>(100,1.23);
func2(100,(int)1.23) ; //显示转换,隐式推断
func2((double)100,1.23);
//double d = func3(100); //error
double d = func3<double>(100); //显式指明返回类型,隐式推断参数类型
}
函数模板的重载
参考代码:07overload.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
void func(T x, T y){ //针对两个任意类型的数据:约束性一般
cout<<"func(1),type="<<typeid(T).name()<<endl;
}
template <typename T>
void func(T* x,T* y){
cout<<"func(2),type="<<typeid(T).name()<<endl;
}
int main(void){
int a = 10,b = 20;
func(a,b) ; //func(1) ,T = int
func(&a,&b); //func(2),T = int
func<int*>(&a,&b); //func(1) ,T= int*
return 0;
}
参考代码2: 08overload.cpp
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
void func(T x, T y){ //针对两个任意类型的数据:约束性一般
cout<<"func(1),type="<<typeid(T).name()<<endl;
}
template <typename T>
void func(T* x,T* y){
cout<<"func(2),type="<<typeid(T).name()<<endl;
}
void func(const char* x,const char* y){ //针对性两个const char *:约束性更强
cout<<"func(3),type="<<typeid(x).name()<<endl;
}
int main(void){
int a = 10,b = 20;
func(a,b) ; //func(1) ,T = int
func(&a,&b); //func(2),T = int
func<int*>(&a,&b); //func(1) ,T= int*
const char* s1 = "123";
const char* s2 = "456";
func(s1,s2); //func(3);
func<>(s1,s2); //func(2)
//如果匹配func(2),类型实参const char*,调用参数类型应该式const char**,无法和调用实参s1,s2
//相匹配,所以只能选中第一个版本
func<const char*>(s1,s2); //func(1)
return 0;
}
类模板的定义
类模板的使用
类模板的实例化
类模板中的成员函数
参考代码:09ct.cpp
#include <iostream>
using namespace std;
template <typename T>
class Compare{ //类模板
public:
Compare(T x,T y):m_x(x),m_y(y){}
T max(void) const{
return m_x < m_y ? m_y:m_x;
}
T min(void) const {
//return m_x >m_y ?m_y:m_x;
//对于类模板的设计者,应该尽可能减少对类型实参的要求,方便类模板的使用者
return m_x < m_y ? m_x:m_y;
}
private:
T m_x;
T m_y;
};
class Integer{
public:
Integer(int data):m_data(data){}
friend ostream& operator<<(ostream& os,const Integer& i){
os<<i.m_data;
return os;
}
//重载《成员函数形式》
bool operator<(const Integer& i) const{
return m_data<i.m_data;
}
//重载>(成员函数形式)
bool operator >(const Integer& i) const{
return m_data>i.m_data;
}
private:
int m_data;
};
int main(void){
//先结合<int>实例化具体的类,再使用该类实例化ci对象
//Compare<int> ci(123,456);
//cout<<"max="<<ci.max()<<",min="<<ci.min()<<endl;
//Compare<double> cd(1.23,4.56);
//cout<<"max="<<cd.max()<<",min="<<cd.min()<<endl;
//cout<<sizeof(Compare)<<endl; //error
//cout<<sizeof(Compare<int>)<<endl; //ok ,8
//Compare cc('A','B'); //error
//Compare<int>ci(123,456);
//cout<<"max="<<ci.max()<<",min="<<ci.min()<<endl;
Integer i1(123);
Integer i2(456);
Compare<Integer>cInt(i1,i2);//ok
cout<<"max="<<cInt.max()<<endl;
return 0;
}
类模板的静态成员
参考代码:static.cpp
#include <iostream>
using namespace std;
template <typename T>
class A{
public:
void printAddr(void){
cout<<"&m_data:"<<&m_data<<",s_data="<<&s_data<<endl;
}
private:
int m_data; //普通成员变量
static int s_data; //静态成员便利
};
template <typename T>
int A<T>::s_data; //定义
int main(void){
A<int> i1,i2;
A<double> d1,d2;
//一共有几个m_data(4)个?s_data?(2个
i1.printAddr();
i2.printAddr();
d1.printAddr();
d2.printAddr();
}
类模板的递归实例化
参考代码:
#include <iostream>
using namespace std;
template <typename T>
class Array{
public:
//下标操作符重载
T& operator[](size_t i){
return m_a[i] ;
}
const T& operator[] (size_t i)const{
return m_a[i] ;
}
//获取容器中元素个数
size_t size(void)const{
return sizeof(m_a)/sizeof(m_a[0]);
}
//重载<<
friend ostream& operator<<(ostream& os,const Array& arr){
for(size_t i=0;i<arr.size();i++) {
os<<arr[i] <<' ';
}
return os;
}
private:
T m_a[3];
};
int main(void){
Array<int>a1;
a1[0] = 10;
a1[1] = 20;
a1[2] = 30;
cout<<a1<<endl;
Array<int>a2;
a2 = a1;
cout<<a2<<endl;
//递归实例化:用类模板实例化的类型,作为类型实参,再实例化该类模板自身
Array<Array<int> >aa;//二维数组
for(size_t i=0;i<aa.size();i++)
for(size_t j=0;j<aa[i].size();j++)
aa[i][j] = i*3+j+1; //1 2 3 4 5 6 7 8 9
for(size_t i=0;i<aa.size();i++){
cout<<aa[i] <<endl;
}
return 0;
}
类模板的特化
全类特化
参考代码:
#include <iostream>
#include <cstring>
using namespace std;
template <typename T>
class Compare{
public:
Compare(T x,T y):m_x(x),m_y(y){}
T Max(void){
cout<<"通用版本" <<endl;
return m_x<m_y?m_y:m_x;
}
private:
T m_x;
T m_y;
};
template <>
class Compare<char *>{ //全类特化(针对char *实例化的具体类)
public:
Compare(char *x,char *y):m_x(x),m_y(y){}
char *Max(void){
cout<<"特化版本"<<endl;
return strcmp(m_x,m_y)<0?m_y:m_x;
}
private:
char *m_x;
char* m_y;
};
int main(void){
Compare<int> cInt(123,456);
cout<<cInt.Max()<<endl; //456
char s1[] = "world";
char s2[] = "hello";
Compare<char *>cChar(s1,s2);
cout<<cChar.Max()<<endl; //world
return 0;
}
成员特化
参考代码:
#include <iostream>
#include <cstring>
using namespace std;
template <typename T>
class Compare{
public:
Compare (T x,T y):m_x(x),m_y(y){}
T Max(void)const{
cout<<"通用版本" <<endl;
return m_x<m_y?m_y:m_x;
}
private:
T m_x;
T m_y;
};
template<>
char *Compare<char *>::Max(void)const{ //成员特化(针对char* 重写的Max函数)
cout<<"特化版本"<<endl;
return strcmp(m_x,m_y)<0?m_y:m_x;
}
int main(void){
Compare<int> cInt(123,456);
cout<<cInt.Max()<<endl; //456
char s1[] = "world";
char s2[] = "hello";
Compare<char *>cChar(s1,s2);
cout<<cChar.Max()<<endl; //world
return 0;
}
局部(偏)特化
模板的使用技巧
类模板参数的缺省值
参考代码:
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename A=double,typename B=A>
class X{
public:
static void foo(void){
cout<<typeid(A).name()<<","<<typeid(B).name()<<endl;
}
};
template<typename A=int,typename B=double>
void fun(void){
cout<<typeid(A).name()<<","<<typeid(B).name()<<endl;
}
int main(void){
X<int,int>::foo();
X<int>::foo();
X<double>::foo();
X<>::foo();
return 0;
}
数值型模板参数(非类型参数)
参考代码
#include <iostream>
using namespace std;
template<typename T,size_t S=10/*数值型模板参数*/>
class Array{
public:
T& operator[](size_t i){
return m_arr[i] ;
}
const T& operator[](size_t i)const{
return m_arr[i] ;
return const_cast<Array&>(* this) [i];
}
size_t size(void) const{
return sizeof(m_arr)/sizeof(m_arr[0] );
}
friend ostream& operator<<(ostream& os,const Array& arr){
for(size_t i=0;i<arr.size();i++){
os<<arr[i] <<' ';
}
return os;
}
private:
T m_arr[S];
};
int main(void){
Array<int,10> arr; //int arr[10]
for(int i=0;i<10;i++){
arr[i]=i+1;
}
cout<<arr<<endl;
Array<int,4+6>arr2;
cout<<arr2.size()<<endl; //10
int num1=4,num2=6;
//Array<int,num1+num2>arr3; //error
const int num3 = 4,num4 = 6;
Array<int,num3+num4>arr4; //ok
cout<<arr4.size()<<endl; //10
Array<int>arr5;
cout<<arr5.size()<<endl; // 10
return 0;
}
嵌套依赖
解决嵌套依赖
参考代码:
#include <iostream>
using namespace std;
class A{
public:
typedef unsigned int uint;
class B{};
};
template <typename T>
void fun(void){
//函数模板第一次编译时,不知T的具体类型,无法正确理解"T::"
//T::uint i=123; //error
//T::B b; //error
//使用typename告诉编译器"T::xx"是一个类型,具体留到第二次再处理
typename T::uint i=123;
typename T::B b;
}
int main(void){
A::uint i=123;
A::B b; //ok
fun<A>();
return 0;
}
依赖模板参数访问成员函数模板
参考代码:
#include <iostream>
using namespace std;
class A{
public:
template <typename T>
void func(void){
cout<<"A::func<T>"<<endl;
}
};
template<typename T>
void func2(void){
T a;
//第一次编译是,无法正确理解"<>" 编译报错
//a.func<int>(); //error
//使用template告诉编译器,<>是模板语法,让其正确理解
a.template func<int>(); //ok
}
int main(void){
A a;
a.func<int>();
func2<A>();
return 0;
}
子模板访问基类模板
参考代码:06inherit.cpp
#include <iostream>
using namespace std;
template <typename T>
class Base{
public:
void foo(void){
cout<<"Base<T>::foo"<<endl;
}
};
template <typename T>
class Derived:public Base<T>{
public:
void func(void){
//foo(); //error,默认不会从基类找foo
//需要使用基类模板的成员,可以显示指明
Base<T>::foo();
this->foo();
}
};
int main(void){
Derived <int> d;
d.func();
return 0;
}
模板型成员变量
参考代码:
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>class A{};
template <typename T>class B{
public:
A<T>m_a; //模板型的成员变量
T m_b; //类模板的普通成员变量
};
int main(void){
B<int>b;
cout<<typeid(b.m_a).name()<<endl;
cout<<typeid(b.m_b).name()<<endl;
return 0;
}
模板型成员函数
参考代码:
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>class A{
public:
void func1(const T& t);/*{
cout<<"类模板的普通成员函数:"<<typeid(t).name()<<endl;
}*/
template<typename V> void func2(const V& v);/*{
cout<<"类模板的模板型成员函数:"<<typeid(v).name()<<endl;
}*/
};
template <typename T>
void A<T>::func1(const T& t){
cout<<"类模板的普通成员函数:"<<typeid(t).name()<<endl;
}
template<typename T> //类模板需要的类型参数
template <typename V> //类模板成员函数需要的类型参数
void A<T>::func2(const V& v){
cout<<"类模板的模板型成员函数::" <<typeid(v).name()<<endl;
}
int main(void){
A<int>a;
a.func1(123);
a.func2<double>(1.23);
return 0;
}
模板型成员类型
参考代码:
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>class A{
public:
void func1(const T& t);/*{
cout<<"类模板的普通成员函数:"<<typeid(t).name()<<endl;
}*/
template<typename V> void func2(const V& v);/*{
cout<<"类模板的模板型成员函数:"<<typeid(v).name()<<endl;
}*/
};
template <typename T>
void A<T>::func1(const T& t){
cout<<"类模板的普通成员函数:"<<typeid(t).name()<<endl;
}
template<typename T> //类模板需要的类型参数
template <typename V> //类模板成员函数需要的类型参数
void A<T>::func2(const V& v){
cout<<"类模板的模板型成员函数::" <<typeid(v).name()<<endl;
}
int main(void){
A<int>a;
a.func1(123);
a.func2<double>(1.23);
return 0;
}
模板型模板参数
参考代码
#include <iostream>
using namespace std;
template <typename T>class Array{ //模拟数组容器(内存连续)
public:
void push_back(const T& data){
cout<<"在数组尾端压入一个元素" <<endl;
}
void pop_back(void){
cout<<"从数组尾部弹出一个元素"<<endl;
}
};
template<typename T>class List{ //模拟链表容器(内存不连续)
public:
void push_back(const T& data){
cout<<"在链表的尾部压入一个元素"<<endl;
}
void pop_back(void){
cout<<"在链表的尾部压入一个元素"<<endl;
}
};
template <typename T,template <typename> class C/*C=Array*/>
class Stack{
public:
void push(const T& data){
m_c.push_back(data);
}
void pop(void){
m_c.pop_back();
}
private:
C<T>m_c; //Array<int> m_c;
};
int main(void){
Stack<int,Array>s1;
//Stack<int>s1;
s1.push(123);
s1.pop();
Stack<int,List>s2;
s2.push(123);
s2.pop();
return 0;
}
模板型模板参数的缺省参数
参考代码:
#include <iostream>
using namespace std;
template <typename T>class Array{ //模拟数组容器(内存连续)
public:
void push_back(const T& data){
cout<<"在数组尾端压入一个元素" <<endl;
}
void pop_back(void){
cout<<"从数组尾部弹出一个元素"<<endl;
}
};
template<typename T>class List{ //模拟链表容器(内存不连续)
public:
void push_back(const T& data){
cout<<"在链表的尾部压入一个元素"<<endl;
}
void pop_back(void){
cout<<"在链表的尾部压入一个元素"<<endl;
}
};
template <typename T,template <typename> class C=Array>
class Stack{
public:
void push(const T& data){
m_c.push_back(data);
}
void pop(void){
m_c.pop_back();
}
private:
C<T>m_c; //Array<int> m_c;
};
int main(void){
//Stack<int,Array>s1;
Stack<int>s1;
s1.push(123);
s1.pop();
Stack<int,List>s2;
s2.push(123);
s2.pop();
return 0;
}
模板中的虚函数
参考代码:
#include <iostream>
using namespace std;
template<typename T>class Base{
public:
virtual T foo(void){
cout<<"基类模板中的虚函数" <<endl;
}
};
template<typename T,typename D> class Derived:public Base<T>{
public:
virtual D foo(void){
cout<<"子类模板中的虚函数" <<endl;
}
//模板型成员函数不能为虚函数
//template<typename R>virtual R fun(void){}
};
int main(void){
Derived<int,int>d;
Base<int>*p =&d;
//p->foo();
return 0;
}
零初始化
未初始化的基本类型
参考代码:
#include <iostream>
using namespace std;
class Student{
public:
Student(void):m_name("无名"),m_age(0),m_no(0){}
friend ostream& operator<<(ostream& os,const Student& s){
os<<s.m_name<<","<<s.m_age<<","<<s.m_no;
return os;
}
private:
string m_name;
int m_age;
int m_no;
};
template<typename T>void func(void){
//如果T是基本类型,使用0零值来初始化
//如果T是类类型对象,调用该的无参构造函数来初始化
T var = T();
cout<<var<<endl;
}
int main(void){
func<int>();
func<double>();
func<string>();
func<Student>();
return 0;
}
模板实战(双向链表容器List)
原有链表
压入新节点
从链表头弹出节点
从尾部压入新节点
从链表尾部弹出节点
参考代码:
#include <iostream>
using namespace std;
//双向线性链表(列表容器)
template<typename T>class List{
public:
//缺省构造函数
List():m_head(NULL),m_tail(NULL){}
//拷贝构造(深拷贝)
List(const List& that):m_head(NULL),m_tail(NULL){
for(Node* pnode = that.m_head;pnode!=NULL;pnode=pnode->m_next){
push_back(pnode->m_data);
}
}
//that: 1 2 3 4 5 6
//新:1 2 3 4 5
//拷贝赋值(深拷贝)
//list1 = list2==>list1.operator=(list2)
List& operator=(const List& that){
if(&that !=this){
List tmp = that;
swap(m_head,tmp.m_head);
swap(m_tail,tmp.m_tail);
}
return *this;
}
//析构函数
~List(void){
clear();
}
//链表判断
bool empty(){
return m_head==NULL && m_tail == NULL;
}
//在链表头部压入新的节点
void push_front(const T& data){
m_head = new Node(data,NULL,m_head);
if(m_head->m_next)
m_head->m_next->m_prev = m_head;
else{
m_tail = m_head;
}
}
//从链表头部弹出节点
void pop_front(){
if(empty()) {
throw underflow_error("pop_front:链表下溢");
}
Node* pnode = m_head->m_next;
delete m_head;
m_head = pnode;
if(m_head)
m_head->m_prev = NULL;
else
m_tail = NULL;
}
//获取头节点的数据
T& front(){
if(empty()){
throw underflow_error("front:链表下溢") ;
}
return m_head->m_data;
}
const T& front() const{
//复用上面代码
return const_cast<List *>(this)->front();
}
//在链表尾部压入新的节点
void push_back(const T& data){
m_tail = new Node(data,m_tail,NULL);
if(m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
//从链表尾部弹出节点
void pop_back(){
if(empty()){
throw underflow_error("pop_back:链表下溢");
}
Node* pnode = m_tail->m_prev;
delete m_tail;
m_tail = pnode;
if(m_tail)
m_tail->m_next = NULL;
else
m_head = NULL;
}
//从尾部获取节点数据
T& back(){
if(empty()){
throw underflow_error("back:链表下溢");
}
return m_tail->m_data;
}
const T& back() const{
return const_cast<List*>(this)->back();
}
//清空链表
void clear(){
while(!empty()) {
pop_back();
}
}
//重载输出操作符:打印链表中每个节点的数据
friend ostream& operator<<(ostream& os,const List& l){
for(Node* pnode=l.m_head;pnode!=NULL;pnode=pnode->m_next){
os<<pnode->m_data<<' ' ;
}
return os;
}
//获取链表节点个数
size_t size()const{
size_t i = 0;
for(Node* pnode = m_head;pnode!=NULL;pnode=pnode->m_next){
i++;
}
return i;
}
private:
class Node{//类模板的成员类型:表示链表节点
public:
Node(const T& data=T(),Node* prev=NULL,Node* next=NULL):m_data(data),m_prev(prev),m_next(next){}
T m_data; //节点中保存数据
Node* m_prev; //指向前一个节点
Node* m_next; //指向后一个节点
};
private:
Node * m_head; //指向链表的头节点
Node* m_tail;//指向链表的尾节点
};
int main(void){
List<int> ls;
ls.push_back(15);
ls.push_back(16);
ls.push_back(17);
ls.push_back(18);
ls.push_back(19);
ls.push_back(20);
ls.push_front(14);
ls.push_front(13);
ls.push_front(12);
ls.push_front(11);
ls.push_front(10);
cout<<ls<<endl;
ls.pop_front();
ls.pop_back();
cout<<ls<<endl; //10..20
cout<<ls.front()<<endl; //10
cout<<ls.back()<<endl; //20
List<int> ls2 = ls; //拷贝构造
cout<<"ls2:"<<ls2<<endl; //10..20
List<int> ls3;
ls3 = ls; //拷贝赋值
cout<<"ls3:"<<ls3<<endl; //10..20
cout<<"size:"<<ls.size()<<endl;
ls.clear();
cout<<"size:"<<ls.size()<<endl;
return 0;
}
打印结果:
10 11 12 13 14 15 16 17 18 19 20
11 12 13 14 15 16 17 18 19
11
19
ls2:11 12 13 14 15 16 17 18 19
ls3:11 12 13 14 15 16 17 18 19
size:9
size:0
STL与普通模板对比时间 计算20次
#include <iostream>
using namespace std;
int count = 0;
//双向线性链表(列表容器)
template<typename T>class List{
public:
//缺省构造函数
List():m_head(NULL),m_tail(NULL){}
//拷贝构造(深拷贝)
List(const List& that):m_head(NULL),m_tail(NULL){
for(Node* pnode = that.m_head;pnode!=NULL;pnode=pnode->m_next){
push_back(pnode->m_data);
}
}
//that: 1 2 3 4 5 6
//新:1 2 3 4 5
//拷贝赋值(深拷贝)
//list1 = list2==>list1.operator=(list2)
List& operator=(const List& that){
if(&that !=this){
List tmp = that;
swap(m_head,tmp.m_head);
swap(m_tail,tmp.m_tail);
}
return *this;
}
//析构函数
~List(void){
clear();
}
//链表判断
bool empty(){
return m_head==NULL && m_tail == NULL;
}
//在链表头部压入新的节点
void push_front(const T& data){
m_head = new Node(data,NULL,m_head);
if(m_head->m_next)
m_head->m_next->m_prev = m_head;
else{
m_tail = m_head;
}
}
//从链表头部弹出节点
void pop_front(){
if(empty()) {
throw underflow_error("pop_front:链表下溢");
}
Node* pnode = m_head->m_next;
delete m_head;
m_head = pnode;
if(m_head)
m_head->m_prev = NULL;
else
m_tail = NULL;
}
//获取头节点的数据
T& front(){
if(empty()){
throw underflow_error("front:链表下溢") ;
}
return m_head->m_data;
}
const T& front() const{
//复用上面代码
return const_cast<List *>(this)->front();
}
//在链表尾部压入新的节点
void push_back(const T& data){
m_tail = new Node(data,m_tail,NULL);
if(m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
//从链表尾部弹出节点
void pop_back(){
if(empty()){
throw underflow_error("pop_back:链表下溢");
}
Node* pnode = m_tail->m_prev;
delete m_tail;
m_tail = pnode;
if(m_tail)
m_tail->m_next = NULL;
else
m_head = NULL;
}
//从尾部获取节点数据
T& back(){
if(empty()){
throw underflow_error("back:链表下溢");
}
return m_tail->m_data;
}
const T& back() const{
return const_cast<List*>(this)->back();
}
//清空链表
void clear(){
while(!empty()) {
pop_back();
}
}
//重载输出操作符:打印链表中每个节点的数据
friend ostream& operator<<(ostream& os,const List& l){
for(Node* pnode=l.m_head;pnode!=NULL;pnode=pnode->m_next){
os<<pnode->m_data<<' ' ;
}
return os;
}
//获取链表节点个数
size_t size()const{
size_t i = 0;
for(Node* pnode = m_head;pnode!=NULL;pnode=pnode->m_next){
i++;
}
return i;
}
private:
class Node{//类模板的成员类型:表示链表节点
public:
Node(const T& data=T(),Node* prev=NULL,Node* next=NULL):m_data(data),m_prev(prev),m_next(next){}
T m_data; //节点中保存数据
Node* m_prev; //指向前一个节点
Node* m_next; //指向后一个节点
};
private:
Node * m_head; //指向链表的头节点
Node* m_tail;//指向链表的尾节点
public:
T& operator[](size_t i){ //i=5 5,4,3,2,1,0
for(Node* pnode=m_head;pnode!=NULL;pnode=pnode->m_next) {
++count;
if(!i--){
return pnode->m_data;
}
}
throw out_of_range("operator[]:下标越界");
}
const T& operator[](size_t i)const{
return const_cast<List&> (*this)[i];
}
public:
//迭代器:容器中的内部类,用于模拟指针的功能
//迭代器本质:封装常规指针的对象,利用操作符重载,让其表现和指针一样的功能
class Iterator{
public:
Iterator(Node* start=NULL,Node* end=NULL,Node* cur=NULL):m_start(start),m_end(end),m_cur(cur){}
//重载*:获取m_cur节点的数据
T& operator*(void) const{
++count;
return m_cur->m_data;
}
//重载->:获取m_cur节点数据的地址
T* operator->(void)const{
return &m_cur->m_data;
}
//==:比较两个节点是否相同
bool operator==(const Iterator& that)const{
return m_cur == that.m_cur;
}
//!=:比较两个节点是否不同
bool operator!=(const Iterator& that)const{
return !(*this==that) ;
}
//前++:指向下一个节点
Iterator& operator++(void){
if(m_cur)
m_cur = m_cur->m_next;
else
m_cur = m_start;
return *this;
}
//后++:指向下一个节点
const Iterator operator++(int){
Iterator old = *this;
++*this;
return old;
}
//前--:指向上一个节点
Iterator& operator--(void){
if(m_cur)
m_cur = m_cur->m_prev;
else
m_cur = m_end;
return *this;
}
//后--:指向上一个节点
const Iterator operator--(int){
Iterator old = *this;
--*this;
return old;
}
private:
Node* m_start; //指向起始位置
Node* m_end; //指向终止位置
Node* m_cur; //指向当前位置
friend class List; //声明列表容器为友元类
};
public:
//获取起始迭代器:m_cur指向容器第一个节点
Iterator begin(void){
Iterator it(m_head,m_tail,m_head);
return it;
}
//获取终止迭代器:m_cur指向容器中最后一个元素后面的位置
Iterator end(void){
Iterator it(m_head,m_tail,NULL);
return it;
}
};
int main(void){
List<int> ls;
for(int i=1;i<=10;i++){
ls.push_back(i);
}
cout<<ls<<endl; //1 2 .. 10
//修改链表每个元素为平方值
//方法一:使用下标操作(平方级时间复杂度)
/*for(int i=0;i<10;i++){
ls[i] *=ls[i];
}
cout<<ls<<endl; //1. 4 ...100*/
//方法二:使用迭代器
for(List<int>::Iterator it = ls.begin();it!=ls.end();it++){
*it *= *it;
}
cout<<ls<<endl; //1...100
cout<<"count:"<<count<<endl;
return 0;
}
代码2:03list.cpp
#include <iostream>
using namespace std;
//双向线性链表(列表容器)
template<typename T>class List{
public:
//缺省构造函数
List():m_head(NULL),m_tail(NULL){}
//拷贝构造(深拷贝)
List(const List& that):m_head(NULL),m_tail(NULL){
for(Node* pnode = that.m_head;pnode!=NULL;pnode=pnode->m_next){
push_back(pnode->m_data);
}
}
//that: 1 2 3 4 5 6
//新:1 2 3 4 5
//拷贝赋值(深拷贝)
//list1 = list2==>list1.operator=(list2)
List& operator=(const List& that){
if(&that !=this){
List tmp = that;
swap(m_head,tmp.m_head);
swap(m_tail,tmp.m_tail);
}
return *this;
}
//析构函数
~List(void){
clear();
}
//链表判断
bool empty(){
return m_head==NULL && m_tail == NULL;
}
//在链表头部压入新的节点
void push_front(const T& data){
m_head = new Node(data,NULL,m_head);
if(m_head->m_next)
m_head->m_next->m_prev = m_head;
else{
m_tail = m_head;
}
}
//从链表头部弹出节点
void pop_front(){
if(empty()) {
throw underflow_error("pop_front:链表下溢");
}
Node* pnode = m_head->m_next;
delete m_head;
m_head = pnode;
if(m_head)
m_head->m_prev = NULL;
else
m_tail = NULL;
}
//获取头节点的数据
T& front(){
if(empty()){
throw underflow_error("front:链表下溢") ;
}
return m_head->m_data;
}
const T& front() const{
//复用上面代码
return const_cast<List *>(this)->front();
}
//在链表尾部压入新的节点
void push_back(const T& data){
m_tail = new Node(data,m_tail,NULL);
if(m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
//从链表尾部弹出节点
void pop_back(){
if(empty()){
throw underflow_error("pop_back:链表下溢");
}
Node* pnode = m_tail->m_prev;
delete m_tail;
m_tail = pnode;
if(m_tail)
m_tail->m_next = NULL;
else
m_head = NULL;
}
//从尾部获取节点数据
T& back(){
if(empty()){
throw underflow_error("back:链表下溢");
}
return m_tail->m_data;
}
const T& back() const{
return const_cast<List*>(this)->back();
}
//清空链表
void clear(){
while(!empty()) {
pop_back();
}
}
//重载输出操作符:打印链表中每个节点的数据
friend ostream& operator<<(ostream& os,const List& l){
for(Node* pnode=l.m_head;pnode!=NULL;pnode=pnode->m_next){
os<<pnode->m_data<<' ' ;
}
return os;
}
//获取链表节点个数
size_t size()const{
size_t i = 0;
for(Node* pnode = m_head;pnode!=NULL;pnode=pnode->m_next){
i++;
}
return i;
}
private:
class Node{//类模板的成员类型:表示链表节点
public:
Node(const T& data=T(),Node* prev=NULL,Node* next=NULL):m_data(data),m_prev(prev),m_next(next){}
T m_data; //节点中保存数据
Node* m_prev; //指向前一个节点
Node* m_next; //指向后一个节点
};
private:
Node * m_head; //指向链表的头节点
Node* m_tail;//指向链表的尾节点
public:
T& operator[](size_t i){ //i=5 5,4,3,2,1,0
for(Node* pnode=m_head;pnode!=NULL;pnode=pnode->m_next) {
if(!i--){
return pnode->m_data;
}
}
throw out_of_range("operator[]:下标越界");
}
const T& operator[](size_t i)const{
return const_cast<List&> (*this)[i];
}
public:
//迭代器:容器中的内部类,用于模拟指针的功能
//迭代器本质:封装常规指针的对象,利用操作符重载,让其表现和指针一样的功能
class Iterator{
public:
Iterator(Node* start=NULL,Node* end=NULL,Node* cur=NULL):m_start(start),m_end(end),m_cur(cur){}
//重载*:获取m_cur节点的数据
T& operator*(void) const{
return m_cur->m_data;
}
//重载->:获取m_cur节点数据的地址
T* operator->(void)const{
return &m_cur->m_data;
}
//==:比较两个节点是否相同
bool operator==(const Iterator& that)const{
return m_cur == that.m_cur;
}
//!=:比较两个节点是否不同
bool operator!=(const Iterator& that)const{
return !(*this==that) ;
}
//前++:指向下一个节点
Iterator& operator++(void){
if(m_cur)
m_cur = m_cur->m_next;
else
m_cur = m_start;
return *this;
}
//后++:指向下一个节点
const Iterator operator++(int){
Iterator old = *this;
++*this;
return old;
}
//前--:指向上一个节点
Iterator& operator--(void){
if(m_cur)
m_cur = m_cur->m_prev;
else
m_cur = m_end;
return *this;
}
//后--:指向上一个节点
const Iterator operator--(int){
Iterator old = *this;
--*this;
return old;
}
private:
Node* m_start; //指向起始位置
Node* m_end; //指向终止位置
Node* m_cur; //指向当前位置
friend class List; //声明列表容器为友元类
};
public:
//获取起始迭代器:m_cur指向容器第一个节点
Iterator begin(void){
Iterator it(m_head,m_tail,m_head);
return it;
}
//获取终止迭代器:m_cur指向容器中最后一个元素后面的位置
Iterator end(void){
Iterator it(m_head,m_tail,NULL);
return it;
}
public:
//插入数据:在local迭代器前面位置前面插入数据,返回新节点的迭代器
Iterator insert(const Iterator& local,const T& data){
if(local==end()){
push_back(data);
return Iterator(m_head,m_tail,m_tail);
}
Node* pnode = new Node(data,local.m_cur->m_prev,local.m_cur);
if(pnode->m_prev)
pnode->m_prev->m_next = pnode;
else
m_head = pnode;
pnode->m_next->m_prev = pnode;
return Iterator(m_head,m_tail,pnode);
}
//删除:删除迭代器指向的当前节点,返回该节点后面的迭代器
Iterator erase(const Iterator& local){
if(local == end()){
throw invalid_argument("erase:无效参数");
}
if(local.m_cur->m_prev)
local.m_cur->m_prev->m_next = local.m_cur->m_next;
else
m_head = local.m_cur->m_next;
if(local.m_cur->m_next)
local.m_cur->m_next->m_prev = local.m_cur->m_prev;
else
m_tail = local.m_cur->m_prev;
Node* pnext = local.m_cur->m_next;
delete local.m_cur;
return Iterator(m_head,m_tail,pnext);
}
};
int main(void){
List<int> ls;
for(int i=1;i<=10;i++){
ls.insert(ls.end(),i);
}
cout<<ls<<endl;
ls.erase(ls.begin());
cout<<ls<<endl;
ls.erase(--ls.end());
cout<<ls<<endl;
List<char>lc;
lc.insert(lc.end(),'A');
lc.insert(lc.end(),'B');
lc.insert(lc.end(),'C');
cout<<lc<<endl; //A B C
List<char>::Iterator it = lc.begin();
it = lc.insert(++++++it,'F');
it = lc.insert(it,'E');
it = lc.insert(it,'D'); //A B C D E F
cout<<lc<<endl; //A B C D E F
it = lc.erase(lc.begin());
it = lc.erase(it);
it = lc.erase(it);
cout<<lc<<endl; //D E F
return 0;
}
案例练习
练习:写一个教师类,包含姓名(m_name),年龄(m_age),工资(m_salary),支持输出操作符重载(<<),比较操作符(<,默认按年龄比较)。
(1) 创建若干个教师对象,保存链表容器中
(2)测试排序,默认按年龄比较
(3)使用自定义比较器(函数,仿函数),自定义按工资比较
参考代码:
#include <iostream>
using namespace std;
//双向线性链表(列表容器)
template<typename T>class List{
public:
//缺省构造函数
List():m_head(NULL),m_tail(NULL){}
//拷贝构造(深拷贝)
List(const List& that):m_head(NULL),m_tail(NULL){
for(Node* pnode = that.m_head;pnode!=NULL;pnode=pnode->m_next){
push_back(pnode->m_data);
}
}
//拷贝赋值(深拷贝)
//list1 = list2==>list1.operator=(list2)
List& operator=(const List& that){
if(&that !=this){
List tmp = that;
swap(m_head,tmp.m_head);
swap(m_tail,tmp.m_tail);
}
return *this;
}
//析构函数
~List(void){
clear();
}
//链表判断
bool empty(){
return m_head==NULL && m_tail == NULL;
}
//在链表头部压入新的节点
void push_front(const T& data){
m_head = new Node(data,NULL,m_head);
if(m_head->m_next)
m_head->m_next->m_prev = m_head;
else{
m_tail = m_head;
}
}
//从链表头部弹出节点
void pop_front(){
if(empty()) {
throw underflow_error("pop_front:链表下溢");
}
Node* pnode = m_head->m_next;
delete m_head;
m_head = pnode;
if(m_head)
m_head->m_prev = NULL;
else
m_tail = NULL;
}
//获取头节点的数据
T& front(){
if(empty()){
throw underflow_error("front:链表下溢") ;
}
return m_head->m_data;
}
const T& front() const{
//复用上面代码
return const_cast<List *>(this)->front();
}
//在链表尾部压入新的节点
void push_back(const T& data){
m_tail = new Node(data,m_tail,NULL);
if(m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
//从链表尾部弹出节点
void pop_back(){
if(empty()){
throw underflow_error("pop_back:链表下溢");
}
Node* pnode = m_tail->m_prev;
delete m_tail;
m_tail = pnode;
if(m_tail)
m_tail->m_next = NULL;
else
m_head = NULL;
}
//从尾部获取节点数据
T& back(){
if(empty()){
throw underflow_error("back:链表下溢");
}
return m_tail->m_data;
}
const T& back() const{
return const_cast<List*>(this)->back();
}
//清空链表
void clear(){
while(!empty()) {
pop_back();
}
}
//重载输出操作符:打印链表中每个节点的数据
friend ostream& operator<<(ostream& os,const List& l){
for(Node* pnode=l.m_head;pnode!=NULL;pnode=pnode->m_next){
os<<pnode->m_data<<' ' ;
}
return os;
}
//获取链表节点个数
size_t size()const{
size_t i = 0;
for(Node* pnode = m_head;pnode!=NULL;pnode=pnode->m_next){
i++;
}
return i;
}
private:
class Node{//类模板的成员类型:表示链表节点
public:
Node(const T& data=T(),Node* prev=NULL,Node* next=NULL):m_data(data),m_prev(prev),m_next(next){}
T m_data; //节点中保存数据
Node* m_prev; //指向前一个节点
Node* m_next; //指向后一个节点
};
private:
Node * m_head; //指向链表的头节点
Node* m_tail;//指向链表的尾节点
public:
T& operator[](size_t i){ //i=5 5,4,3,2,1,0
for(Node* pnode=m_head;pnode!=NULL;pnode=pnode->m_next) {
if(!i--){
return pnode->m_data;
}
}
throw out_of_range("operator[]:下标越界");
}
const T& operator[](size_t i)const{
return const_cast<List&> (*this)[i];
}
public:
//迭代器:容器中的内部类,用于模拟指针的功能
//迭代器本质:封装常规指针的对象,利用操作符重载,让其表现和指针一样的功能
class Iterator{
public:
Iterator(Node* start=NULL,Node* end=NULL,Node* cur=NULL):m_start(start),m_end(end),m_cur(cur){}
//重载*:获取m_cur节点的数据
T& operator*(void) const{
return m_cur->m_data;
}
//重载->:获取m_cur节点数据的地址
T* operator->(void)const{
return &m_cur->m_data;
}
//==:比较两个节点是否相同
bool operator==(const Iterator& that)const{
return m_cur == that.m_cur;
}
//!=:比较两个节点是否不同
bool operator!=(const Iterator& that)const{
return !(*this==that) ;
}
//前++:指向下一个节点
Iterator& operator++(void){
if(m_cur)
m_cur = m_cur->m_next;
else
m_cur = m_start;
return *this;
}
//后++:指向下一个节点
const Iterator operator++(int){
Iterator old = *this;
++*this;
return old;
}
//前--:指向上一个节点
Iterator& operator--(void){
if(m_cur)
m_cur = m_cur->m_prev;
else
m_cur = m_end;
return *this;
}
//后--:指向上一个节点
const Iterator operator--(int){
Iterator old = *this;
--*this;
return old;
}
private:
Node* m_start; //指向起始位置
Node* m_end; //指向终止位置
Node* m_cur; //指向当前位置
friend class List; //声明列表容器为友元类
};
public:
//获取起始迭代器:m_cur指向容器第一个节点
Iterator begin(void){
Iterator it(m_head,m_tail,m_head);
return it;
}
//获取终止迭代器:m_cur指向容器中最后一个元素后面的位置
Iterator end(void){
Iterator it(m_head,m_tail,NULL);
return it;
}
public:
//插入数据:在local迭代器前面位置前面插入数据,返回新节点的迭代器
Iterator insert(const Iterator& local,const T& data){
if(local==end()){
push_back(data);
return Iterator(m_head,m_tail,m_tail);
}
Node* pnode = new Node(data,local.m_cur->m_prev,local.m_cur);
if(pnode->m_prev)
pnode->m_prev->m_next = pnode;
else
m_head = pnode;
pnode->m_next->m_prev = pnode;
return Iterator(m_head,m_tail,pnode);
}
//删除:删除迭代器指向的当前节点,返回该节点后面的迭代器
Iterator erase(const Iterator& local){
if(local == end()){
throw invalid_argument("erase:无效参数");
}
if(local.m_cur->m_prev)
local.m_cur->m_prev->m_next = local.m_cur->m_next;
else
m_head = local.m_cur->m_next;
if(local.m_cur->m_next)
local.m_cur->m_next->m_prev = local.m_cur->m_prev;
else
m_tail = local.m_cur->m_prev;
Node* pnext = local.m_cur->m_next;
delete local.m_cur;
return Iterator(m_head,m_tail,pnext);
}
};
//线性查找(全局的泛型算法函数)
template<typename IT,typename TYPE>
IT find(IT begin,IT end,TYPE data){
for(IT it=begin;it!=end;it++){
if(*it == data) {
return it;
}
}
return endl;
}
List<int> ls2;
//排序(全局的泛型算法函数) ,通过"<" 比较
template<typename IT>
void sort(IT begin,IT end){
for(IT i = begin;i!=end;i++){
for(IT j = begin;j!=i;j++) {
if(*i<*j) {
swap(*i,*j) ;
}
}
cout<<ls2<<endl;
}
}
//重载排序函数,通过“比较器”实现比较
template<typename IT,typename CMP>void sort(IT begin,IT end,CMP cmp){
for(IT i = begin;i!=end;i++){
for(IT j = begin;j!=i;j++) {
if(*i<*j) {
swap(*i,*j) ;
}
}
// cout<<ls2<<endl;
}
}
//比较器(用户自行定义,可以指定比较规则)
//实现方式一:函数
bool cmpFunc(int i,int j){
return i<j;
}
//实现方式二:仿函数(重载函数调用操作符"()")
class cmpClass{
public:
bool operator()(int i,int j){
return i>j;
}
};
class Teacher{
public:
Teacher(const string& name,int age,int salary):m_name(name),m_age(age),m_salary(salary){}
friend ostream& operator<<(ostream& os,const Teacher& t){
os<<"(" <<t.m_name<<","<<t.m_age<<","<<t.m_salary<<")"<<endl;
return os;
}
bool operator<(const Teacher& t) const{
return m_age<t.m_age;
}
string m_name;
int m_age;
int m_salary;
};
bool cmpTeacherFunc(const Teacher& t1,const Teacher& t2){
return t1.m_salary<t2.m_salary;
}
class cmpTeacherClass{
public:
bool operator()(const Teacher& t2,const Teacher& t2){//比较器类(仿函数)
return t1.m_salary<<t2.m_salary;
}
};
int main(void){
List<Teacher> lt;
lt.push_back(Teacher("张老师",25,20000));
lt.push_back(Teacher("杨老师",26,20000));
lt.push_back(Teacher("王老师",27,20000));
lt.push_back(Teacher("李老师",28,20000));
lt.push_back(Teacher("赵老师",29,20000));
lt.push_back(Teacher("闵老师",30,20000));
cout<<"排序前:"<<"\n"<<lt<<endl;
sort(lt.begin(),lt.end()); //默认使用<,按年龄排序
cout<<"按年龄排序排序后:"<<"\n"<<lt<<endl;
sort(lt.begin(),lt.end(),cmpTeacherFunc); //默认使用<,按年龄排序
sort(lt.begin(),lt.end(),cmpTeacherClass()); //默认使用<,按年龄排序
cout<<"按工资排序后:"<<"\n"<<lt<<endl;
return 0;
}
标准模板库(STL)
迭代器
向量
向量的使用
参考代码:
#include <iostream>
#include <vector>
using namespace std;
//打印参数向量中每个元素
void print(vector<int>& vec){
int size = vec.size();
cout<<"向量大小(元素个数):" <<size<<endl;
for(int i=0;i<vec.size();i++){
cout<<vec[i] <<' ' ;
}
cout<<endl;
}
int main(void){
vector<int> v1; //空向量
print(v1);
vector<int> v2(5); //预分配5个元素空间
print(v2);
vector<int>v3(5,8); //预分配5个元素空间,并使用8进行初始化
print(v3);
int arr[] = {10,20,30,40,50};
vector<int> v4(arr,arr+5); //范围初始化
print(v4);
vector<int> v5 = v4;//拷贝构造
print(v5);
v1 = v5; //拷贝赋值
print(v1);
for(int i=0;i<v1.size();i++){
++v1[i] ; //随机访问
}
print(v1);
//获取收尾元素
cout<<"首元素:"<<v1.front()<<endl;
cout<<"尾元素:"<<v1.back()<<endl;
//在尾部压入或弹出数据
v1.push_back(61);
print(v1);
v1.pop_back();
print(v1);
//插入和删除(效率低)
v1.insert(v1.begin(),10);
print(v1);
v1.erase(v1.end()-1);
print(v1);
return 0;
}
向量的迭代器
参考代码:
#include <iostream>
#include <vector>
using namespace std;
//使用(正向)迭代器打印向量的每个元素
void print(const vector<int>& vec){
for(vector<int>::const_iterator it = vec.begin();it!=vec.end();it++){
cout<<*it<<' ';
}
cout<<endl;
}
//使用(反向)迭代器打印向量的每个元素
void rprint(const vector<int>& vec){
for(vector<int>::const_reverse_iterator it = vec.rbegin();it!=vec.rend();it++){
cout<<*it<<' ';
}
cout<<endl;
}
int main(void){
vector<int>v1(5);
print(v1);
//使用下标访问
for(int i=0;i<v1.size();i++){
v1[i] = (i+1)*10;
}
print(v1);
rprint(v1);
return 0;
}
迭代器的使用
参考代码:
#include <iostream>
#include <vector>
using namespace std;
//使用(正向)迭代器打印向量的每个元素
void print(const vector<int>& vec){
for(vector<int>::const_iterator it = vec.begin();it!=vec.end();it++){
cout<<*it<<' ';
}
cout<<endl;
}
//使用(反向)迭代器打印向量的每个元素
void rprint(const vector<int>& vec){
for(vector<int>::const_reverse_iterator it = vec.rbegin();it!=vec.rend();it++){
cout<<*it<<' ';
}
cout<<endl;
}
int main(void){
vector<int>v1(5);
print(v1);
//使用下标访问
for(int i=0;i<v1.size();i++){
v1[i] = (i+1)*10;
}
print(v1);
rprint(v1);
//顺序迭代
vector<int>::iterator it = v1.begin();
for(it;it!=v1.end();it++){
*it +=10;
}
print(v1); //20...60
//随机迭代
it = v1.begin();
for(int i =0; i<v1.size();i++){
*(it+i) += 10;
}
print(v1); //30...70
return 0;
}
参考代码:
#include <iostream>
#include <vector>
using namespace std;
int main(void){
vector<int> v1;
v1.push_back(100);
vector<int>::iterator it = v1.begin();
cout<<*it<<endl; //100
v1.push_back(200);
it = v1.begin();
cout<<*it<<endl; //100
return 0;
}
向量的查找
删除匹配:从容器中删除和key匹配的所有元素
template<typename T>
void remove(vector<T>& vec,const T& key){
for(typename vector<T>::iterator it = vec.begin(); (it = find(it,vec.end(),key)) != vec.end(); it = vec.erase(it));
}
向量的排序
参考代码:
#include <iostream>
#include <vector>
#include <algorithm> //全局泛型算法函数
using namespace std;
void print(const vector<int>& vec){
vector<int>::const_iterator it = vec.begin();
for(it;it!=vec.end();it++){
cout<<*it<<' ' ;
}
cout<<endl;
}
//比较器(函数)
bool cmpFunc(int a,int b){
return a>b;
}
//比较器(仿函数)
class cmpClass{
public:
bool operator()(int a,int b){
return a>b ;
}
};
int main(void){
int arr[] = {1,3,2,0,5,4};
vector<int> v1(arr,arr+5);
print(v1);
//查找0并删除
vector<int>::iterator it = find(v1.begin(),v1.end(),0);
if(it != v1.end()){
v1.erase(it) ;
}
print(v1);
//排序
sort(v1.begin(),v1.end());
print(v1);
//降序排序
//方法一:
// sort(v1.begin(),v1.end(),cmpFunc);
// 方法二:
//sort(v1.begin(),v1.end(),cmpClass()); //cmpClass cmp; cmp(a,b) ==>cmp.operator()(a,b);
// 方法三:
sort(v1.rbegin(),v1.rend());
print(v1);
return 0;
}
capacity() 和reserve() //获取或设置容器的容量
size() 和 resize() //获取或设置容器的大小(实际元素个数)
双端队列
参考代码:05deque.cpp
#include <iostream>
#include <deque>
#include <vector>
using namespace std;
int main(void){
deque<int> v(5);
cout<<"size="<<v.size()<<endl;
//cout<<"capacity="<<v.capacity()<<endl;
//v.reserve(10);
cout<<"size="<<v.size()<<endl;
//cout<<"capacity="<<v.capacity()<<endl;
deque<int> d(5);
cout<<d.front()<<endl;//0
d.push_front(10);
cout<<d.front()<<endl; //10
cout<<d.back()<<endl; //0
d.push_back(10);
cout<<d.back()<<endl; //10
d.pop_front();
d.pop_back();
cout<<d.front()<<endl; //0
cout<<d.back()<<endl; //0
return 0;
}
列表
链表
堆栈
队列
优先队列
参考代码:07spq.cpp
#include <iostream>
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <list>
using namespace std;
//优先队列使用比较器
class cmpClass{
public:
bool operator()(int a,int b){
return !(a<b) ;
}
};
int main(void){
//堆栈
//stack<string> ss; //默认使用deque 我们 喜欢 编程
//stack<string,vector<string> > ss; //使用vector 我们 喜欢 编程
stack<string,list<string> > ss; //使用list 我们 喜欢 编程
ss.push("编程");
ss.push("喜欢");
ss.push("我们");
while(!ss.empty()){
cout<<ss.top()<<' '; //top:获取栈顶数据
ss.pop(); //pop:弹出栈顶数据
}
cout<<endl;
//队列
queue<string> qs; //默认使用deque
//queue<string,list<string> > qs; //默认使用deque ,可以选择选择list
qs.push("我们");
qs.push("喜欢");
qs.push("编程");
while(!qs.empty()){
cout<<qs.front()<<' ' ; //front:获取队列首部数据
qs.pop(); //pop: 弹出队列首部数据
}
cout<<endl;
//优先队列
//priority_queue<int> pi; //默认使用deque,可以选择vector
//priority_queue<int,vector<int> > pi; //默认使用deque,可以选择vector
//priority_queue<int,list<int> > pi; //error
priority_queue<int,vector<int>,cmpClass > pi; //自定义比较器
pi.push(10);
pi.push(40);
pi.push(20);
pi.push(30);
pi.push(50);
while(!pi.empty()){
cout<<pi.top()<<' '; //获取队列最优(大)数据
pi.pop();
}
cout<<endl;
return 0;
}
总结:适配器容器
(1)堆栈(stack):后进先出
语法:stack<元素类型,底层容器类型>
可以适配的底层容器:vector/[deque] /list
(2)队列(queue):先进先出
语法:queue<元素类型,底层容器类型>
可以适配的底层容器 :[deque]/list
(3)优先队列(priority_queue):优者先出(默认大则优)
priority_queue<元素类型,底层容器类型>
priority_queue<元素类型,底层容器类型,比较器类>
可以适配的底层容器:vector / [deque]
映射
参考代码:08map.cpp
#include <iostream>
#include <map>
using namespace std;
class Candidate{
public:
Candidate(const string& name="",size_t votes=0):m_name(name),m_votes(votes){}
const string& name(void) const{ //获取候选者姓名
return m_name;
}
size_t votes(void) const{ //获取候选者票数信息
return m_votes;
}
void vote(void){
++m_votes;
}
private:
string m_name; //候选者姓名
size_t m_votes; //候选者获得的票数
};
int main(void){
//创建映射,key->char value->Candidate
map<char,Candidate> mcc;
//使用insert向映射添加新数据
mcc.insert(pair<char,Candidate>('A',Candidate("游成为")));
mcc.insert(make_pair('B',Candidate("闵卫"))); //make_pair: 快速创建一个pair对象
//使用[] 向映射添加新数据
mcc['C'] = Candidate("张淑敏");
mcc['D'] = Candidate("蒋贵良");
mcc['E'] = Candidate("马志国");
typedef map<char,Candidate>::iterator IT;
for(size_t i=0;i<10;i++){
for(IT it= mcc.begin();it!=mcc.end();it++) {
//节点数据pair<char,Candidate>
//first->key(char) second->value(Candidate)
cout<<'['<<it->first<<']' <<it->second.name()<<' ';
}
cout<<endl<<"请投票:"<<flush;
char key;
cin >>key;
IT it = mcc.find(key);
if(it == mcc.end()){
cout<<"废票"<<endl;
continue;
}
it->second.vote();
}
//唱票
IT win = mcc.begin();
for(IT it = mcc.begin();it!=mcc.end();it++){
cout<<it->second.name()<<"获取了" <<it->second.votes()<<"票"<<endl;
if(it->second.votes()>win->second.votes()){
win =it;
}
}
cout<<"热烈祝贺"<<win->second.name()<<"被选为优秀老师!"<<endl;
return 0;
}
多重映射
参考代码:09set.cpp
#include <iostream>
#include <set>
using namespace std;
int main(void){
set<string>si; //key->string(唯一,只读)
si.insert("hello");
si.insert("world");
si.insert("ok");
si.insert("blue");
si.insert("ok");
si.insert("mall");
si.insert("shop");
si.insert("convenience");
cout<<"单词个数:"<<si.size()<<endl;
typedef set<string>::iterator IT;
for(IT it = si.begin();it!=si.end();it++){
cout<<*it<<' ';
}
cout<<endl;
return 0;
}
集合与多重集合
参考代码:10set.cpp
#include <iostream>
#include <set>
using namespace std;
int main(void){
multiset<string>si; //key->string(唯一,只读)
si.insert("hello");
si.insert("world");
si.insert("ok");
si.insert("blue");
si.insert("ok");
si.insert("mall");
si.insert("shop");
si.insert("convenience");
cout<<"单词个数:"<<si.size()<<endl;
typedef multiset<string>::iterator IT;
for(IT it = si.begin();it!=si.end();it++){
cout<<*it<<' ';
}
cout<<endl;
//统计单词"hello"出现频率
IT itlow = si.lower_bound("hello");
IT itup = si.upper_bound("hello");
int count = 0 ;
for(IT it = itlow;it!=itup;it++){
++count;
}
cout<<"出现hello次数"<<count<<endl;
return 0;
}