C++程序 右旋转数组的翻转算法
在许多应用程序中,需要将数组向右移动若干个位置。例如,当你在编辑一行文本时,若想往右移动一些单词,那么在底层,操作系统会对字符串数组进行右移操作。C++是一门强大的编程语言,提供了标准库中的函数和算法来解决此类问题。然而,在某些情况下,需要使用更为高效和灵活的方法来实现这种移动操作。
本文将介绍右旋转数组的翻转算法,其中包括两种不同的实现方式:利用环状替代和三次翻转法。两种算法的时间复杂度均为O(n),并且它们可以非常有效地移动数组。
环状替代算法
环状替代算法基于以下观察结果:当我们右旋转数组时,位于右侧的元素将移到数组的左侧,同时数组的其他元素向右移动一位。因此,我们可以利用环形替换来实现这种右移操作。
首先,我们将最右侧的k个元素从数组中取出,并将其存储在另一个数组中。然后,我们移动原数组中剩余的元素,使它们向右移动k个位置。最后,我们将先前存储在另一个数组中的元素插入到新数组的左侧。
以下是该算法的代码示例,其中数组的元素类型为int:
#include <iostream>
using namespace std;
void rotate(int nums[], int size, int k) {
k = k % size; // 验证输入的k是否超出数组大小
int count = 0;
for (int start = 0; count < size; start++) {
int current = start;
int prev = nums[start];
do {
int next = (current + k) % size;
int temp = nums[next];
nums[next] = prev;
prev = temp;
current = next;
count++;
} while (start != current);
}
}
int main() {
int nums[] = {1, 2, 3, 4, 5, 6, 7};
int k = 3;
int size = sizeof(nums) / sizeof(nums[0]);
rotate(nums, size, k);
for (int i = 0; i < size; i++) {
cout << nums[i] << " ";
}
return 0;
}
我们可以通过将数组向右移动3个位置来测试此代码。在此示例中,数组的元素值为{1, 2, 3, 4, 5, 6, 7}。输出的结果应为{5, 6, 7, 1, 2, 3, 4}。
三次翻转法
三次翻转法是一种更好的算法,它具有更好的空间复杂度,并且代码更为简洁。
首先,我们依次翻转整个数组,然后再将初始数组分成两个子数组A和B。我们依次翻转这两个子数组,最后的结果即为右移k位后的数组。
以下是该算法的代码示例:
#include <iostream>
using namespace std;
void reverse(int nums[], int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
void rotate(int nums[], int size, int k) {
k = k % size;
reverse(nums, 0, size - 1);
reverse(nums, 0, k - 1);
reverse(nums, k, size - 1);
}
int main() {
int nums[] = {1, 2, 3, 4, 5, 6, 7};
int k = 3;
int size = sizeof(nums) / sizeof(nums[0]);
rotate(nums, size, k);
for (int i = 0; i < size; i++) {
cout << nums[i] << " ";
}
return 0;
}
同样的,我们将数组向右移动3个位置,输出的结果应为{5, 6, 7, 1, 2, 3, 4}。
结论
两种算法均可用于将数组向右移动若干个位置。环状替代算法可以交换两个元素之间的位置,因此它可以在O(1)的时间内实现元素的移动。然而,它需要额外的O(k)空间来存储从右侧取出的元素,这可能会导致较大的空间开销。三次翻转法仅使用恒定的额外空间,因此具有更好的空间复杂度。此外,只需要三次翻转操作,该算法的时间复杂度为O(n)。
在运用这些算法之前,需要对输入的k进行合法性验证,避免其超出数组大小。通过实验结果,我们可以发现三次翻转法相对简洁,甚至还可以通过 STL提供的函数实现。然而,它仍需了解算法的逻辑,因为在日常的实际开发中,需要灵活运用这些基本技能并做出更为复杂的实现。