Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

Boost Minmax library

Boost , ,

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Header <boost/algorithm/minmax.hpp>

Motivation
Synopsis
Function templates description
Definition
Requirements on types
Preconditions
Postconditions
Complexity
Example
Notes
Rationale
Note about performance
Acknowledgements

Motivation

Библиотека minmax состоит из двух заголовкови(см.обоснование). Проблема, решаемая этой библиотекой, заключается в том, что одновременные вычисления min и max требуют только одного сравнения, но с использованиемstd::minиstd::maxСравнение двух сил. Хуже того, для вычисления минимальных и максимальных элементов диапазонаnэлементов требуется только3n/2+1сравнения, вместо2n(в двух проходах), вынужденныхstd::min_elementиstd::max_element. Я всегда думал, что это пустая трата, чтобы вызвать две функции, чтобы вычислить степень диапазона, выполняя два прохода над входом, когда одного должно быть достаточно. Библиотека решает обе проблемы.

Первый файл реализует шаблоны функцийminmaxкак простые расширения стандарта C++. Когда он возвращает паруconst&, мы должны использовать библиотекуBoost.tupleдля создания таких пар. (Обратите внимание: намерение состоит не в том, чтобы исправить известные по умолчаниюstd::minиstd::max, а в том, чтобы добавить еще один алгоритм, который объединяет оба; см.обоснование.)

Второй файл реализует функциональные шаблоныminmax_element. Во второй части также предлагаются варианты, которые обычно не могут быть вычислены алгоритмом minmax, и которые являются более гибкими в случае, если некоторые элементы равны. Эти варианты могли быть также обеспечены политическим дизайном, но я вынес решение против этого (см.обоснование).

Если вас интересует производительность, вы увидите, чтоminmax_elementнемного менее эффективен, чем одинmin_elementилиmax_element, и, таким образом, в два раза эффективнее двух отдельных вызововmin_elementиmax_element. С теоретической точки зрения все функцииminmax_elementвыполняют максимум3n/2+1сравнения и ровно n приращенийForwardIterator.

Synopsis of <boost/algorithm/minmax.hpp>

#include <boost/tuple/tuple.hpp>
namespace boost {
  template <class T>
  tuple<T const&, T const&>
  minmax(const T& a, const T& b);
  template <class T, class BinaryPredicate>
  tuple<T const&, T const&>
  minmax(const T& a, const T& b, BinaryPredicate comp);
}

Synopsis of <boost/algorithm/minmax_element.hpp>

#include <utility> // for std::pair
namespace boost {
  template <class ForwardIterator>
  std::pair<ForwardIterator,ForwardIterator>
  minmax_element(ForwardIterator first, ForwardIterator last);
  template <class ForwardIterator, class BinaryPredicate>
  std::pair<ForwardIterator,ForwardIterator>
  minmax_element(ForwardIterator first, ForwardIterator last,
                 BinaryPredicate comp);
}
In addition, there are a bunch of extensions which specify which element(s) you want to pick in case of equal elements. They are:
  • first_min_elementиlast_min_element
  • First_max_elementиlast_max_element
  • first_min_first_max_element,first_min_last_max_element,last_min_first_max_elementиlast_min_last_max_element
I won't bore you with the complete synopsis, they have exactly the same declaration as their corresponding _element function. Still, you can find the complete synopsis here.

Function templates description

The minmax algorithm returns a pair p containing either (a,b) or (b,a), such that p.first<p.second in the first version, or comp(p.first,p.second) in the second version. If the elements are equivalent, the pair (a,b) is returned.
[1]

minmax_elementсемантически эквивалентенfirst_min_first_max_element.

First_min_elementиfirst_max_elementнаходят наименьшие и наибольшие элементы в диапазоне[первый, последний]. Если таких элементов несколько, то первый возвращается. Они идентичныstd::min_elementиstd::max_elementи включены в эту библиотеку только для симметрии.

Последний_мин_элементипоследний_макс_элементнаходят наименьшие и наибольшие элементы в диапазоне[первый, последний]. Они почти идентичныstd::min_elementиstd::max_element, за исключением того, что они возвращают последний экземпляр самого большого элемента (а не первый, какfirst_min_elementиlast_max_element).

