给出一个例子
这个函数的缺陷显而易见:它总是需要查找数据结构的所有元素,即使要查找的元素就在尾部也是如此。
template <typename T, typename X>
T find(T start, T beyond, const X& x)
{
while (start != beyond && *start != x)
++start;
return start;
}
这个泛型函数在一个任意的数据结构中进行线性查找。譬如说,我们声明了
int x [ 10 ]
而且我们想要找出在数组x中第一次出现42的位置,我们可以这样写
int* p = find (x , x+10 , 42 );
在此之后,p将指向x 中第一个等于42的元素,如果不存在这样的元素,p就指向超出末端的位置。
问题来了,假设我们不是想找出第一个,而是找出最后一个元素,那么我们该怎么做?
我们可能写出这样的函数
template <typename T, typename X>
T find1(T start, T beyond, const X& x)
{
T result = beyond;
while (start != beyond) {
if (*start == x)
result = start;
++start;
}
return result;
}
这个函数的缺陷显而易见:它总是需要查找数据结构的所有元素,即使要查找的元素就在尾部也是如此。
我们会想到,既然要找的是最后一次出现,为什么不从尾部开始往前找呢?
然后这样的函数应运而生了:
template <typename T, typename X>
T find2(T start, T beyond, const X& x)
{
if (start != beyond) {
T p = beyond;
do {
if (*--p == x)
return p;
}while (p != start)
}
return beyond;
}
为什么会这么复杂?与最开始的find函数比起来,这也太复杂了吧。本质原因是这样的,查找失败是所返回的值不如向前查找时返回的值合乎逻辑。在前向查找时,果然遍历整个数据结构都没找到要找的值,我们会返回末端在下一个位置的迭代器。但是,这个函数却不然,它从后往前遍历数据结构,若果找不到的话,却要返回最开始查找元素的前一个位置的迭代器。如此的蹩脚!!
这种不对称性源自c / c++ 语言定义的迭代器都确保逾尾值,但对超出头部的值却不能保障。换句话说如果定义了 int a [ 10 ] ,a + 10是合法的,而a + 11 、 a - 1 都是非法的。
书上给出了解决方法,不直接使用迭代器的值,而是假设每个迭代器都指向数据结构中紧跟在我们要查找的元素的后面的位置。
template <typename T, typename X>
T rnfind(T start, T beyond, const X& x)
{
while (beyond != start && beyond[-1] != x)
--beyond;
return beyond;
}
不使用 x -- 而是用beyond [ -1 ]意味着T必须是一个随机存储迭代器,而不仅仅是一个双向迭代器。
实际上已经完成任务了,但是我们想要更精妙一些。我们想要用最原始的find 函数来解决这个问题。假设T是一个双向迭代器,我们可以设计一个类型TR——行为和T类似,但
是方向相反。然后调用find 函数时我们只需传一对TR类型的迭代器即可。
记住我们 rnfind 函数的思想,于是我们写出了下面的代码
#ifndef REV_H_INCLUDED
#define REV_H_INCLUDED
#include "stdafx.h"
template <typename It, typename T> class Rev;
template <typename It, typename T> bool operator==(const Rev<It,T>&, const Rev<It,T>&);
template <typename It, typename T> bool operator!=(const Rev<It,T>&, const Rev<It,T>&);
template <typename It, typename T>
class Rev {
friend bool operator== <It, T> (const Rev<It,T>&, const Rev<It,T>&);
friend bool operator!= <It, T> (const Rev<It,T>&, const Rev<It,T>&);
public:
Rev(It);
operator It();
Rev<It, T>& operator++();
Rev<It, T> operator++(int);
Rev<It, T>& operator--();
Rev<It, T> operator--(int);
T& operator*();
private:
It it;
};
#include "Rev.cpp"
#endif
#include "Rev.h"
template <typename It, typename T>
Rev<It, T>::Rev(It i):it(i) { }
template <typename It, typename T>
Rev<It, T>::operator It()
{
return it;
}
template <typename It, typename T>
Rev<It, T>& Rev<It, T>::operator++()
{
--it;
return *this;
}
template <typename It, typename T>
Rev<It, T> Rev<It, T>::operator++(int)
{
Rev<It, T> r = *this;
--it;
return r;
}
template <typename It, typename T>
Rev<It, T>& Rev<It, T>::operator--()
{
++it;
return *this;
}
template <typename It, typename T>
Rev<It, T> Rev<It, T>::operator--(int)
{
Rev<It, T> r = *this;
++it;
return r;
}
template <typename It, typename T>
T& Rev<It, T>::operator*()
{
It i = it;
return *--i;
}
//
// 友元函数
template <typename It, typename T>
bool operator==(const Rev<It,T>& it1, const Rev<It,T>& it2)
{
return it1.it == it2.it;
}
template <typename It, typename T>
bool operator!=(const Rev<It,T>& it1, const Rev<It,T>& it2)
{
return !(it1 == it2);
}