STL与泛型编程入门

STL与泛型编程入门

STL的概念与组成
Iterator(迭代器)  Container(容器) Algorithm(算法) Adaptors(配接器)

抽象的重要性

计算机科学的重要进步,许多是由于发掘了新的抽象性质而促成的

面向过程->基于对象->面向对象->泛型



面向过程(Procedure-Oriented)的抽象

抽象出Procedure(Function)的概念,把程序分成若干个子过程。将事物的 方法隐藏于各个函数内--C语言。

适用于处理小型的程序。对大型程序,   子程序之间关系复杂,不易处理 变化的需求--引发软件危机的原因--需要新的抽象。


示例:


#include <stdio.h>

void fun()
{
// fun() 隐藏了一系列方法
            .
            .
            .
            .
            .
}

int main()
{
      fun();
      
      return 0;
}



基于对象(Object-Based)的抽象

引入抽象数据类型(ADT,Abstract DataType)。C++的类,将事物的 属性方法紧密地结合在一起--VB、带类的C。

与面向过程相比,可以更好地处理变化,一定程度上化解了软件危机。但各个类之间的关系不容易处理,而且程序 代码数量比面向过程时更大--需要新的抽象。


示例:


#include<iostream>

using namespace std;


class A<span style="white-space:pre">				</span>//方法与属性的紧密结合
{
	int x;
public :
	A(int x=0):x(x){}

	void pxy()
	{
	cout<<x<<endl;
      }
};

int main()
{
	A *p =new A(2) ;

	p->pxy();

	delete p;

	return 0;
}



面向对象(Object-Oriented)的抽象

抽象出 封装、继承、多态( polymorphic)的概念。

与基于对象相比,有更多的间接性。运用多态,我们可以 调用某种方法,而不用指定此方法所属的类型。因而达到更进一步的抽象性。



示例:


#include <iostream>
#include <cmath>

using namespace  std;



#define  pai acos(-1);

class Shape{
public:
	Shape(){}
	~Shape(){}
	virtual float GetArea(){return -1;}
};

class retc :virtual public Shape
{
	int w,h;
public:
	retc(int w,int h):w(w),h(h){ cout<<"Creatre rect\n";	}
	~retc(){cout<<"Delete rect\n";}
	float GetArea(){return w*h;}

};

class Circ :virtual public Shape
{
	int R;
public:
	Circ(int r): R(r){ cout<<"Creatre Circle\n";	}
	~Circ(){cout<<"Delete Circle\n";}
	float GetArea();

};

float Circ::GetArea()
{
	float ans=3.1415926*R*R;
	return ans;
}

class Square : public retc
{
public:
	Square(int w):retc(w,w)
	{
	 cout<<"Creatre Square\n";
	}
	~Square()
	{
	cout<<"Delete Square\n";
	}

};


int main()
{

	Shape *ptr;
	Circ circ(2);
	retc ret(3,4);
	Square square(3);
<span style="white-space:pre">	</span>ptr = &circ;                        //对用户封装了具体的类型,用户只需和抽象类打交道
<span style="white-space:pre">	</span>cout<<endl<<ptr->GetArea()<<endl;
<span style="white-space:pre">	</span>ptr = &ret;
<span style="white-space:pre">	</span>cout<<endl<<ptr->GetArea()<<endl;
<span style="white-space:pre">	</span>ptr = &square;
<span style="white-space:pre">	</span>cout<<endl<<ptr->GetArea()<<endl;
	
	return   0;

}


STL 的概念:

­何为STL?
STL(StandardTemplate Library)是C++标准庫的一部分(80%),是用C++Template机制来表达泛型的庫。
STL(StandardTemplate Library)是用泛型技术来设计完成的实例


vector <int> a;   //定义一个动态数组
deque <int> b;    //定义一个双端队列
      .
      .
      .
sort(a.begin(),a.end());      //用一个泛型算法可以处理多种数据结构。
                             //而且在获得弹性的同时运行效率上和以前相比没有损失。
sort(b.begin(),b.end());


STL

