Spec-Zone.ru › C++

std::rotate

Определено в заголовке <algorithm>
(1)
template< class ForwardIt >
ForwardIt rotate( ForwardIt first, ForwardIt middle, ForwardIt last );
(до C++20)
template< class ForwardIt >
constexpr ForwardIt rotate( ForwardIt first,
                            ForwardIt middle, ForwardIt last );
(с 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. Этот перегруз не участвует в разрешении перегрузки, если

std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> является true.

(до C++20)

std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> является true.

(с C++20)

Если [first, middle) или [middle, last) не является валидным диапазоном, поведение не определено.

Параметры

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

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

Итератор, равный:

  • last, если first == middle равно true,
  • first, если middle == last равно true,
  • first + (last - middle)[1] в противном случае, т.е. новое расположение элемента, на который указывает first.
  1. Операции + и - не обязаны поддерживаться, они используются только для представления позиции возвращаемого итератора.

Сложность

Линейная по расстоянию между first и last.

Исключения

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

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

Примечания

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

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

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

См. также реализации в 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 является распространённым строительным блоком во многих алгоритмах. Этот пример демонстрирует сортировку вставкой.

#include <algorithm>
#include <iostream>
#include <vector>
 
auto print = [](auto const remark, auto const& 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++.

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

См. также

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

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

Spec-Zone.ru

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