C/C++程序员:模版和容器的基本应用

模板
一、类型参数
支持更多类型冒泡排序函数。
二、类模板、函数模板与模板特化
1.模板的两步实例化
类模板------>具体类------>对象
      编译期       运行期
函数模板------>具体函数------>调用
        编译期         运行期
2.模板特化就是针对某种特定的类型,是通用模板获得相应的特殊的定义。
三、模板及模板特化语法
1.类模板
template<class 类型形参1, class 类型形参2, ...> class 类模板名 {...};
如:
template<class T1, class T2, class T3> class Dumy {
  T1 foo (T2 t2) {
    T3 t3;
    ...
  }
};
在类声明外部定义成员函数:
template<class T1, class T2, class T3>
T1 Dumy<T1, T2, T3>::foo (T2 t2) {
  T3 t3;
  ...
}
2.类模板特化
template<> class 类模板名<类型实参1, 类型实参2, ...> {...};
如:
template<> class Dumy<char,short,int> {
   char foo (short t2) {
     int t3;
     ...
   }
};
在类声明外部定义成员函数:
char Dumy<char,short,int>::foo(short t2) {
   int t3;
   ...
}
3.类成员函数特化
template<>
返回类型 类模板名<类型实参1,类型实参2,...>::成员函数名 (形参表) {...}
如:
template<>
char Dumy<char,short,int>::foo(short t2) {
   int t3;
   ...
}
4.函数模板
template<class 类型形参1, class 类型形参2, ...>
返回类型 函数模板名 (形参表) {...}
如:
template<class T1, class T2, class T3>
T1 foo (T2 t2) {
   T3 t3;
   ...
}
5.函数模板特化
template<>
返回类型 函数模板名<类型实参1, 类型实参2, ...> (形参表) {...}
如:
template<>
char foo<char,short,int> (short t2) {
   int t3;
   ...

四、模板的局部特化与最优匹配
1.编译器优先选择特化程度最高的版本。
A)template<class T1, class T2>
class Pair {...};
B)template<class T1>
class Pair<T1,int> {...};
C)template<>
class Pair<int,int> {...};
-----------------------------
Pair<double, double> p1; // A
Pair<double, int> p2;    // B
Pair<int, int> p3;       // C
2.编译器优先选择针对指针的特化版本。
A)template<class T> class Feeb {...};
B)template<class T*> class Feeb {...};
-----------------------------
Feeb<char> f1;  // A,T=char
Feeb<char*> f2; // B,T=char
3.编译器优先选择参数匹配程度最高的特化版本。
A)template<class T1,class T2,class T3>
class Trio {...};
B)template<class T1,class T2>
class Trio<T1,T2,T2> {...};
C)template<class T1>
class Trio<T1,T1*,T1*> {...};
-----------------------------
Trio<int,short,char*>  t1; // A
Trio<int,short,short>  t2; // B
Trio<char,char*,char*> t3; // C
五、模板的非类型参数与缺省参数
1.一个模板类或者模板函数除了可以接受类型参数以外,还可以接受非类型参数,但是对应的实参必须是常量表达式。
2.模板类或者模板函数也可以带有缺省参数,但是如果一个模板参数有缺省值,该参数后边的所有参数必须都有缺省值。
六、容器与迭代器
指针:*/->/++/--/==/!=
int a[100];
int* p = a;

STL(上)
一、STL容器概述
1.数组与链表的优缺点
1)数组:随机访问高效,空间要求高,插入删除不便。
2)链表:空间要求低,插入删除方便,随机访问困难。
2.C++的STL提供了一套容器模板,使得对数据结构的底层操作对程序设计者透明化,同时结合了数组和链表各自优点,以尽可能简单的方式获得尽量高效的使用效果。
3.十大容器
1)向量(vector)
支持对数据元素的下标访问,在容器的尾部进行插入和删除效率很高。
2)列表(list)
高效地在任意位置做插入和删除,不支持对数据元素的下标访问。
3)双端队列(deque)
支持对数据元素的下标访问,在容器的头部和尾部进行插入和删除效率很高。
4)堆栈(stack)
只支持在容器的一端存储和提取数据元素。
5)队列(queue)
支持从后端压入从前端提取数据元素。
6)优先队列(priority_queue)
提取的永远是当前容器中优先级最高的数据元素。
7)映射(map)
以key的升序存储key-value对的序列。每个key只能出现一次。根据key提取value效率非常高。
8)集合(set)
映射的低级形式,每个数据元素只有key没有value。
9)多重映射(multimap)
key不唯一的映射。
10)多重集合(multiset)
key不唯一的集合。
4.容器的分类
1)线性容器:向量、列表、双端队列。
2)适配器容器:堆栈、队列、优先队列。
3)关联容器:映射、集合、多重映射、多重集合。
5.容器的共同特征
1)所有的容器类型支持拷贝构造和拷贝赋值,这样一个容器类型的对象可以作为一个整体被复制给另一个相同类型的容器对象,前提是容器中元素类型也要支持拷贝构造和拷贝赋值。
2)所有的容器类型支持“==”运算符。两个容器类型对象相等的条件:容器类型相同、容器中数据元素的类型相同,元素个数相同,对应元素之间满足“==”运算符的判断。
3)所有的容器类型支持“<”运算符。两个相同类型容器进行“<”比较,其中一个容器中的每一个数据元素都要“<”另一个容器中对应位置的元素。
4)容器所存放的对象都是对象的副本,因此可能存放在容器中的元素类型一般都要支持缺省构造、拷贝构造和拷贝赋值运算符。
二、向量(vector)
1.基本特点
1)内存连续与下标访问。
2)动态内存管理。
3)通过内存预分配减小动态内存管理的额外开销。
4)支持插入和删除(虽然效率不高)。
2.定义变量
#include <vector>
vector<int> vn;
vector<string> vs;
vector<vector<int> > vvn;
3.随机访问
vn.push_back (10);
vn.push_back (20);
cout << vn[0] << endl; // 10
cout << vn[1] << endl; // 20
for (int i = 0; i < vn.size (); i++)
  cout << vn[i] << endl;