­六大组件
容器(Container)
算法(Algorithm)
迭代器(Iterator)
仿函数(Function object)
适配器(Adaptor)
空间配制器(allocator)



#include<iostream>
#include<algorithm>
#include<list>
#include<functional>

using namespace std;

typedef int elemtype;

template <typename T>
void printelem (T elem)
{
      cout<<elem<<"  ;";
}

void (*pe)(elemtype) = printelem;    //函数指针

int main()
{
      int a[5]={1,2,3,4,5};
      list<elemtype> li(a,a+5);     //用a数组做list容器的初始值
      for_each(li.begin(),li.end(),pe);   //对区间内每个元素调用传入的操作pe
      cout<<endl;

      li.push_back(6);
      li.push_back(7);
      li.push_back(0);
      li.push_back(9);
      for_each(li.begin(),li.end(),pe);
      cout<<endl;

      li.remove_if(bind2nd(modulus<elemtype>(),2));    //除去所有奇数
      for_each(li.begin(),li.end(),pe);
      cout<<endl;

	return   0;

}





template //函数模板

本文介绍函数模板的概念、用途以及如何创建函数模板和函数模板的使用方法......
在创建完成抽象操作的函数时,如:拷贝,反转和排序,你必须定义多个版本以便能处理每一种 数据类型。以 max() 函数为例,它返回两个参数中的较大者:double max(double first, double second);
complex max(complex first, complex second);
date max(date first, date second);
//..该函数的其它版本
尽管这个函数针对不同的 数据类型其实现都是一样的,但程序员必须为每一种数据类型定义一个单独的版本:
double max(double first, double second)
{
return first>second? first : second;
}
complex max(complex first, complex second)
{
return first>second? first : second;
}
date max(date first, date second)
{
return first>second? first : second;
}
这样不但重复劳动,容易出错,而且还带来很大的维护和调试工作量。更糟的是,即使你在程序中不使用某个版本,其代码仍然增加 可执行文件的大小,大多数 编译器将不会从可执行文件中删除未引用的函数。
用普通函数来实现抽象操作会迫使你定义多个函数实例,从而招致不小的维护工作和调试开销。解决办法是使用函数模板代替普通函数。

函数声明格式
template <class(typename) any(或任意符合规则的名称) >(如果还有其他类型名,就用逗号隔开)
返回类型 函数名( 形参 表);
函数定义和声明格式基本相同,形参表要加上形参名,分号改为函数体。
声明的例子:
template <class type1, class type2>
type1 add(type1,type2);
template <class type1, class type2>
type1 add(type1 a,type2 b)
{return a + (type1)b;}
也可以直接定义函数,不声明。
说明: template是一个声明模板的关键字,表示声明一个模板关键字class不能省略,如果 形参类型多于一个 ,每个形参前都要加class <类型 形参表>可以包含基本 数据类型或类类。
#include <iostream>
using std::cout;
using std::endl;
//声明一个函数模版,用来比较输入的两个相同数据类型的参数的大小,class也可以被typename代替,
//T可以被名称字代替,只要符合命名规则即可。
template <class T>
T min(T& x,T& y)
{ return(x<y)?x:y;}
int main( )
{
    int n1 = 2,n2 = 10;
    double d1 = 1.5,d2 = 5.6;
    cout<< "较小整数:"<<min(n1,n2)<<endl;
    cout<< "较小实数:"<<min(d1,d2)<<endl;
    system("PAUSE");
    return 0;
}


程序运行结果:
程序分析:main()函数中定义了两个 整型变量n1 , n2 两个双精度类型变量d1 , d2然后调用min( n1, n2); 即实例化 函数模板T min(T x, T y)其中T为int型,求出n1,n2中的最小值.同理调用min(d1,d2)时,求出d1,d2中的最小值.




Container(容器)的概念:

用来管理一组元素。



­容器的分类
序列式容器(Sequencecontainers)
­每个元素都有固定位置--取决于插入时机和地点,和元素值无关。
­vector、deque、list
关联式容器(Associatedcontainers)
­元素位置取决于特定的排序准则,和插入顺序无关
­set、multiset、map、multimap



