向量旋转

定义

向量的旋转是指将向量中每一个元素循环左移或者右移。左移和右移一定程度上是等价的,本文均以右移为例。

有两种表示方式:

rotate: vector.begin(), vector.end(), steps

rotate: vector.begin(), iterator_middle, vector.end()

其中,第一种意义与定义相同。

第二种是指旋转之后以 iterator_middle 为新的起始元素。即:

Before rotate:
begin, begin + 1, ..., middle, middle + 1, ..., end - 1

After rotate:
middle, middle + 1, ..., end - 1, begin, begin + 1, ..., middle - 1

使用

在 C++ 中使用 std::rotate(begin, middle, end) 来旋转向量以及其他有前向迭代器的容器。

如果需要旋转无迭代器的容器中的元素,请参考实现中的方法三。

实现

方法一 朴素算法

朴素实现是开一个等大的向量,然后遍历拷贝。消耗空间较大,故略过。

方法二 STL标准实现

STL 的标准实现为一个时间复杂度 $O(n)$,空间复杂度 $O(1)$ 的算法。

此方法先将 (begin, middle) 和 (middle, end) 中较短的部分交换,然后交换更长者的剩余部分。

template<class Iterator>
void rotate(Iterator first, Iterator medium, Iterator end) {
    Iterator next = middle;
    while (first != next)
    {
        swap (first++, next++);
        if (next==end) next = middle;
        else if (first==middle) middle = next;
    }
}

方法三 简单实现

设 $a = [begin, middle), b = [middle, end)$,对于初始向量 $ab$,要得到的结果向量为 $ba$。而

$$ ba = (a^{-1}b^{-1})^{-1} $$

其中 $^{-1}$ 指对序列取反。所以这个简单算法如下:

template<class Iterator>
void rotate(Iterator first, Iterator medium, Iterator end) {
    reverse(first, medium);
    reverse(medium, end);
    reverse(first, end);
}

此方法适用于需要手搓轮子的情况。比如二维 vector 矩阵需要按列旋转时。