4.迭代访问
vector<int>::iterator it = vn.begin ();
cout << *it << endl; // 10
it++;
cout << *it << endl; // 20
for (vector<int>::iterator it = vn.begin (); it != vn.end (); it++)
  cout << *it << endl;
5.预分配与初始化
vector<int> vn (200);
vector<int> vn (200, 2);
class Student {...};
vector<Student> vs (200);
vector<Student> vs (200,
Student ("张飞", 28));
6.front()/back()成员函数分别返回向量容器中第一个和最后一个数据元素。
7.size()/resize()/clear()/capacity()/reserve()
size() - 返回向量的大小,即数据元素的个数。
resize() - 改变向量的大小,可能引发类类型数据元素的析构或构造。
clear() - resize(0),清空向量中所有的数据元素。
capacity() - 返回向量的容量,即最多可容纳数据元素的个数。
reserve() - 人为地多预留一些内存空间。只能增长不能减少内存。多分配的内存不做初始化,不会调用类类型数据元素的构造函数。
1)向量的大小可以增加也可以减少,引起向量大小变化的成员函数除了resize()以外还有push_back()/pop_back(),以及insert()/erase()。
2)向量的容量只能增加不能减少,只能通过reserve()成员函数人为地改变向量的容量。
3)向量的大小的增加可能会导致容量的增加,但是容量的变化并不会引起大小的变化。
4)通过resize()增加向量的大小,新增部分会被初始化,但是通过reserve()增加向量的容量,新增内存并不做初始化。
5)位于向量容量范围内但是却不在其大小范围内元素,可以通过下标或者迭代器访问,但是其值往往是不确定的。
6)无论是resize()还是reserve(),他们所引起的向量的大小或容量的改变,都发生在容器的尾部。
8.insert()/erase()
这两个函数都是以迭代器作为参数,表示插入和删除的位置。
9.find()/sort():全局函数
10.通过迭代器构造向量容器

  STL(下)
一、双端队列(deque)
1.双端队列具有向量所有的功能。
2.在双端队列的头部进行插入和删除与在其尾部做这些操作具有一样高的效率。
3.和向量相比,双端队列的内存开销稍大,对数据元素进行下标访问的效率也要略低一些。
4.在接口方面双端队列相对于向量增加了push_front()和pop_front()成员函数,用于在其头部插入和删除元素,同时保证效率。
二、列表(list)
1.列表时按照链表的形式进行存储的。
2.在列表的任何位置进行插入和删除效率都很高。
3.不能以下标的方式对列表中的数据元素进行随机访问。其迭代器也不支持对整型的加减运算。
4.特有的成员函数:
1)remove:删除所有匹配的节点。
2)sort:排序。
3)unique:使连续出现相同数据元素唯一化。
1 3 4 5 5 5 9 8 7 7 7 7 5 5 9
1 3 4   5   9 8     7   5   9
4)splice:拆分。
5)merge:合并。
三、堆栈(stack)
1.堆栈可以作为任何支持push_back()/pop_back()/back()/empty()/size()操作的底层容器的包装类。换言之,只要是提供了上述公有成员函数的任何类型,都可以被堆栈适配。
堆栈接口-调用->底层容器接口
push()         push_back()
pop()          pop_back()
top()          back()
size()         size()
empty()        empty()
2.定义堆栈容器对象时不仅需要明确数据元素的类型,还需要指明底层容器的类型,如果没有指明底层容器,缺省使用双端队列(deque)作为底层容器。
如:
stack<string, vector<string> > ss;
stack<string> ss; // 等价于stack<string, deque<string> > ss;
三种基本线性容器(向量、双端队列和列表)都可用于适配堆栈容器。
四、队列(queue)
队列接口-调用->底层容器接口
push()         push_back()
pop()          pop_front()
back()         back()
front()        front()
size()         size()
empty()        empty()
缺省底层容器是deque。
五、优先队列(priority_queue)
1.对于基本类型的数据元素,缺省方式以大者优先。对于类类型的数据元素,缺省方式根据该类型的“<”运算符判断优先级。
2.无论是基本类型还是类类型的数据元素,总可以通过该模板的第三个类型实参,指定一个比较器函数对象,通过该对象的operator()运算符函数指定优先级的判断规则。
六、映射(map)
pair<int, string> p (10, "hello");
cout << p.first << endl; // 10
cout << p.second << endl; // hello
make_pair (10, "hello");

通过map的insert成员函数,映射容器中添加pair对象,该pair对象包含有key-value对。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值