关于在STL容器list中使用find_if搜索特定的节点

本人处在学习阶段,需要您的宝贵意见。。。。。。。。。


我使用的是比较大的数据结构,定义如下:

class Display

{

public:

              unsigned int ipAddress;

              unsigned int playStyle;

              unsigned int brightnessAdjust;

              unsigned int width;

              unsigned int height;

              unsigned int colorStyle;

              unsigned int oe;

              unsigned int driver;

              unsigned int colorGroup;

              unsigned int clockFrequency;

              unsigned int scanStyle;

              unsigned int clockOccupy;

              unsigned int grayLayer;

              unsigned int lineCloseTime;

              unsigned int lineScanAvailability;

              unsigned int brightnessValue;

              unsigned int linesOfEveryGroup;

              unsigned int rowsInverse;

              unsigned int colsInverse;

              unsigned int stantardReturn;

              unsigned int uReturn;

              unsigned int twiceReturn;

              unsigned int peculiarFunction;

              string       name;

      public:                

              Display (void);        // 构造函数声明

             ~Display (void);       // 析构函数声明

}

现基于list容器已经建立起具有若干节点(1~30)的list,并根据实际需要增添新的节点,要求新增的节点的name要和list中所有节点的name不同,我想到的方案是:在调用push_back之前,先对list进行搜索,检查是否已经存在和新增的节点的name相同的节点。若不存在,则可以调用push_back添加新节点,否则提示已经存在name相同的节点。其中name的值是在运行期由用户通过文本输入框(Edit)输入的字符串来确定的。实现过程,可以使用两种方式样式来配合算法find_if:使用辅助函数Unary Predicates和使用访函数(或称函数对象)(Functors or Function Objects)。

 

<!--[if !supportLists]-->       <!--[endif]-->使用辅助函数Unary Predicates :

算法有一种特殊的辅助函数叫做Predicates(判别式或谓词)。所谓Predicates,就是返回布尔值的函数。它们通常被用来指定搜索准则和排序准则,Predicates可能有一个或两个操作数,视情况而定。注意:并非任何返回布尔值的一元函数或二元函数都是合法的PredicatesSTL要求,面对相同的值,Predicates必须得出相同的结果,这条戒律将那些被调用时,会改变自己内部状态的函数清除出场。

如果两次用到这样的函数,每次用户输入的字符串不同,而且都是在执行时期才处理,则必须在函数被调用之前先将用户输入的字符串传给该函数,通常会导致使用一些全局变量,算法的调用者算法所调用的函数都会用到它们。

list<Display> displays_list;        // 全局变量

string newName;                          // 全局变量

bool CheckBeSameName (Display& x)

{      

      if (x.name.size () == newName.size ())

      {

            return (std::equal (x.name.begin (), x.name.end (), newName.begin ()));

      }

      else

      {

             return false;

      }

}

void __fastcall TForm::Button_AddClick (TObject *Sender)

{

newName.swap (string (Trim (Edit_Name->Text).c_str ()));

......

if (find_if (displays_list.begin (), displays_list.end (), CheckBeSameName)) == displays_list.end ())

      {                            

             Display display_temp;

              ......

              displays_list.push_back (display_temp);

       }

}

       例子中find_if算法在给定区间(Ranges)内搜索使被传入的一元判别式返回结果为true的第一个元素的迭代器,即返回给定区间内name成员的字符串数据值等于用户输入的字符串(newName)的第一个Display节点。如果没有任何节点匹配这个(name成员的字符串值等于用户输入的字符串newName)条件。find_if算法就返回区间的终点(也就是算法find_if的第二个参数)。

 

<!--[if !supportLists]-->       <!--[endif]-->使用访函数(或称函数对象)(Functors or Function Objects

传递给算法的函数型参数Functional Arguments),并不一定得是函数,也可以是行为类似函数的对象。这种对象称为Function Object(函数对象)或称Functor(访函数)。仿函数是泛型编程强大威力和纯粹抽象概念的又一个例证,可以说,任何东西,只要其行为像函数,它就可以被当作函数来用。什么才是具备函数行为(也就是行为像个函数)呢?所谓函数行为,是指可以使用小括号传递参数,藉以调用某个东西。如果你指望对象也可以具备函数行为,就必须让它们也可以被“调用”——通过小括号的运用和参数的传递。只需要定义operator(),并给予合适的参数类别:

class X

{

public:

               return_value_type operator () (arguments) const {...};

               ......

}

       为了获得C++标准程序库的保证行为,不应该传递一个行为取决于被拷贝次数或被调用次数的仿函数,也就是说,如果以两个相同的参数来调用一个单参数判别式(unary predicate),该判别式应该总是返回相同的结果。换句话说,判别式不应该因为被调用而改变自身状态。判别式的副本和其正本有着相同状态,要做到这一点,一定得保证不应该因为函数调用而改变判别式状态,应该将operator()声明为const成员函数。

 

相对于一般函数,访函数有它的优点:

1、仿函数是Smart Functions (智能型函数)行为类似指针的对象,我们称为Smart Pointers行为类似函数的对象,同样道理,我们可以称之为Smart Functions,因为它们的能力可以超越operator()。仿函数可以拥有成员函数和成员变量,这意味着仿函数拥有状态(state)。事实上,在同一时间里,由某个仿函数所代表的单一函数,可能有不同的状态,这在一般函数中是不可能的。另一个好处是:可以在执行期(runtime)初始化它们——当然必须在它们被使用(被调用)之前。

       2、每个仿函数都有自己的型别:一般函数,唯有在它们的标记式(signatures)不同时,才算型别不同。而仿函数即使标记式相同,也可以有不同的型别。事实上,有仿函数定义的每一个函数行为都有自己的型别。这对于利用template实现泛型编程是一个卓越贡献,由此,我们可以将函数行为当作template参数来运用。这使得不同型别的容器可以使用类型的仿函数作为排序准则。这可以确保不会在排序准则不同的群集(collections)之间赋值、合并或比较。甚至可以设计仿函数继承体系(Functions Hierarchies),以此完成某些特别事情,例如在一个总体原则下确立某些特殊情况。

       3、仿函数通常比一般函数速度快:就template而言,由于更多细节在编译期就已确定,所以通常可能进行更好的最佳化,所以,传入一个仿函数(而非一般函数),可以获得更好的性能。

list<Display> displays_list;        // 全局变量(避免了使用全局变量string newName的形式)

class CheckBeSameName

{

private:

      string newDisplayName;

public:

    CheckBeSameName (string str): newDisplayName (str) { }          // 构造函数(初始化行初始化)

                                                                                           // 无参数时可省略(使用缺省的)

      bool operator () (Display &x) const

            {
                if
(x.name.size () == newDisplayName.size ())

         {

              return (std::equal (x.name.begin (), x.name.end (), newDisplayName.begin ()));

         }

         else

         {

               return false;

         }

    }

};

void __fastcall TForm::Button_AddClick (TObject *Sender)

{

string temp_name (Trim (Edit_Name->Text).c_str ());

......

if (find_if (displays_list.begin (), displays_list.end (), CheckBeSameName (temp_name)) == displays_list.end ())

{   

Display display_temp;

......

              displays_list.push_back (display_temp);

}

}

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值