Spec-Zone.ru › C++

std::rotate

Определено в заголовочном файле <algorithm>
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt middle, ForwardIt last );
(1) (constexpr с C++20)
template< class ExecutionPolicy, class ForwardIt >
ForwardIt rotate( ExecutionPolicy&& policy,
                  ForwardIt first, ForwardIt middle, ForwardIt last );
(2) (с C++17)
1) Выполняет циклический сдвиг влево диапазона элементов.
В частности, std::rotate меняет местами элементы в диапазоне [first, last) таким образом, что элементы из [first, middle) перемещаются после элементов из [middle, last), сохраняя порядок элементов в обоих диапазонах.
2) То же, что и (1), но выполняется согласно policy.
Эта перегрузка участвует в разрешении перегрузки, только если значение следующего выражения равно true:

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>>

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>

(начиная с C++20)

Если выполняется любое из следующих условий, поведение программы не определено:

  • [first, middle) или [middle, last) не является допустимым диапазоном.
  • Тип *first не является Swappable.
(до C++11)
  • ForwardIt не является ValueSwappable.
  • Тип *first не является MoveConstructible.
  • Тип *first не является MoveAssignable.
(начиная с C++11)

Параметры

first, last - пара итераторов, задающая диапазон элементов для циклического сдвига
middle - элемент, который должен оказаться в начале диапазона после циклического сдвига
policy - используемая политика выполнения
Требования к типам
-ForwardIt должен соответствовать требованиям LegacyForwardIterator.

Возвращаемое значение

Итератор элемента, на который изначально указывал *first, то есть std::distance(middle, last)-й следующий итератор после first.

Сложность

Не более std::distance(first, last) обменов.

Исключения

Перегрузка с параметром шаблона с именем ExecutionPolicy сообщает об ошибках следующим образом:

  • Если выполнение функции, вызванной в рамках алгоритма, приводит к выбросу исключения, а ExecutionPolicy является одной из стандартных политик, вызывается std::terminate. Для любого другого значения ExecutionPolicy поведение определяется реализацией.
  • Если алгоритму не удаётся выделить память, выбрасывается std::bad_alloc.

Возможная реализация

См. также реализации в libstdc++, libc++ и MSVC STL.

template<class ForwardIt>
constexpr // since C++20
ForwardIt rotate(ForwardIt first, ForwardIt middle, ForwardIt last)
{
    if (first == middle)
        return last;
    
    if (middle == last)
        return first;
    
    ForwardIt write = first;
    ForwardIt next_read = first; // read position for when “read” hits “last”
    
    for (ForwardIt read = middle; read != last; ++write, ++read)
    {
        if (write == next_read)
            next_read = read; // track where “first” went
        std::iter_swap(write, read);
    }
    
    // rotate the remaining sequence into place
    rotate(write, next_read, last);
    return write;
}

Примечания

std::rotate в распространённых реализациях работает эффективнее, если ForwardIt соответствует требованиям LegacyBidirectionalIterator или (что ещё лучше) LegacyRandomAccessIterator.

Реализации (например, MSVC STL) могут включать векторизацию, если тип итератора соответствует требованиям LegacyContiguousIterator, а обмен значениями его типа не вызывает ни одной нетривиальной функции-члена, специальной для этого типа, и ни одной функции swap, найденной с помощью ADL.

Пример

std::rotate — распространённый строительный блок многих алгоритмов. В этом примере демонстрируется сортировка вставками.

#include <algorithm>
#include <iostream>
#include <vector>

auto print = [](const auto remark, const auto& v)
{
    std::cout << remark;
    for (auto n : v)
        std::cout << n << ' ';
    std::cout << '\n';
};

int main()
{
    std::vector<int> v{2, 4, 2, 0, 5, 10, 7, 3, 7, 1};
    print("before sort:\t\t", v);
    
    // insertion sort
    for (auto i = v.begin(); i != v.end(); ++i)
        std::rotate(std::upper_bound(v.begin(), i, *i), i, i + 1);
    print("after sort:\t\t", v);
    
    // simple rotation to the left
    std::rotate(v.begin(), v.begin() + 1, v.end());
    print("simple rotate left:\t", v);
    
    // simple rotation to the right
    std::rotate(v.rbegin(), v.rbegin() + 1, v.rend());
    print("simple rotate right:\t", v);
}

Вывод:

before sort:                2 4 2 0 5 10 7 3 7 1
after sort:                0 1 2 2 3 4 5 7 7 10
simple rotate left:        1 2 2 3 4 5 7 7 10 0
simple rotate right:        0 1 2 2 3 4 5 7 7 10

Отчёты об ошибках

Следующие отчёты об ошибках, изменяющие поведение, были применены задним числом к ранее опубликованным стандартам C++.

Отчёт об ошибке Применён к Опубликованное поведение Корректное поведение
LWG 488 C++98 новая позиция элемента, на который указывает first, не возвращалась возвращается

См. также

rotate_copy
копирует и циклически сдвигает диапазон элементов
(шаблон функции и функциональный объект алгоритма)
ranges::rotate_copy
(C++20)
ranges::rotate
(C++20)
циклически сдвигает порядок элементов в диапазоне
(функциональный объект алгоритма)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/rotate

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API