Семейство алгоритмов, включающихпервый_min_first_max_element,первый_min_last_max_element,последний_min_first_max_elementипоследний_min_last_max_element, можно описать в общем виде следующим образом (используя, который, чтодляпервогоилипоследнего):, который_min_, что_max_element, который, который, который, который наименьший элемент и (первый или последний, согласно, что, что) самый большой элемент в диапазоне[первый, последний], самый большой элемент в диапазонеПервая версия семантически эквивалентна:<

 std::make_pair(boost::which_min_element(first,last),
                 boost::what_max_element(first,last)),
>и вторая версия:<
 std::make_pair(boost::which_min_element(first,last,comp),
                 boost::what_max_element(first,last,comp)).
>


Примечание:первый_min_last_max_elementтакже можно описать как нахождение первого и последнего элементов в диапазоне, если бы он был стабильно отсортирован.

Определение

Определено вminmax.hppи вminmax_element.hpp

Требования к типам

Для minmaxTдолжна быть моделью
LessThan Comparable.

Для всех остальных шаблонов функций версии с двумя параметрами шаблона:

Для версий с тремя параметрами шаблона:

Предварительные условия

  • [перформанс, ][Время суток].

Постусловия

В дополнение к приведенному выше семантическому описанию дляminmax_elementи всех, которые_min_какие_max_elementварианты, значение возвратапоследнееилиstd::make_pair(last,last)тогда и только тогда, когда[первый, последний]является пустым диапазоном. В противном случае возвращаемое значение или оба члена получающейся пары являются итераторами в диапазоне[первый, последний].

Сложность

Минмакс выполняет одно сравнение и имеет постоянную сложность. Использование усилителя::tupleпредотвращает создание копий в случае, если аргументы передаются посредством ссылки.

Сложность всех остальных алгоритмов линейна. Все они выполняют ровно n операций приращения, и нулевые сравнения, если[первый, последний]пуст, в противном случае:

, гдеn— число элементов в[первый, последний].

Пример

