STL一一find()函数算法的泛化过程

前言
再好的编程技巧,也无法让一个笨拙的算法起死回生。选择错误的算法,变注定了失败的命令。回归于主题,如果将一个叙述完整的算法转化成程序,是经过积累才能写得出来的。那么,如何设计一个算法,使它适用于任何数据结构呢?

什么叫泛化
我们也许会想,如何在即将处理的未知数据结构上,正确的实现所有的操作呢?只要把操作对象的类型加以抽象化,把操作对象的标示法和区间目标的移动行为抽象化,整个算法也就在一个抽象的层面工作了,整个过程称为算法的泛型化,简称泛化。

算法泛化实例
让我们看看算法泛化的一个实例,以简单的循序查找为例,假设我们要编写一个find()函数,在array中查找特地值,面对整数array,我们的直觉是:

int *find(int *arr,int size,int value)
{
	int i = 0;
	for (i = 0; i < size; i++)
		if (arr[i] == value)
			break;

	return &(arr[i]);
}

该函数在某个区间内查找value。返回的是一个指针,指向它所找到的第一个符合条件的元素;如果没有找到,就返回最后的一个元素的下一个位置。

通过一个实例来验证是否能查找到元素。下面是find()函数的使用

#include <iostream>

using namespace std;

int *find(int *arr,int size,int value)
{
	int i = 0;
	for (i = 0; i < size; i++)
		if (arr[i] == value)
			break;

	return &(arr[i]);
}


int main(int argc, char const *argv[])
{
	
	const int  SIZE = 10;
	int arr[SIZE] = {0,1,2,3,4,5,6,7,8,9};

	int len = sizeof(arr) / sizeof(int);
	int *end = arr + SIZE;
	int value = 6; //查找的值

	int *res = find(arr,len,value);
	if (res == end)
		cout <<value<< " not found"<<endl;
	else
		cout <<value<< " found"<<endl;


	return 0;
}

输出结果:
在这里插入图片描述

find()函数的这种做法暴露太多的实现细节,也因此太过依附特定的容器。为了让find()适用所有的类型的容器,其操作应该抽象化些,让find()接受两个指针类型的参数,标出一个操作区间,改进上面的find()函数的写法:

int *find(int *begin, int *end, int value)
{
	while (begin != end && *begin != value)
		++begin;

	return begin;
}

上面的find()函数在一个“前闭后开”区间[begin,end]内查找value,并返回一个指针,指向它所找到的第一个符合条件的元素:如果没有找到,就返回end。下面是使用find()函数的例子:

#include <iostream>

using namespace std;


int *find(int *begin, int *end, int value)
{
	while (begin != end && *begin != value)
		++begin;

	return begin;
}


int main(int argc, char const *argv[])
{
	
	const int  SIZE = 10;
	int arr[SIZE] = {0,1,2,3,4,5,6,7,8,9};

	int *end = arr + SIZE;
	int value = 6; //查找的值

	int *res = find(arr,end,value);
	if (res == end)
		cout <<value<< " not found"<<endl;
	else
		cout <<value<< " found"<<endl;


	return 0;
}

输出结果:

在这里插入图片描述
find()函数也可以方便地用来查找array的子区间:

int *res = find(arr,end,value);

模板与泛型编程
面向对象的编程OOP和泛型编程都能处理编程程序时不知道类型的情况。不同之处在于,OOP编程能处理类型在程序运行之前的未知的情况;而在泛型编程中,在编译时就能获知类型了。

容器、迭代器和算法都是泛型编程的例子,当我们编写一个泛型程序find()时,是独立于特定类型来编写代码的,当使用一个泛型程序时,我们提供类型或值,程序实例可在其上运行。

模板是泛型编程的基础。我们不必了解模板是如何定义的就使用它们。接下来看看find()的模板实现:

template<typename T>
T *find(T *begin, T *end, T& value)
{
	while (begin != end && *begin != value)
		++begin;

	return begin;
}

这样的find()很好,几乎适用于任何容器,只要该容器允许指针入,而指针们又支持以下四种find()函数中出现的操作行为:

  1. != 运算符
  2. *取值运算符
  3. 递增运算符(++)
  4. 复制,一边返回函数的返回值

模板与泛型编程find()例子如下:

#include <iostream>

using namespace std;


template<typename T>
T *find(T *begin, T *end, T& value)
{
	while (begin != end && *begin != value)
		++begin;

	return begin;
}

int main(int argc, char const *argv[])
{
	
	const int  SIZE = 10;
	int arr[SIZE] = {0,1,2,3,4,5,6,7,8,9};

	int *end = arr + SIZE;
	int value = 6; //查找的值

	int *res = find(arr,end,value);
	if (res == end)
		cout <<value<< " not found"<<endl;
	else
		cout <<value<< " found"<<endl;


	return 0;
}

输出结果:
在这里插入图片描述

find()函数的迭代器实现

迭代器是一种行为类似的指针对象,换句话说,是一种smart pointers。现在我将find()函数内的指针以迭代器取代,重新写:

#include <iostream>

using namespace std;


template<class Iterator, class T>
Iterator find(Iterator begin, Iterator end, T& value)
{
	while (begin != end && *begin != value)
		++begin;

	return begin;
}

int main(int argc, char const *argv[])
{
	
	const int  SIZE = 10;
	int arr[SIZE] = {0,1,2,3,4,5,6,7,8,9};

	int *end = arr + SIZE;
	int value = 6; //查找的值

	int *res = find(arr,end,value);
	if (res == end)
		cout <<value<< " not found"<<endl;
	else
		cout <<value<< " found"<<endl;


	return 0;
}

输出结果:

在这里插入图片描述
到这里,这便是一个完全的泛型化find()函数。你可以在任何C++标准库的某个头文件里看到它。长相几乎一模一样。

在这里插入图片描述

扫二维码关注微信公众号,获取技术干货

参考:STL源码剖析

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值