C++模板和STL

37 篇文章 3 订阅
30 篇文章 2 订阅
本文深入探讨了C++中的模板,包括函数模板、类模板、模板特化、模板参数缺省值等概念,并详细阐述了STL的使用,如迭代器、向量、双端队列、堆栈、队列、优先队列以及映射和集合等容器的实现与应用。
摘要由CSDN通过智能技术生成

在这里插入图片描述

模板

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

函数模板的定义

在这里插入图片描述
在这里插入图片描述

#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;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值