Этот пример включен в раздел примеров библиотеки под
minmax_ex.cpp.<
int main()
{
  using namespace std;
  boost::tuple<int const&, int const&>result1 = boost::minmax(1, 0);
  assert( result1.get<0>() == 0 );
  assert( result1.get<1>() == 1 );
 list<int>L;
 generate_n(front_inserter(L), 1000, rand);
  typedef list<int>::const_iterator iterator;
  pair< iterator, iterator >result2 = boost::minmax_element(L.begin(), L.end());
  cout << "The smallest element is " << *(result2.first) << endl;
  cout << "The largest element is  " << *(result2.second) << endl;
  assert( result2.first  == std::min_element(L.begin(), L.end());
  assert( result2.second == std::max_element(L.begin(), L.end());
}
>

Примечания

Мы не поддерживаем такие идиомы, какпривязка(a,b)=minmax(a,b)для заказа двух элементовa,b, хотя это имело бы желаемый эффект, если бы мы вернули ссылку вместо постоянной ссылки. Причина в том, что два ненужных задания выполняются, если a и b в порядке. Лучше придерживаться, если (bдля достижения этого эффекта.

Эти алгоритмы всегда выполняют не менее3n/2-2сравнений, что в любом случае является нижней границей по количеству сравнений (Кормен, Лейзерсон, Ривест: «Введение в алгоритмы», раздел 9.1, Упражнение 9.1-). Алгоритмы по существу сравнивают элементы в парах, выполняя 1 сравнение для первых двух элементов, затем 3 сравнения для каждой оставшейся пары элементов (один для заказа элементов и один для обновления каждого минимума и максимума). Когда число элементов нечетное, последний необходимо сравнить с текущим минимумом, а также с текущим максимумом. Кроме того, дляminmax, в случаях, когда равенство двух участников в паре может произойти, и обновление хранит второе, мы сохраняем первое, чтобы проверить в конце, если обновление должно было сохранить первое (в случае равенства). Трудно предсказать, будет ли выполнено последнее сравнение или нет, следовательно, самое большее в обоих случаях.

Эти алгоритмы всегда выполняют не менее3n/2-2сравнений, что в любом случае является нижней границей по количеству сравнений. Метод такой же, как в примечании.выше, и, как и выше, когда число элементов нечетное, последний необходимо сравнить с текущим минимумом, а также с текущим максимумом. Мы можем избежать последнего сравнения, если первое успешно, следовательно,самое большеевместоточнов странном случае.

Обоснование:

Почему не один заголовок?

Этот проект был первоначально предложен и одобрен в официальном обзоре. Поскольку потребность в Boost.tuple стала очевидной (из-за ограниченийstd::pair), стало также раздражающим требовать другую библиотеку дляminmax_element, которая в ней не нуждается. Следовательно, разделение на два файла заголовка.Передний итераторявляется модельюПередний итератор.

  • Форвард-итератор— этоLessThan Comparable.
  • For the versions with three template parameters:
    • Передний итераторявляется модельюПередний итератор.
    • Бинарный Предикатявляется модельюБинарный Предикат.
    • Форвардиотератортип значения конвертируется вдвоичный прогнозпервый тип аргумента и второй тип аргумента.

    Preconditions

    • [первый, последний]— действительный диапазон.

    Postconditions

    In addition to the semantic description above. for minmax_element and all the which_min_what_max_element variants, the return value is last or std::make_pair(last,last) if and only if [first, last) is an empty range. Otherwise, the return value or both members of the resulting pair are iterators in the range [first, last).

    Complexity

    Minmax performs a single comparison and is otherwise of constant complexity. The use of boost::tuple<T const&> prevents copy constructors in case the arguments are passed by reference.

    The complexity of all the other algorithms is linear. They all perform exactly n increment operations, and zero comparisons if [first,last) is empty, otherwise :

    where n is the number of elements in [first,last).

    Example

    This example is included in the distribution in the examples section of the library under
    minmax_ex.cpp.
    int main()
    {
      using namespace std;
      boost::tuple<int const&, int const&> result1 = boost::minmax(1, 0);
      assert( result1.get<0>() == 0 );
      assert( result1.get<1>() == 1 );
      list<int> L;
      generate_n(front_inserter(L), 1000, rand);
      typedef list<int>::const_iterator iterator;
      pair< iterator, iterator > result2 = boost::minmax_element(L.begin(), L.end());
      cout << "The smallest element is " << *(result2.first) << endl;
      cout << "The largest element is  " << *(result2.second) << endl;
      assert( result2.first  == std::min_element(L.begin(), L.end());
      assert( result2.second == std::max_element(L.begin(), L.end());
    }

    Notes

    [1] We do not support idioms such as tie(a,b)=minmax(a,b) to order two elements a, b, although this would have the desired effect if we returned a reference instead of a constant reference. The reason is that two unnecessary assignments are performed if a and b are in order. It is better to stick to if (b<a) swap(a,b) to achieve that effect.

    [2] These algorithms always perform at least 3n/2-2 comparisons, which is a lower bound on the number of comparisons in any case (Cormen, Leiserson, Rivest: "Introduction to Algorithms", section 9.1, Exercise 9.1-). The algorithms essentially compare the elements in pairs, performing 1 comparison for the first two elements, then 3 comparisons for each remaining pair of elements (one to order the elements and one for updating each the minimum and and the maximum). When the number of elements is odd, the last one needs to be compared to the current minimum and also to the current maximum. In addition, for minmax, in cases where equality of the two members in the pair could occur, and the update stores the second, we save the first to check at the end if the update should have stored the first (in case of equality). It's hard to predict if the last comparison is performed or not, hence the at most in both cases.

    [3] These algorithms always perform at least 3n/2-2 comparisons, which is a lower bound on the number of comparisons in any case. The method is the same as in note [2] above, and like above, when the number of elements is odd, the last one needs to be compared to the current minimum and also to the current maximum. We can avoid the latter comparison if the former is successful, hence the at most instead of exactly in the odd case.

    Rationale:

    Why not a single header <boost/algorithm/minmax.hpp>?

    This was the design originally proposed and approved in the formal review. As the need for Boost.tuple became clear (due to the limitations of std::pair), it became also annoying to require another library for minmax_element which does not need it. Hence the separation into two header files.[ORIG_END] -->

    Your minmax suffers from the same problems as std::min and std::max.

    Я знаю о проблемах с std::min и std::max, и все дебаты, которые продолжаются (пожалуйста, проконсультируйтесь).Статья Александрескуи ссылки на нее. Но я не рассматриваю цель этой библиотеки как исправление чего-то, что является частью стандарта C++. Я смиренно думаю, что это выходит за рамки этой библиотеки. Скорее, я следую стандарту, просто предоставляя еще одну функцию той же семьи. Если кто-то еще хочет исправить std::min, их исправление, вероятно, будет применяться для повышения::minmax.

    Why no min/max_element_if?

    В первой версии библиотеки я предложил_ifверсии всех алгоритмов (ну, не всех, потому что это было бы слишком много). Однако для этого просто нет причин, и все версии, которые у меня были, были так же быстро реализованы с использованием отличногоБиблиотека. А именно, призыв кmin_element_if (первый, последний, пред)будет так же хорошо реализован:<

         // equivalent to min_element_if(first, last, pred)
         min_element(boost::make_filter_iterator(first, last, pred),
                     boost::make_filter_iterator(last, last, pred));
    
    >Возможно, версияmin_element_ifнесколько короче, но накладные расходы на адаптеры итератора невелики, и они избавляются от большого количества кода (подумайте обо всех комбинациях между первым / последним и удвоите их с вариантами _if!).

    Discussion: about std::max_element

    Это обоснование несколько исторично, но объясняет, почему все эти функцииfirst/last_min/max_element.

    Стандарт C++ требует, чтобыstd::min_elementиstd::max_elementвозвращали первый экземпляр наименьших и крупнейших элементов (в отличие, скажем, от последнего). Этот произвольный выбор имеет некоторую последовательность: В случае v типа vector, например, верно, чтоstd::min_element(v.begin(),v.end(),std::less()) == std::max_element(v.begin(),v.end(),std:: greater()).

    Конечно, в этом нет ничего плохого: это просто вопрос выбора. Еще один способ определить min_element и max_element - определить их как первый и последний элементы, если диапазон был стабильно отсортирован. (Сортстабильныйнеобходим для разграничения итераторов, имеющих одинаковое значение.) В этом случае мин должен вернуть первую инстанцию, а макс - последнюю. Затем обе функции связаныreverse_iterator(std::first_min_element(v.begin(),v.end(),std::less())) == std::last_max_element(v.rbegin(),v.rend(),std:: greater()). Это определение тонко отличается от предыдущего.

    Проблема определения возникает, когда человек пытается спроектировать элемент minmax_element, используя процедуру, предложенную в (Cormen, Leiserson, Rivest: «Введение в алгоритмы», раздел 9.1). Ондолжениметь возможность вывести алгоритм, используя только3n/2сравнения, если[первый, последний]имеетnэлементов, но если попытаться написать функцию, называемуюfirst_min_first_max_element(), которая возвращает обаstd::min_elementиstd::max_elementв паре, тривиальная реализация не работает. Проблема, довольно тонко, заключается в равных элементах: Мне пришлось некоторое время думать, чтобы найти способ выполнить только три сравнения на пару и вернуть первые мин и первые макс элементы. Долгое время казалось, что любая попытка сделать это потребует четырех сравнений на пару в худшем случае. Эта реализация достигает трех.

    Невозможно (или даже желательно) изменить значениеmax_element, но все же полезно предоставить функцию под названиемminmax_element, которая возвращает паруmin_elementиmax_element. Хотя достаточно легко назватьmin_elementиmax_element, это выполняет2(n-1)сравнения и требуетдвухпроходов над входом. Напротив,minmax_elementбудет выполнять меньшее количество сравнений и выполнятьодиночныйпроход над входом. Экономия может быть значительной, когда тип итератора не является исходным указателем или даже просто моделью концепции InputIterator (хотя в этом случае интерфейс должен быть изменен, поскольку тип возврата не может быть скопирован, поэтому можно, например, вернуть значение).

    Чтобы извлечь выгоду из всех вариантов алгоритма, я предлагаю ввести какfirst_min_elementиlast_min_element, так и их аналогиfirst_max_elementиlast_max_element. Затем я также предлагаю все варианты алгоритмов:first_min_last_max_elementиlast_min_first_max_element, которые выполняют только самое большее3n/2сравнения, и только один проход на входе. Фактически, можно доказать, что для вычисления minmax требуется по меньшей мере3(n/2)-2сравнения в любом случае проблемы (Cormen, Leiserson, Rivest, 2-е издание, раздел 9.1). Реализация, которую я даю, не выполняет ненужных сравнений (результат которых мог быть вычислен по транзитивности от предыдущих сравнений).

    Похоже, чтопервый_min_last_max_elementможет быть немного медленнее, чемтолько первый_min_element, все еще намного меньше, чемпервый_min_elementипоследний_max_element, называемый отдельно

    . Почему алгоритмы, а не аккумуляторы?

    Алгоритмы minmax полезны для вычисления степени диапазона. В компьютерной графике нам нужен ограничивающий ящик из набора объектов. В этом случае необходимость в одном проходе еще более жесткая, поскольку все три направления должны быть сделаны сразу. Пища для размышлений: существует материя для хорошей общей библиотеки программирования со стекируемымиupdate_minиupdate_maxфункциональными объектами, которые хранят ссылку наmin_resultиmax_resultпеременных, в сочетании сfor_eachалгоритмом.

    Я считаю, что многие стандартные последовательные алгоритмы могут быть переформулированы с помощью аккумуляторов (и многие другие, такие как статистика, ожидание / дисперсия / и т. Д.). Кажется, что есть место для другой библиотеки, но я не вижу, чтобы она конкурировала с minmax, а скорее распространяла несколько алгоритмов (включая minmax) на каркас аккумулятора. Тем не менее, я чувствовал, что это выходит за рамки этой библиотеки, чтобы предоставить такие аккумуляторы.

    This first/last is a perfect application for a policy-based design.

    Правда, и я мог бы пойти по этому пути с политикой по умолчанию дляmin_elementиmax_element, чтобы выбрать первое появление результата. Это уменьшило бы количество комбинаций вариантов minmax_element. Но это также означало бы изменение интерфейсаboost::minmax_element. Одной из целей алгоритмаminmax_elementявляется его возможное дополнение к стандарту C++, в связи сstd::min_elementиstd::max_element(и я считаю, что это было бы вполне естественно, учитывая краткость реализации и не совсем тривиальную деталь, которая необходима, чтобы сделать его правильным). Таким образом, изменение интерфейса путем добавления политик означало бы, к сожалению, отход от стандарта и создало бы препятствие на пути к этой цели. Кроме того, код остается довольно читаемым и простым без политик. Поэтому я очень рад, что так оно и осталось.

    About performance

    Acknowledgements

    Generic: Min and Max Redivivus, by Andrei Alexandrescu Dr. Dobbs, April 2001

    My students in CS903 (Polytechnic Univ., http://photon.poly.edu/~hbr/cs903/) who had minmax_element as an assignment helped clarify the issues, and also come up with the optimum number of comparisons for first_min_last_max_element. The identification of the issue surrounding max_element is solely my own.

    One minmax_element implementation, which performs 3(n/2)+O(log n) comparisons on the average when the elements are random_shuffled, was suggested by my student Marc Glisse. The current one, which performs 3(n/2)+1 comparisons in the worst case, was suggested by John Iacono.

    Finally, Matthew Wilson and Jeremy Siek contributed pre-review comments, while Gennadiy Rozental, John Maddock, Craig Henderson, Gary Powell participated in the review of the library, managed by Thomas Witt. In particular, Gennadiy suggested a factorization of the code; while I haven't followed it all the way, his suggestions do make the code more readable and still work with older compilers. Late after the review, as I finally scrounged to add the library for a release, Eric Niebler noted the bad behavior of std::pair for minmax and suggested to use Boost.tuple instead. All my thanks for the excellent advice and reviews from all.

    See also

    min, max, min_element, max_element, LessThan Comparable, sort, nth_element .

    Last modified 2012-12-10

    © Copyright Hervé Brönnimann, Polytechnic University, 2002--2004. Use, modification, and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file License_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

    Статья Boost Minmax library раздела может быть полезна для разработчиков на c++ и boost.




    Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



    :: Главная :: ::


    реклама


    ©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
    Top.Mail.Ru

    Время компиляции файла: 2024-08-30 11:47:00
    2025-05-19 17:40:52/0.014015913009644/1