qsort
От: Mikka77  
Дата: 16.02.05 17:47
Оценка:
Добрый вечер.
Предположим, имеется такой код:

struct MyStruct {
  ANYTYPE m_a;
  ANYTYPE m_b;
  std::string m_s;
};

class CAny {
//...
  CArray<MyStruct , MyStruct>array;
//..
};

void CAny::Sort(int type, BOOL bAscending)
{
  //type - индекс, обозначает член MyStruct, по которому производить сортировку
  switch(type) {
    case 1:
    //...сортировать по m_a
    break;
    case 2:
    //...сортировать по m_b
    break;
    default:
    //...сортировать по m_s
    break;
  }
  qsort(array.GetData(), array.GetSize(), sizeof(MyStruct), compare);
  //compare - адрес СТАТИЧЕСКОЙ ф-ции сортировки
}

Получается, что я должен определить ф-ю сортировки для каждого члена MyStruct.
А учитывая, что сортировка может быть задана как по возрастанию, так и по убыванию, то получается по 2 ф-ции на каждого члена:
class CAny {
//...
static int __cdecl CompareAscA(const void* p1, const void* p2);
static int __cdecl CompareDescA(const void* p1, const void* p2);

static int __cdecl CompareAscB(const void* p1, const void* p2);
static int __cdecl CompareDescB(const void* p1, const void* p2);

static int __cdecl CompareAscS(const void* p1, const void* p2);
static int __cdecl CompareDescS(const void* p1, const void* p2);
//...
};

При этом

Я, конечно, могу завести статический член в MyStruct, который буду инициализировать в ф-ции Sort(),
и который будет определять, по какому полю MyStruct сортировать. Но проблема в том, что он будет статический. То есть асинхронная сортировка нескольких таких приведет к какой-то лаже.

Возможно, есть какое-то простое решение, но мне чего-то пока не сообразить.
Спасибо

17.02.05 17:23: Перенесено модератором из 'C/C++. Прикладные вопросы' — Павел Кузнецов
"Количество времени, необходимое для решения задачи, не зависит от того, было это время использовано для решение данной задачи или нет." ©Mikka77
Re: qsort
От: Mikka77  
Дата: 16.02.05 17:52
Оценка:
Здравствуйте, Mikka77, Вы писали:

M>Добрый вечер.

M>Предположим, имеется такой код:

M>
M>struct MyStruct {
M>  ANYTYPE m_a;
M>  ANYTYPE m_b;
M>  std::string m_s;
M>};

M>class CAny {
M>//...
M>  CArray<MyStruct , MyStruct>array;
M>//..
M>};

M>void CAny::Sort(int type, BOOL bAscending)
M>{
M>  //type - индекс, обозначает член MyStruct, по которому производить сортировку
M>  switch(type) {
M>    case 1:
M>    //...сортировать по m_a
M>    break;
M>    case 2:
M>    //...сортировать по m_b
M>    break;
M>    default:
M>    //...сортировать по m_s
M>    break;
M>  }
M>  qsort(array.GetData(), array.GetSize(), sizeof(MyStruct), compare);
M>  //compare - адрес СТАТИЧЕСКОЙ ф-ции сортировки
M>}
M>

M>Получается, что я должен определить ф-ю сортировки для каждого члена MyStruct.
M>А учитывая, что сортировка может быть задана как по возрастанию, так и по убыванию, то получается по 2 ф-ции на каждого члена:
M>
M>class CAny {
M>//...
M>static int __cdecl CompareAscA(const void* p1, const void* p2);
M>static int __cdecl CompareDescA(const void* p1, const void* p2);

M>static int __cdecl CompareAscB(const void* p1, const void* p2);
M>static int __cdecl CompareDescB(const void* p1, const void* p2);

M>static int __cdecl CompareAscS(const void* p1, const void* p2);
M>static int __cdecl CompareDescS(const void* p1, const void* p2);
M>//...
M>};
M>

M>При этом

M>Я, конечно, могу завести статический член в MyStruct, который буду инициализировать в ф-ции Sort(),

M>и который будет определять, по какому полю MyStruct сортировать. Но проблема в том, что он будет статический. То есть асинхронная сортировка нескольких таких приведет к какой-то лаже.

M>Возможно, есть какое-то простое решение, но мне чего-то пока не сообразить.

M>Спасибо

Забыл там дописать, что в MyStruct некоторые поля одного типа, соответственно не имеет смысла писать идентичные ф-ции сортировки для каждого поля
"Количество времени, необходимое для решения задачи, не зависит от того, было это время использовано для решение данной задачи или нет." ©Mikka77
Re: qsort
От: PM  
Дата: 17.02.05 07:19
Оценка:
Здравствуйте, Mikka77, Вы писали:

Типа такого?
#include <algorithm>
#include <functional>
#include <vector>
#include <iostream>
#include <iterator>

