<?xml version="1.0" encoding="utf-8" ?>
<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink">
<description>
<title-info>
<genre>comp_programming</genre>
<author>
<first-name>Morten</first-name>
<middle-name></middle-name>
<last-name>Sшrvig</last-name>
</author>
<book-title>Базовые алгоритмы Qt 4 (Qt 4's Generic Algorithms)</book-title>
<lang>ru</lang>
<translator>
<first-name>Эдуард</first-name>
<middle-name></middle-name>
<last-name>Ершов</last-name>
</translator>
</title-info>
<document-info>
<author>
<first-name>Вадим</first-name>
<middle-name></middle-name>
<last-name>Кузнецов</last-name>
<nickname>DikBSD</nickname>
</author>
<program-used>ExportToFB21</program-used>
<date value="2008-06-27">27.06.2008</date>
<id>OOo-ExportToFB21-200862722542</id>
<version>1.0</version>
<history>
<p>1.0 Вычитка и создание fb2-файла</p>
</history>
</document-info>
</description>
<body>
<title>
<p>Базовые алгоритмы Qt 4 (Qt 4's Generic Algorithms)</p>
</title>
<section>
<p>Qt предоставляет ряд алгоритмов на основе шаблона, которые реализуют самые полезные алгоритмы STL, начиная с версии 2. В этой статье, мы рассмотрим некоторые из алгоритмов, предлагаемых в Qt 4 &lt;QtAlgorithms&gt;. </p>
<empty-line/>
<p>Qt предоставляет собственные алгоритмы потому, что некоторые платформы (например, embedded Linux) не предоставляет реализацию STL. Алгоритмы используются внутри Qt и доступны его пользователям. </p>
<p>Возможно смешивание реализаций STL и Qt контейнеров и алгоритмов. Например, вы можете использовать алгоритм std::find() для <a l:href="http://www.crossplatform.ru/documentation/qtdoc4.3/qlist.php">QList</a>&lt;T&gt;, или qSort() для std::vector&lt;T&gt;. Это работает потому, что алгоритмы основаны на итераторах STL-стиля, и итераторы контейнеров классов Qt отвечают требованиям STL. </p>
</section>
<section id="_twosortsofsort">
<title>
<p>Два вида сортировки</p>
</title>
<p>Алгоритмы qSort() и qStableSort()могут быть использованы при сортировке элементов <a l:href="http://www.crossplatform.ru/documentation/qtdoc4.3/qlist.php">QList</a>&lt;T&gt;, <a l:href="http://www.crossplatform.ru/documentation/qtdoc4.3/qvector.php">QVector</a>&lt;T&gt; или в любом динамическом C++ массиве. С Qt 4, также возможно определить любой оператор сравнения (вместо operator&lt;()). </p>
<p>Stable сортировка имеет свойство сохранения порядка похожих элементов при сортировке. Это полезно, когда имеешь дело с элементами, которые сравниваются между собой, даже если они не полностью эквивалентны. Например, если сортируется список адресов по фамилии, можно использовать qStableSort (), чтобы сохранить начальный порядок людей с одинаковой фамилией. Обычная сортировка не гарантирует этого. </p>
</section>
<section id="_linearandbinarysearch">
<title>
<p>Линейный и бинарный поиск</p>
</title>
<p>Алгоритмы qFind() и qBinaryFind() в качестве параметров получают итераторы диапазона и значение, а возвращают итератор на элемент, который соответствует данному значению, или "end" итератор, если не найдено ни одного элемента. Алгоритм бинарного поиска намного быстрее чем линейный алгоритм, но он может работать только с сортированными диапазонами. </p>
<p>Если значение встречается более одного раза, qFind() вернет итератор на первый элемент, тогда как qBinaryFind() на произвольный. </p>
<p>Для большей гибкости, Qt 4 предоставляет qLowerBound() и qUpperBound(). Как и qBinaryFind(), они работают с сортированным диапазоном. Если значение найдено, qLowerBound() вернет итератор на первый найденный элемент, а qUpperBound() вернет итератор, указывающий на следующий за последним элемент. Если значение не найдено, они вернут итератор на позицию, в которую данный элемент может быть вставлен. </p>
<p>Частый пример использования qLowerBound() и qUpperBound() это проход по всем вхождениям значения: </p>
<p><code>QStringList list;</code></p>
<p><code>QStringList::iterator i, j;</code></p>
<p><code>...</code></p>
<p><code>i = qLowerBound(list.begin(), list.end(), value);</code></p>
<p><code>j = qUpperBound(list.begin(), list.end(), value);</code></p>
<p><code> </code></p>
<p><code>while (i != j) {</code></p>
<p><code>    processItem(*i);</code></p>
<p><code>    ++i;</code></p>
<p><code>}</code></p>
</section>
<section id="_exampleastaticmap">
<title>
<p>Пример: статическая Map</p>
</title>
<p>В этой секции, мы будем использовать бинарный поиск, для реализации "static const" map. Структура данных полностью хранится в памяти и состоит из пары "фамилия, имя", которые отсортированы по фамилии. По сравнению с использованием <a l:href="http://www.crossplatform.ru/documentation/qtdoc4.3/qmap.php">QMap</a> или <a l:href="http://www.crossplatform.ru/documentation/qtdoc4.3/qhash.php">QHash</a>, этот подход экономит память и имеет смысл в высоко оптимизированных приложениях или библиотеках. </p>
<p>Сначала, мы определяем структуру для имен, а так же операторы сравнения для поиска вхождения фамилий: </p>
<p><code>struct Entry {</code></p>
<p><code>    const char *familyName;</code></p>
<p><code>    const char *givenName;</code></p>
<p><code>};</code></p>
<p><code> </code></p>
<p><code>bool operator&lt;(const Entry &amp;entry, const QString &amp;family)</code></p>
<p><code>{</code></p>
<p><code>    return entry.familyName &lt; family;</code></p>
<p><code>}</code></p>
<p><code> </code></p>
<p><code>bool operator&lt;(const QString &amp;family, const Entry &amp;entry)</code></p>
<p><code>{</code></p>
<p><code>    return family &lt; entry.familyName;</code></p>
<p><code>}</code></p>
<p>Затем объявляем наши данные: </p>
<p><code>static const int NumEntries = 4;</code></p>
<p><code>static const Entry entries[NumEntries] = {</code></p>
<p><code>    { "Deitel", "Harvey" },</code></p>
<p><code>    { "Deitel", "Paul" },</code></p>
<p><code>    { "Jobs", "Steve" },</code></p>
<p><code>    { "Torvalds", "Linus" }</code></p>
<p><code>};</code></p>
<p><code>static const Entry * const end = entries + NumEntries;</code></p>
<p>Указатель end отмечает конец массива. </p>
<p><code>bool contains(const QString &amp;family)</code></p>
<p><code>{</code></p>
<p><code>    return qBinaryFind(entries, end, family) != end;</code></p>
<p><code>}</code></p>
<p>Теперь, когда все на месте, реализация contains() тривиальна. Так как C++ указатели отвечают критериям STL итераторов произвольного доступа, мы можем использовать их в связке с qBinaryFind(). </p>
<p><code>QString givenName(const QString &amp;family)</code></p>
<p><code>{</code></p>
<p><code>    const Entry *i = qBinaryFind(entries, end, family);</code></p>
<p><code>    if (i == end)</code></p>
<p><code>        return "";</code></p>
<p><code>    return i-&gt;givenName;</code></p>
<p><code>}</code></p>
<p>Функция givenName() возвращает имя человека с данной фамилией. Например, если мы передаем в качестве аргумента "Torvalds", мы получаем "Linus"; если мы передаем "Deitel", функция возвращает "Harvey" или "Paul". </p>
<p><code>QStringList givenNames(const QString &amp;family)</code></p>
<p><code>{</code></p>
<p><code>    const Entry *i = qLowerBound(entries, end, family);</code></p>
<p><code>    const Entry *j = qUpperBound(entries, end, family);</code></p>
<p><code>    QStringList result;</code></p>
<p><code>    while (i != j)</code></p>
<p><code>        result += (i++)-&gt;givenName + (" " + family);</code></p>
<p><code>    return result;</code></p>
<p><code>}</code></p>
<p>Функция givenNames() возвращает список людей, принадлежащих определенной семье. Здесь показано использование qLowerBound() и qUpperBound(). </p>
</section>
</body>
</FictionBook>
