在python中旋转列表最有效的方法是什么? 现在我有这样的东西:

>>> def rotate(l, n):
...     return l[n:] + l[:n]
... 
>>> l = [1,2,3,4]
>>> rotate(l,1)
[2, 3, 4, 1]
>>> rotate(l,2)
[3, 4, 1, 2]
>>> rotate(l,0)
[1, 2, 3, 4]
>>> rotate(l,-1)
[4, 1, 2, 3]

有没有更好的办法?


当前回答

下面的方法是O(n)到位,辅助内存不变:

def rotate(arr, shift):
  pivot = shift % len(arr)
  dst = 0
  src = pivot
  while (dst != src):
    arr[dst], arr[src] = arr[src], arr[dst]
    dst += 1
    src += 1
    if src == len(arr):
      src = pivot
    elif dst == pivot:
      pivot = src

请注意,在python中,这种方法与其他方法相比效率非常低,因为它不能利用任何部分的本机实现。

其他回答

这也取决于您是想将列表移到合适的位置(改变它),还是想让函数返回一个新列表。因为,根据我的测试,像这样的东西比你的实现(添加两个列表)至少快20倍:

def shiftInPlace(l, n):
    n = n % len(l)
    head = l[:n]
    l[:n] = []
    l.extend(head)
    return l

事实上,即使在它的顶部添加l = l[:]来操作传入的列表的副本,速度仍然是原来的两倍。

各种实现,在http://gist.github.com/288272上有一些计时

可能更适合使用ringbuffer。它不是一个列表,尽管出于您的目的,它的行为可能足够像一个列表。

问题是列表上移位的效率是O(n),这对于足够大的列表来说非常重要。

在环缓冲区中移动只是更新了头的位置也就是O(1)

对于一个列表X = ['a', 'b', 'c', 'd', 'e', 'f'],并且shift值小于列表长度,我们可以如下所示定义函数list_shift()

def list_shift(my_list, shift):
    assert shift < len(my_list)
    return my_list[shift:] + my_list[:shift]

的例子,

list_shift (X, 1)返回(' b ', ' c ', ' d ', ' e ', ' f ', ' '] list_shift (X, 3)返回(' d ', ' e ', ' f ', ' ', ' b ', ' c ']

我以这个成本模型作为参考:

http://scripts.mit.edu/~6.006/fall07/wiki/index.php?title=Python_Cost_Model

切片列表和连接两个子列表的方法是线性时间操作。我建议使用pop,这是一个常数时间操作,例如:

def shift(list, n):
    for i in range(n)
        temp = list.pop()
        list.insert(0, temp)

下面的方法是O(n)到位,辅助内存不变:

def rotate(arr, shift):
  pivot = shift % len(arr)
  dst = 0
  src = pivot
  while (dst != src):
    arr[dst], arr[src] = arr[src], arr[dst]
    dst += 1
    src += 1
    if src == len(arr):
      src = pivot
    elif dst == pivot:
      pivot = src

请注意,在python中,这种方法与其他方法相比效率非常低,因为它不能利用任何部分的本机实现。