Здравствуйте, _nn_, Вы писали:
__>Чем аргументираванно такое поведение ?
__>Спасибо.
Алгоритмы (sort, stable_sort) не могут использоваться со списками, потому что списки не поддерживают итераторы свободного доступа. Впрочем, для сортировкиэлементов в списках определена специальная функция sort()
Здравствуйте, sadomovalex, Вы писали:
S>Здравствуйте, _nn_, Вы писали:
__>>Чем аргументираванно такое поведение ?
__>>Спасибо.
S>
S>Алгоритмы (sort, stable_sort) не могут использоваться со списками, потому что списки не поддерживают итераторы свободного доступа. Впрочем, для сортировкиэлементов в списках определена специальная функция sort()
S>Н. Джосьютис
Я это же и написал.
Просто идея такая — вместо того чтобы пихать sort по классам, которые не могут работать с std::sort обычным.
Сделать еще одну функцию (написанно выше какую) и ее перегружать для всего где не работает std::sort обычный.
Здравствуйте, _nn_, Вы писали:
__>Просто идея такая — вместо того чтобы пихать sort по классам, которые не могут работать с std::sort обычным. __>Сделать еще одну функцию (написанно выше какую) и ее перегружать для всего где не работает std::sort обычный. __>Почему не сделать так ?
Дык какая собсно тебе разница, вызывать функцию класса или передавать контейнер в глобальную функцию?
std::sort это — изначально — разновидность быстрой сортировки контейнеров с произвольным доступом (массивы, std::vector).
std::list::sort использует алгоритм сортировки двухсвязных списков.
std::set/map/multiset/multimap вообще сортировать нельзя.
Для контейнеров с медленным произвольным доступом (по forward iterator'у) можно написать разновидность быстрой сортировки. Но вроде бы ни в одной версии STL этого не сделали.
В принципе, можно сделать функцию-диспетчера, которая различала бы тип контейнера и выполняла ту или иную сортировку.
template<class V, class A, class P>
void sort_container(std::vector<V,A>& cont, P pred)
{
std::sort(cont.begin(), cont.end(), pred);
}
template<class V, class A, class P>
void sort_container(std::list<V,A>& cont, P pred)
{
cont.sort(pred);
}
template<class C>
void sort_container(C& cont)
{
sort_container(cont, std::less<typename C::value_type>());
}
Перекуём баги на фичи!
Re[3]: Однообразность в STL
От:
Аноним
Дата:
25.08.04 12:43
Оценка:
Так ведь таким образом ты и потеряешь внешнюю, видимую пользователю однообразность, у тебя будет что-нить вроде
template<class Cont>
void Sort(Cont &);
template<class T>
void Sort(list<T> &);//допустим, вижуал 6.0 не сможет определить кто из функций лучше подходит, но это
//уже дело десятое
Здравствуйте, _nn_, Вы писали:
__>Напрашивается вопрос почему не сделать функцию sort в векторе. __>Или же почему не сделать функцию sort еще и так: __>
Ага, согласен, там еще много интересных функций которые хотелось бы так же перегрузить, например for_each. Такие разновидности я уже реализовал здесь, например kafe/algorithm.hpp (CVS версия).
__>А потом перегружать для нужных контейнеров. __>И тогда не будет проблемы выше.
Этого не делал, не было надобности.
__>Чем аргументираванно такое поведение ?
Историей наверно, да к тому же в STL много функций, которые должны работать именно с итераторами, а не с контейнерами, видимо решили базироваться на чем то одном (для общности ).
PS. Просматривая стандартный <algorithm> все время вспоминал про то, что как было бы здорово иметь нормальные ламбда функции в C++. Половину STL можно было бы выкинуть
Здравствуйте, Aera, Вы писали:
A>Можно сортировать не только контейнеры целиком, но и часть контейнера, в т.ч. и когда контейнер не является классом:
A>
A>int a[10];
A>std::sort(a, a+10);
A>
Это легко лечиться классом оболочкой, которая содержит в себе пару итераторов
Например, так:
/// Array reference.template<class ValueType>
class array_ref:
{
public:
template<int Size>
array_ref(ValueType (&X)[Size]): Begin(X), End(X+Size) {}
// здесь интерфейсы контейнера, такие как typedef ... iterator, iterator begin() и т.д. ...
...
private:
ValueType *Begin;
ValueType *End;
};
/// Creates an array reference.template<class ValueType, int Size>
array_ref<ValueType> make_array_ref(ValueType (&X)[Size])
{
return array_ref<ValueType>(X);
}
Тогда пример будет выглядеть так:
int a[10];
std_ex::sort(make_array_ref(a));
Заметь, безопаснее, так как размер массива может измениться в следующей версии программы. Пример реализации array_ref здесь.
Здравствуйте, _nn_, Вы писали:
__>Просто идея такая — вместо того чтобы пихать sort по классам, которые не могут работать с std::sort обычным.
__>Сделать еще одну функцию (написанно выше какую) и ее перегружать для всего где не работает std::sort обычный.
Короче, надо паттерн "стратегия" в шаблонном варианте применить.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _nn_, Вы писали:
К><>
К>std::sort это — изначально — разновидность быстрой сортировки контейнеров с произвольным доступом (массивы, std::vector). К>std::list::sort использует алгоритм сортировки двухсвязных списков. К>std::set/map/multiset/multimap вообще сортировать нельзя.
К>Для контейнеров с медленным произвольным доступом (по forward iterator'у) можно написать разновидность быстрой сортировки. Но вроде бы ни в одной версии STL этого не сделали.
К>В принципе, можно сделать функцию-диспетчера, которая различала бы тип контейнера и выполняла ту или иную сортировку. К>
К>template<class V, class A, class P>
К>void sort_container(std::vector<V,A>& cont, P pred)
К>{
К> std::sort(cont.begin(), cont.end(), pred);
К>}
К>template<class V, class A, class P>
К>void sort_container(std::list<V,A>& cont, P pred)
К>{
К> cont.sort(pred);
К>}
К>template<class C>
К>void sort_container(C& cont)
К>{
К> sort_container(cont, std::less<typename C::value_type>());
К>}
К>
Можно и так, но ИМХО здесь "чисто конкретно" паттерн стратегия (policy) в шаблонном варианте надо применять.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _nn_, Вы писали:
К><>
К>std::sort это — изначально — разновидность быстрой сортировки контейнеров с произвольным доступом (массивы, std::vector). К>std::list::sort использует алгоритм сортировки двухсвязных списков. К>std::set/map/multiset/multimap вообще сортировать нельзя.
К>Для контейнеров с медленным произвольным доступом (по forward iterator'у) можно написать разновидность быстрой сортировки. Но вроде бы ни в одной версии STL этого не сделали.
К>В принципе, можно сделать функцию-диспетчера, которая различала бы тип контейнера и выполняла ту или иную сортировку.
А почему в STL это не предусмотрели ?
Тогда можно было бы использовать одну функцию для всего.
Можно будет писать такое :
template<typename TContainer>
class C
{
TContainer c;
public:
void sort()
{
std::sort_container(c);
}
};
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, Aera, Вы писали:
_>Это легко лечиться классом оболочкой, которая содержит в себе пару итераторов
_>Например, так: _>
_>/// Array reference.
_>template<class ValueType>
_>class array_ref:
_>
Здравствуйте, _nn_, Вы писали:
К>>В принципе, можно сделать функцию-диспетчера, которая различала бы тип контейнера и выполняла ту или иную сортировку.
__>А почему в STL это не предусмотрели ? __>Тогда можно было бы использовать одну функцию для всего.
Потому что сортировка списка меняет порядок обхода, не меняя сами элементы. А сортировка массива — обменивает значения.
Криворукий эскиз быстрой сортировки над forward-итерируемым массивом. Заметьте, даже не над bidirectional.
template<class It, class Pred>
std::pair<It,size_t> dummy_partition(It begin, It end, Pred pred)
{
if(begin == end) return std::make_pair(begin,0);
It splitter = begin;
It it = splitter; ++it;
// invariant: [begin,splitter) < [splitter] < (splitter,it)
size_t d = 0; // == distance(begin,splitter)while(it != end)
{
if(!pred(*splitter, *it)) // *splitter >= *it
{
swap(*splitter,*it);
++splitter; ++d;
}
++it;
}
return std::make_pair(splitter,d);
}
template<class It, class Pred>
void dummy_sort_imp(It begin, It end, size_t size, Pred pred)
{
while(size > 1)
{
// разбиваем интервал на два, с центральным элементом
std::pair<It,size_t> part = dummy_partition(begin,end,pred);
It end1 = part.first;
It begin2 = end1; ++begin2;
size_t size1 = part.second;
size_t size2 = size-size1-1;
// рекурсивно спускаемся в меньший из интервалов (оставляя больший для следующей итерации)if(size1*2 <= size)
{
dummy_sort(begin, end1, size1, pred);
begin = begin2;
size = size2;
}
else
{
dummy_sort(begin2, end, size2, pred);
end = end1;
size = size1;
}
}
}
template<class It, class Pred>
void dummy_sort(It begin, It end, Pred pred)
{
// вычисляем размер интервала единожды (требуется O(N) инкрементов итератора)
dummy_sort_imp(begin, end, std::distance(begin,end), pred);
}
что есть случаи когда нельзя их использовать) и STL не собираюсь менять, но моему личному опыту, просто надоедает писать X.begin(), X.end() (а в основном именно такая последовательность встречаеться в коде), поэтому предлагаю пользоваться готовыми оболочками.
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, Aera, Вы писали:
A>>А какие вспомогательные классы нужны для следующего кода:
_>Можно так, используя sequence и make_sequence (см. там же, array_ref наследуеться от sequence): _>
_>std::vector<int> vector(2000);
_>// заполняем
_>std_ex::sort(vector);
_>int prev_size=vector.size();
_>for(int index=0; index<200; ++index)
_> vector.push_back(some_value());
_>std_ex::sort(make_sequence(vector.begin()+prev_size, vector.end())); // использовать оболочку sequence
_>std_ex::inplace_merge(vector, vector.begin()+prev_size); // здесь middle указываеться в конце.
_>
_>Не утверждаю что всегда надо передавать контейнеры везде где не попадя (я уже говорил
что есть случаи когда нельзя их использовать) и STL не собираюсь менять, но моему личному опыту, просто надоедает писать X.begin(), X.end() (а в основном именно такая последовательность встречаеться в коде), поэтому предлагаю пользоваться готовыми оболочками.
Можно сделать проще, если это идет имено в таком порядке и рядом :
что есть случаи когда нельзя их использовать) и STL не собираюсь менять, но моему личному опыту, просто надоедает писать X.begin(), X.end() (а в основном именно такая последовательность встречаеться в коде), поэтому предлагаю пользоваться готовыми оболочками.
__>Можно сделать проще, если это идет имено в таком порядке и рядом : __>
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, _nn_, Вы писали:
К>>>В принципе, можно сделать функцию-диспетчера, которая различала бы тип контейнера и выполняла ту или иную сортировку.
__>>А почему в STL это не предусмотрели ? __>>Тогда можно было бы использовать одну функцию для всего.
К>Потому что сортировка списка меняет порядок обхода, не меняя сами элементы. А сортировка массива — обменивает значения.
К>Криворукий эскиз быстрой сортировки над forward-итерируемым массивом. Заметьте, даже не над bidirectional.
Это не аргумент против добавления такой удобной вещи
Здравствуйте, sergey_shandar, Вы писали:
_>Здравствуйте, _nn_, Вы писали:
_>>>Не утверждаю что всегда надо передавать контейнеры везде где не попадя (я уже говорил
что есть случаи когда нельзя их использовать) и STL не собираюсь менять, но моему личному опыту, просто надоедает писать X.begin(), X.end() (а в основном именно такая последовательность встречаеться в коде), поэтому предлагаю пользоваться готовыми оболочками.
__>>Можно сделать проще, если это идет имено в таком порядке и рядом : __>>
_>Согласен, но у меня просто аллергия на дефайны .
Почему ?
Мне кажется что в данном случае гараздо проще использовать макрос чем определять десяток функций, к которым может еще что-нибудь добавиться, вдобавок этот макрос можно пихать везде, а не к только определенным функциям.
Здравствуйте, denisku, Вы писали:
D>Здравствуйте, _nn_, Вы писали:
__>>Просто идея такая — вместо того чтобы пихать sort по классам, которые не могут работать с std::sort обычным. __>>Сделать еще одну функцию (написанно выше какую) и ее перегружать для всего где не работает std::sort обычный. __>>Почему не сделать так ? D>Дык какая собсно тебе разница, вызывать функцию класса или передавать контейнер в глобальную функцию?
Разница в том что я смогу делать так : http://rsdn.ru/Forum/Message.aspx?mid=779712&only=1