zoukankan      html  css  js  c++  java
  • C++ 中对vector<T*> 数组的查找和排序



    /*
    2015-06-06 本文主要叙述对于vector<T*> (指针数组)如何进行find 操作下面的代码实现了Find,FindRange 模板函数,
    解释了为什么std::find 不能解决问题,
    解释了如用find_if来解决问题。
    并提供了一个sort 的例子
    */


    //
    --------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "Unit1.h" #include <vector> #include <algorithm> using namespace std; //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; class CA { public: int a; CA(int a) { this->a = a; } bool operator == (int t) { return a == t; } //无法编译 //friend bool operator == (const CA* ca,int t); }; //无法编译 /* bool operator == (const CA* ca,int t) { return ca->a == t; }*/ bool Compare(CA* f, CA* s) { return f->a < s->a; } template<class T1,class T2> vector<T1*>::iterator Find( vector<T1*>::iterator begin, vector<T1*>::iterator end, const T2& var) { while(begin != end) { if (*(*begin) == var) { return begin; } begin++; } } template<class T1,class T2> vector<T1*> FindRange( vector<T1*>::iterator begin, vector<T1*>::iterator end, const T2& var) { vector<T1*> result; while(begin != end) { if (*(*begin) == var) { result.push_back(*begin); } begin++; } return result; } /*** * 使用find_if */ static int globA = 1; bool prec (CA* ca) { if (globA == ca->a) return true; else return false; } vector<CA*> arry; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { arry.push_back(new CA(2)); arry.push_back(new CA(21)); arry.push_back(new CA(3)); arry.push_back(new CA(1)); arry.push_back(new CA(4)); arry.push_back(new CA(1)); arry.push_back(new CA(12)); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { sort(arry.begin(),arry.end(),Compare); for(unsigned i = 0; i < arry.size(); i++) { ShowMessage(IntToStr(arry[i]->a)); } vector<CA*>::iterator itor = find(arry.begin(),arry.end(),21); if (itor != arry.end()) { ShowMessage("find!"); } vector<CA*> range = FindRange<CA,int>(arry.begin(),arry.end(),1); ShowMessage("find "+IntToStr(range.size())+" number"); globA = 1; vector<CA*>::iterator itor2 = find_if(arry.begin(),arry.end(),prec); if (itor2 != arry.end()) { ShowMessage("find!"); } } //--------------------------------------------------------------------------- void __fastcall TForm1::FormDestroy(TObject *Sender) { for (unsigned i =0; i < arry.size() ;i++) { delete arry[i]; arry[i] = NULL; } arry.clear(); } //---------------------------------------------------------------------------

    上述代码使用模板函数对vector<T*> 类的数组,进行查找。

    标准库中的find 比较的方式如下:

    template <class _RandomAccessIter, class _Tp>
    _STLP_INLINE_LOOP _RandomAccessIter __find(_RandomAccessIter __first, _RandomAccessIter __last,
                                               const _Tp& __val,
                                               const random_access_iterator_tag &)
    {
      _STLP_DIFFERENCE_TYPE(_RandomAccessIter) __trip_count = (__last - __first) >> 2;
    
      for ( ; __trip_count > 0 ; --__trip_count) {
        if (*__first == __val) return __first; //解除引用然后比较
        ++__first;
    
        if (*__first == __val) return __first;
        ++__first;
    
        if (*__first == __val) return __first;
        ++__first;
    
        if (*__first == __val) return __first;
        ++__first;
      }
    
      switch(__last - __first) {
      case 3:
        if (*__first == __val) return __first;
        ++__first;
      case 2:
        if (*__first == __val) return __first;
        ++__first;
      case 1:
        if (*__first == __val) return __first;
        ++__first;
      case 0:
      default:
        return __last;
      }
    }

    可以看见,标准库的实现是 *__first == __val ,要求实现 == 操作符。

    然而,由于vector<T*> 内的元素都是指针,是无论如何也无法 满足==操作符比较的。

    至于,为什么vector里面存指针?这关系到运行效率,指针拷贝成本低。

    因此,如果vector<T*>这样的数组,基本考虑2种方式find

    //自己实现一个Find泛型方法,不过依然要求实现操作符重载。
    template<class T1,class T2> vector<T1*>::iterator Find( vector<T1*>::iterator begin, vector<T1*>::iterator end, const T2& var) { while(begin != end) { if (*(*begin) == var) { return begin; } begin++; } }

    或者采用find_if

    template <class _RandomAccessIter, class _Predicate>
    _STLP_INLINE_LOOP _RandomAccessIter __find_if(_RandomAccessIter __first, _RandomAccessIter __last,
                                                  _Predicate __pred,
                                                  const random_access_iterator_tag &)
    {
      _STLP_DIFFERENCE_TYPE(_RandomAccessIter) __trip_count = (__last - __first) >> 2;
    
      for ( ; __trip_count > 0 ; --__trip_count) {
        if (__pred(*__first)) return __first;
        ++__first;
    
        if (__pred(*__first)) return __first;
        ++__first;
    
        if (__pred(*__first)) return __first;
        ++__first;
    
        if (__pred(*__first)) return __first;
        ++__first;
      }
    
      switch(__last - __first) {
      case 3:
        if (__pred(*__first)) return __first;
        ++__first;
      case 2:
        if (__pred(*__first)) return __first;
        ++__first;
      case 1:
        if (__pred(*__first)) return __first;
        //    ++__first;  我不知道为什么这里有这样的注释,C++ BUILDER 6 里面的代码就是这样的。可见,标准库也是人写的。
      case 0:
      default:
        return __last;
      }
    }

    从find_if 的实现可以看出,他的想法是传入一个类或者函数,把元素作为参数代入,如果函数返回true,就满足条件。

    因此,使用了一个全局变量(实际应酌情考虑使用类成员)。

    /***
     * 使用find_if
     */
    static int globA = 1;
    
    bool prec (CA* ca)
    {
        if (globA == ca->a)
            return true;
        else
            return false;
    }
    //使用时
    globA = 1;
    vector<CA*>::iterator itor2 = find_if(arry.begin(),arry.end(),prec);

    附带一个sort排序的例子(这个方式和C#,Java 里的方式差不多,只不过 C# 和Java要求传入的是实现ICompare的接口而已,这里是函数指针,本质都是将“行为”传进去)

    在元素遍历,查找,排序方面,C#和Java要优雅的多。也许C++11 解决了这个问题,没去研究了。

  • 相关阅读:
    restful风格
    拦截器(拦截都是控制层的地址。 filter: )
    Springmvc完成ajax功能,controller类返回的数据类型为String且为汉字时出现乱码
    文件上传
    Springmvc完成ajax功能。(jquery. $)
    Controller如何进行重定向跳转
    Maven学习日志一
    SSM整合
    Spring学习日志四
    Spring学习日志三
  • 原文地址:https://www.cnblogs.com/songr/p/4555677.html
Copyright © 2011-2022 走看看