­Vectors
将元素置于一个动态数组中加以管理。
可以随机存取元素(用索引直接存取)。
数组尾部添加或移除元素非常快速。但是在中部或头部安插元素比较费时。


­Deques
deque,是“double-ended queue”的缩写。
可以随机存取元素(用索引直接存取)。
数组头部和尾部添加或移除元素都非常快速。但是在中部或头部安插元素比较费时。

­Lists
双向链表。
不提供随机存取(按顺序走到需存取的元素,O(n))。
在任何位置上执行插入或删除动作都非常迅速,内部只需调整一下指针。




迭代器(Iterator)


­指针与数组

  const int size=6;
    int a[size]={0,1,2,3,4,5};
    int *begin=a;
    int *end=a+6;
    for(int *p=begin;p!=end;p++)
    {
          cout<<*p<<" ";
    }
    cout<<endl;

­
­
­
­指针与其它数据结构呢?比如说链表?
存储空间是非连续的。不能通过对指向这种数据结构的指针做累加来遍历。
能不能提供一个行为类似指针的类,来对非数组的数据结构进行遍历呢?这样我们就能够以同样的方式来遍历所有的数据结构(所有容器)。


­迭代器与容器
通过迭代器,我们可以 用相同的方式来访问、遍历(泛型抽象)容器。



­迭代器的概念
迭代器是一个“可遍历STL容器内全部或部分元素”的对象。
一个迭代器指出容器中的一个特定位置。
具有遍历复杂数据结构的能力


­迭代器的作用
能够让迭代器与算法不干扰的相互发展,最后又能无间隙的粘合起来。
重载了*,++,==,!=,=运算符。用以操作复杂的数据结构。
容器提供迭代器,算法使用迭代器。




迭代器的分类:




一个例子:

template<class Input_iterator,class Distance>
void advance_II(Input_iterator & i, Distance n)
{
      for(;n>0;n--,i++); //单项逐一前进
}

template<class Bidirectional_iterator,class Distance>
void advance_BI(Bidirectional_iterator & i, Distance n)
{
      if(n>=0)     //双项逐一前进
      for(;n>0;n--,i++);
      else
      for(;n<0;n++,i--);
}

template<class RandomAcess_iterator,class Distance>
void advance_RAI(RandomAcess_iterator & i, Distance n)
{
      i+=n;    //随机,跳跃前进

}

Algorithm(算法)

­泛型算法通则
所有算法的前两个参数都是一对iterators:[first,last),用来指出容器内一个范围内的元素。
每个算法的声明中,都表现出它所需要的最低层次的iterator类型。


大部分算法都可以用functioinobject 来更改准则。functionobject又称functor。




不修改内容的序列操作:

adjacent_find 查找两个相邻(Adjacent)的等价(Identical)元素
all_ofC++11 检测在给定范围中是否所有元素都满足给定的条件
any_ofC++11 检测在给定范围中是否存在元素满足给定条件
count 返回值等价于给定值的元素的个数
count_if 返回值满足给定条件的元素的个数
equal 返回两个范围是否相等
find 返回第一个值等价于给定值的元素
find_end 查找范围A中与范围B等价的子范围最后出现的位置
find_first_of 查找范围A中第一个与范围B中任一元素等价的元素的位置
find_if 返回第一个值满足给定条件的元素
find_if_notC++11 返回第一个值不满足给定条件的元素
for_each 对范围中的每个元素调用指定函数
mismatch 返回两个范围中第一个元素不等价的位置
none_ofC++11 检测在给定范围中是否不存在元素满足给定的条件
search 在范围A中查找第一个与范围B等价的子范围的位置
search_n 在给定范围中查找第一个连续n个元素都等价于给定值的子范围的位置

修改内容的序列操作:

