patternrubyMinor
Algorithm to rotate array elements in Ruby
Viewed 0 times
elementsarrayalgorithmrubyrotate
Problem
I wrote this algorithm to rotate elements in an array. It's not very efficient, but it works. It has another disadvantage that it doesn't rotate right (it would be nice to pass it negative steps, for example).
An aside, does this count as \$O(n^2)\$? For each step, we have to iterate over the entire array and shift positions by -1.
Let \$A\$ be the size of the array, \$S\$ be the steps, and \$C\$ be the constant operations of storing the first element then adding it to the end of the array.
$$
T(A, S) = S(A) + S(2C)
$$
This notation is ad-hoc, so excuse me if it doesn't make sense.
I am aware of
But I'm curious if there are other ways that rely less on
def rotate_left!(array, steps = 1)
for i in 0...steps
first = array[0]
for j in 1...array.size
array[j - 1] = array[j]
end
array[-1] = first
end
endAn aside, does this count as \$O(n^2)\$? For each step, we have to iterate over the entire array and shift positions by -1.
Let \$A\$ be the size of the array, \$S\$ be the steps, and \$C\$ be the constant operations of storing the first element then adding it to the end of the array.
$$
T(A, S) = S(A) + S(2C)
$$
This notation is ad-hoc, so excuse me if it doesn't make sense.
I am aware of
array#rotate, and of array#shift and array#pop. For example:def my_rotate!(array, steps = 1)
for i in 1..steps
array.push(array.shift)
end
end
# or
array.push(array.shift(steps)).flatten!But I'm curious if there are other ways that rely less on
Array instance methods.Solution
Your algorithm is \$O(N*M)\$ where:
\$N\$ = size of array
\$M\$ = steps
It's possible to do an array rotation that's \$O(N)\$, regardless of the number of steps you specify though.
Start by thinking of the array as two pieces, separated at "steps" indices into the array. For example, if you're going to rotate by 4, then mentally separate it into array[1..5] and array[5..N].
To do the rotation, start by reversing each of those pieces. Then reverse the entire array, something on this order:
Note: I'm more accustomed to C-style arrays, where indexes start at 0 instead of 1. I've tried to compensate appropriately, but I haven't tested this, so I wouldn't be surprised if there were still a few off-by-one errors.
This steps through the entire array twice, regardless of the size of rotation, so it's likely to be slower than yours for steps=1, about the same speed for steps = 2, and faster for steps > 2.
\$N\$ = size of array
\$M\$ = steps
It's possible to do an array rotation that's \$O(N)\$, regardless of the number of steps you specify though.
Start by thinking of the array as two pieces, separated at "steps" indices into the array. For example, if you're going to rotate by 4, then mentally separate it into array[1..5] and array[5..N].
To do the rotation, start by reversing each of those pieces. Then reverse the entire array, something on this order:
for j in 1...steps/2
temp = array[j]
array[j] = array[steps-j+1]
array[steps-j+1] = temp
end
for k in 1...(array.size-steps)/2
temp = array[steps+k]
array[steps+k] = array[array.size-k+1]
array[array.size-k+1]=temp
end
for i in 1...array.size
temp = array[i]
array[i] = array[array.size-i+1]
array[array.size-i+1] = temp
endNote: I'm more accustomed to C-style arrays, where indexes start at 0 instead of 1. I've tried to compensate appropriately, but I haven't tested this, so I wouldn't be surprised if there were still a few off-by-one errors.
This steps through the entire array twice, regardless of the size of rotation, so it's likely to be slower than yours for steps=1, about the same speed for steps = 2, and faster for steps > 2.
Code Snippets
for j in 1...steps/2
temp = array[j]
array[j] = array[steps-j+1]
array[steps-j+1] = temp
end
for k in 1...(array.size-steps)/2
temp = array[steps+k]
array[steps+k] = array[array.size-k+1]
array[array.size-k+1]=temp
end
for i in 1...array.size
temp = array[i]
array[i] = array[array.size-i+1]
array[array.size-i+1] = temp
endContext
StackExchange Code Review Q#125221, answer score: 4
Revisions (0)
No revisions yet.