// Функтор сравнения
template<typename Class, typename Member>
struct mem_less : public std::binary_function<Class, Class, bool>
{
     typedef Member Class::* MemberPtr;

     MemberPtr mem_ptr_;

     mem_less(MemberPtr mem_ptr) : mem_ptr_(mem_ptr) {}
     bool operator()(Class const& obj1, Class const& obj2) const
     {
    return obj1.*mem_ptr_ < obj2.*mem_ptr_;
     }
};

struct A
{
     int a, b;
     float c;

     template<typename OStream>
     friend OStream& operator << (OStream& os, A const& obj)
     {
         os << "a: " << obj.a << " b: " << obj.b << " c: " << obj.c;
         return os;
     }
};

int main()
{
    std::vector<A>  aa(2);
    aa[0].a = 1; aa[0].b = 2; aa[0].c = 0.5f;
    aa[1].a = 2; aa[1].b = 1; aa[1].c = -0.5f;
    
    std::cout << "sort by A::a\n";
    std::sort(aa.begin(), aa.end(), mem_less<A, int>(&A::a));
    std::copy(aa.begin(), aa.end(),
        std::ostream_iterator<A>(std::cout, "\n"));
    
    std::cout << "sort by A::b\n";
    std::sort(aa.begin(), aa.end(), mem_less<A, int>(&A::b));
    std::copy(aa.begin(), aa.end(),
        std::ostream_iterator<A>(std::cout, "\n"));

    std::cout << "sort by A::c\n";
    std::sort(aa.begin(), aa.end(), mem_less<A, float>(&A::c));
    std::copy(aa.begin(), aa.end(),
        std::ostream_iterator<A>(std::cout, "\n"));
}


--
foobar2000 v0.8.3: выключен.
Re: qsort
От: Bell Россия  
Дата: 17.02.05 07:33
Оценка: 4 (2)
Здравствуйте, Mikka77, Вы писали:
Итак, pointers to members вступают в игру!


#include <vector>
#include <algorithm>
#include <string>

//Предикат, осуществляющий сравнение двух объектов по определенному полю
template<class T, class M>
class pmem_cmp_
{
   M T::* pmem_;//указатель на член
   bool bAscending_;
public:
   pmem_cmp_(M T::* pmem, bool bAscending) : pmem_(pmem), bAscending_(bAscending) {}
   bool operator() (const T& lhs, const T& rhs) const 
   {
      if(bAscending_)
         return lhs.*pmem_ < rhs.*pmem_;
      else
         return rhs.*pmem_ < lhs.*pmem_;

   }
};

//функция, упрощающая синтаксис при создании объекта - предиката: 
//вместо pmem_cmp_<MyStruct, int>(&MyStruct::n_) теперь можно написать pmem_cmp(&MyStruct::n_) 
template<class T, class M>
inline pmem_cmp_<T, M> pmem_cmp(M T::* pmem, bool bAscending) { return pmem_cmp_<T, M>(pmem, bAscending); }

struct MyStruct
{
   int n_;
   double d_;
   std::string s_;
};

//извини, но MFC-шные контейнеры я не перевариваю ;-)
class CAny
{
   std::vector<MyStruct> array;

public:
   void Sort(int type, bool bAscending);
};

void CAny::Sort(int type, bool bAscending)
{
   switch(type)
   {
      case 1:
         std::sort(array.begin(), array.end(), pmem_cmp(&MyStruct::n_, bAscending));
         break;
      case 2:
         std::sort(array.begin(), array.end(), pmem_cmp(&MyStruct::d_, bAscending));
         break;
      case 3:
         std::sort(array.begin(), array.end(), pmem_cmp(&MyStruct::s_, bAscending));
         break;
   };
}


Кстати в CAny::Sort можно сразу передавать указатель на член, по которому нужно сортировать, тогда реализации этой функции будет состоять вообще из одной строки.

Единственное требование — для элементов MyStruct, по которым будет производится сортировка, должен быть определен operator <().
Любите книгу — источник знаний (с) М.Горький
Re[2]: qsort
От: Mikka77  
Дата: 17.02.05 12:54
Оценка:
Здравствуйте, Bell, Вы писали:


template<class T, class C>
class CComparer
{
    C T::*m_pMember;
    BOOL m_bAscending;
public:
    CComparer(C T::*pMember, BOOL bAscending)
        : m_pMember(pMember), m_bAscending(bAscending){};

    BOOL operator() (const T &arg1, const T &arg2) const
    {
        if(m_bAscending)
            return *arg2.m_pMember < *arg1.m_pMember;
        else
            return *arg2.m_pMember < *arg1.m_pMember;
    }
};