copy 将一个范围中的元素拷贝到新的位置处
copy_backward 将一个范围中的元素按逆序拷贝到新的位置处
copy_ifC++11 将一个范围中满足给定条件的元素拷贝到新的位置处
copy_nC++11 拷贝 n 个元素到新的位置处
fill 将一个范围的元素赋值为给定值
fill_n 将某个位置开始的 n 个元素赋值为给定值
generate 将一个函数的执行结果保存到指定范围的元素中,用于批量赋值范围中的元素
generate_n 将一个函数的执行结果保存到指定位置开始的 n 个元素中
iter_swap 交换两个迭代器(Iterator)指向的元素
moveC++11 将一个范围中的元素移动到新的位置处
move_backwardC++11 将一个范围中的元素按逆序移动到新的位置处
random_shuffle 随机打乱指定范围中的元素的位置
remove 将一个范围中值等价于给定值的元素删除
remove_if 将一个范围中值满足给定条件的元素删除
remove_copy 拷贝一个范围的元素,将其中值等价于给定值的元素删除
remove_copy_if 拷贝一个范围的元素,将其中值满足给定条件的元素删除
replace 将一个范围中值等价于给定值的元素赋值为新的值
replace_copy 拷贝一个范围的元素,将其中值等价于给定值的元素赋值为新的值
replace_copy_if 拷贝一个范围的元素,将其中值满足给定条件的元素赋值为新的值
replace_if 将一个范围中值满足给定条件的元素赋值为新的值
reverse 反转排序指定范围中的元素
reverse_copy 拷贝指定范围的反转排序结果
rotate 循环移动指定范围中的元素
rotate_copy 拷贝指定范围的循环移动结果
shuffleC++11 用指定的随机数引擎随机打乱指定范围中的元素的位置
swap 交换两个对象的值
swap_ranges 交换两个范围的元素
transform 对指定范围中的每个元素调用某个函数以改变元素的值
unique 删除指定范围中的所有连续重复元素,仅仅留下每组等值元素中的第一个元素。
unique_copy 拷贝指定范围的唯一化(参考上述的 unique)结果

划分操作:

is_partitionedC++11 检测某个范围是否按指定谓词(Predicate)划分过
partition 将某个范围划分为两组
partition_copyC++11 拷贝指定范围的划分结果
partition_pointC++11 返回被划分范围的划分点
stable_partition 稳定划分,两组元素各维持相对顺序

排序操作:

is_sortedC++11 检测指定范围是否已排序
is_sorted_untilC++11 返回最大已排序子范围
nth_element 部份排序指定范围中的元素,使得范围按给定位置处的元素划分
partial_sort 部份排序
partial_sort_copy 拷贝部分排序的结果
sort 排序
stable_sort 稳定排序

二分法查找操作:

binary_search 判断范围中是否存在值等价于给定值的元素
equal_range 返回范围中值等于给定值的元素组成的子范围
lower_bound 返回指向范围中第一个值大于或等于给定值的元素的迭代器
upper_bound 返回指向范围中第一个值大于给定值的元素的迭代器

集合操作:

includes 判断一个集合是否是另一个集合的子集
inplace_merge 就绪合并
merge 合并
set_difference 获得两个集合的差集
set_intersection 获得两个集合的交集
set_symmetric_difference 获得两个集合的对称差
set_union 获得两个集合的并集

堆操作:

is_heap 检测给定范围是否满足堆结构
is_heap_untilC++11 检测给定范围中满足堆结构的最大子范围
make_heap 用给定范围构造出一个堆
pop_heap 从一个堆中删除最大的元素
push_heap 向堆中增加一个元素
sort_heap 将满足堆结构的范围排序

最大/最小操作:

is_permutationC++11 判断一个序列是否是另一个序列的一种排序
lexicographical_compare 比较两个序列的字典序
max 返回两个元素中值最大的元素
max_element 返回给定范围中值最大的元素
min 返回两个元素中值最小的元素
min_element 返回给定范围中值最小的元素
minmaxC++11 返回两个元素中值最大及最小的元素
minmax_elementC++11 返回给定范围中值最大及最小的元素
next_permutation 返回给定范围中的元素组成的下一个按字典序的排列
prev_permutation 返回给定范围中的元素组成的上一个按字典序的排列






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值