void CClass::Sort(BOOL bAscending)
{
  CComparer<CAny, BOOL>(&CReportItem::m_time, bAscending);//ругается:
  //error C2665: 'CComparer<class CReportItem,int>::CComparer<class CReportItem,int>'
  //: none of the 2    overloads can convert parameter 1 from type 'unsigned long CReportItem::*'
}
"Количество времени, необходимое для решения задачи, не зависит от того, было это время использовано для решение данной задачи или нет." ©Mikka77
Re[3]: qsort
От: Bell Россия  
Дата: 17.02.05 13:07
Оценка: 3 (1)
Здравствуйте, Mikka77, Вы писали:

Тут неправильно:
M>    BOOL operator() (const T &arg1, const T &arg2) const
M>    {
M>        if(m_bAscending)
M>            return *arg2.m_pMember < *arg1.m_pMember;
M>        else
M>            return *arg2.m_pMember < *arg1.m_pMember;
M>    }


надо так:
return arg2.*m_pMember < arg1.*m_pMember;



Непонятно, что ты пытаештся тут создать:
M>  CComparer<CAny, BOOL>(&CReportItem::m_time, bAscending);//ругается:


Если ты хочешь сравнивать объекты типа CReportItem по полю m_time, то надо писать так:
  CComparer<CReportItem, Тип-члена-m_time>(&CReportItem::m_time, bAscending);
Любите книгу — источник знаний (с) М.Горький
Re[4]: qsort
От: Mikka77  
Дата: 17.02.05 13:28
Оценка:
Здравствуйте, Bell, Вы писали:
это я перепутал респект!
"Количество времени, необходимое для решения задачи, не зависит от того, было это время использовано для решение данной задачи или нет." ©Mikka77
Re[4]: qsort
От: WolfHound  
Дата: 17.02.05 14:43
Оценка: 1 (1)
Здравствуйте, Bell, Вы писали:

B>Тут неправильно:

B>
M>>    BOOL operator() (const T &arg1, const T &arg2) const
M>>    {
M>>        if(m_bAscending)
M>>            return *arg2.m_pMember < *arg1.m_pMember;
M>>        else
M>>            return *arg2.m_pMember < *arg1.m_pMember;
M>>    }
B>


B>надо так:

B>
B>return arg2.*m_pMember < arg1.*m_pMember;
B>

+1 Впрочем и это не все проблемы данного куска... m_bAscending на направление сортировки не влияет.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re: qsort
От: WolfHound  
Дата: 17.02.05 14:43
Оценка: 3 (2) +1
Здравствуйте, Mikka77, Вы писали:

M>
M>struct MyStruct {
M>  ANYTYPE m_a;
M>  ANYTYPE m_b;
M>  std::string m_s;
M>};
M>

Про остальное тебе уже расказали, а еще скажу что MyStruct с помощью qsort сортировать нельзя ибо MyStruct содержит std::string и как следствие не является POD типом.
... << RSDN@Home 1.1.4 beta 3 rev. 185>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[2]: qsort
От: Костя Ещенко Россия  
Дата: 17.02.05 22:39
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Mikka77, Вы писали:

B>Итак, pointers to members вступают в игру!

Несколько вызовов std::sort с предикатами разных типов приводят к излишнему раздуванию кода.
На мой взгляд лучше не плодить типы предикатов для каждого поля, а сделать чтобы предикаты одного типа могли сортировать по любому полю. Примерно так:

template<class T, T MyStruct::* Pm>
bool ConditionalCompare(MyStruct const& l, MyStruct const& r, bool less)
{
  return less
    ? l.*Pm < r.*Pm
    : r.*Pm < l.*Pm
    ;
}

struct MyStructCompare
{
  bool less;
  bool(* cond_compare )(MyStruct const&, MyStruct const&, bool);
    
  bool operator()(MyStruct const& l, MyStruct const& r) const
  {
    return cond_compare(l, r, less);
  }
};

void CClass::Sort(bool bAscending)
{
  MyStructCompare pred = { bAscending, 0 };
  
  switch( index )
  {
  case 0: pred.cond_compare = &ConditionalCompare<int, &MyStruct::i>; break;
  case 1: pred.cond_compare = &ConditionalCompare<double, &MyStruct::d>; break;
  default: pred.cond_compare = &ConditionalCompare<void*, &MyStruct::p>; break;
  }

  std::sort( begin(), end(), pred );
}
На самом деле, люди не читают газеты, они принимают их каждое утро, так же как ванну. ©Маршалл Мак-Льюэн
Re[2]: qsort
От: c-smile Канада http://terrainformatica.com
Дата: 18.02.05 00:59
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Про остальное тебе уже расказали, а еще скажу что MyStruct с помощью qsort сортировать нельзя ибо MyStruct содержит std::string и как следствие не является POD типом.


В общем верно,
но если сильно надо то можно и qsort. Надо лишь проверить устройство std::string для вашего компилятора.
В большинтсве имплементаций — можно. В 99% случаев raw swap эквивалентен логическому swap.

Disclaimer: это из разряда "если отдаешь себе отчет".
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.