In Place rotation C ++ Practice

时间:2009-11-11 18:48:45

标签: c++ arrays rotation

我有一个正在运行的旋转函数用于我的“items”int数组。下面的代码完成了它,除了我不必要地转移值。我试图实现“就地”轮换。我的意思是ptrs会增加或减少而不是从数组中获取值。我需要以这种方式“提升”效率水平这个方法。任何建议?

void quack::rotate(int nRotations)
{
 if ( count <= 1 ) return;
 else  // make sure our ptrs are where we want them.
 {
  intFrontPtr = &items[0].myInt;
  intBackPtr  = &items[count-1].myInt;
 }
 for (int temp = 0; nRotations != 0;)
 {
  if ( nRotations > 0 )
  {
     temp = *intFrontPtr;
    *intFrontPtr = *intBackPtr;
    *intBackPtr  = temp; // Connect temps for the rotation
   --intBackPtr; // Move left [...<-] into the array
  }
  else if ( nRotations < 0 ) 
  {
   temp = *intBackPtr;
   *intBackPtr  = *intFrontPtr;
   *intFrontPtr = temp; // Connect temps for the rotation
   ++intFrontPtr; // Move right [->...] into the array
  }
  if ( intBackPtr  == &items[0].myInt  || 
    intFrontPtr == &items[count-1].myInt ) 
  {
   intFrontPtr = &items[0].myInt; 
   intBackPtr  = &items[count-1].myInt; // need to re-set
   if ( nRotations > 0 ) nRotations--;  // Which ways did we rotate?
   else nRotations++;
  }
 }
 }

哦,是的,我正在尝试练习c ++,并且知道他们已经有许多函数可以编程执行此操作...我试图“构建我自己的”。我想我已经在语法上得到了它,但效率始终是我奋斗的地方。作为一个新手,我非常感谢对这方面的批评..

10 个答案:

答案 0 :(得分:15)

在数组中旋转元素有一个老技巧(我首先在Programming Pearls中看到它)

假设您想要通过三个元素向左旋转数组。

首先反转前三个元素,然后反转剩余的元素,然后反转整个数组。

Starting Array:
1 2 3 4 5 6 7

After reversing the first three elements
3 2 1 4 5 6 7

After reversing the remaining elements
3 2 1 7 6 5 4

Finally reverse the entire array to get the final rotated array
4 5 6 7 1 2 3

可以在适当的位置反转阵列的部分,因此您不需要任何额外的内存。

答案 1 :(得分:6)

您可以保留数据,并有一个“基本索引”成员来指示数组应该从哪里开始。然后,您需要在访问阵列时使用它来调整索引。阵列本身应该是私有的,并且只能通过进行调整的访问器函数来访问。像这样:

class quack
{
public:
    explicit quack(int size) : items(new Item[size]), size(size), base(0) {}
    ~quack() {delete [] items;}

    void rotate(int n)      {base = (base + n) % size;}
    Item &operator[](int i) {return items[(base + i) % size];}

private:
    quack(quack const&) = delete;          // or implement these if you want
    void operator=(quack const&) = delete; // the container to be copyable

    Item *items;
    int   size;
    int   base;
};

虽然我称之为RotatableArray,而不是quack

答案 2 :(得分:1)

一个接一个地进行旋转真的不是可行的方法。如果你正在进行超过2或3次旋转的任何事情,那么它的速度非常快。

编辑: 作为最后的想法......将元素放在一个(双)链接'循环'列表中(所以最终元素指向第一个),需要旋转才能将头指针移动几个元素。 (头指针是一个指针,指示循环列表中的哪个元素是开头)。

这是迄今为止在元素列表上进行旋转的最快(最简单)方法

答案 3 :(得分:1)

像往常一样,如果你真的需要物理旋转元素,那么C ++的正确答案就是使用std::rotate,这正是你想要做的。

如果必须手动实现(作为练习作业),请查看这些slides以获取John Bentley的“Programming Pearls”中的算法。

答案 4 :(得分:0)

实际上,这样做的方法是使用索引而不是指针。

int to = 0;
int from = (to + nRotations) % count;
if (to == from)
    return;

for (int i=0; i < count; i++) {
   swap(from, to);
   from = advance(from);
   to = advance(to);
}

// ...
static inline int advance(int n, int count) { return (n + 1) % count; }

答案 5 :(得分:0)

我可能有一个替代解决方案来内联旋转数组。如前所述,这种方法的工作原理如下:

,而不是颠倒元素集的旧技巧

初​​始化:

(注意q =向左移动的数量,n =数组的长度)

  1. 确定第一个源元素,位于x1 = q%n
  2. 目标元素位于x2 = 0
  3. char,ch1,是ar [x1]元素
  4. char,ch2,是ar [x2]元素
  5. 在i = 0到n-1上循环,其中n =数组的长度

    1. 使用ch1
    2. 覆盖目标元素ar [x2]
    3. 设置ch1 = ch2
    4. 设置x1 = x2
    5. 设置x2 = x2 - q
    6. 如果由于上述减法,x2为负数,则向其中添加n
    7. ch2 = ar [x2]
    8. 以下内容可能有助于解释其工作原理。

      示例,向左旋转2个字符:

      a b c d e f g

      c d e f g a b

      x1    ch1    x2    ch2
      2     c      0     a
      0     a      5     f
      5     f      3     d
      3     d      1     b
      1     b      6     g
      6     g      4     e
      4     e      2     c
      

      正如您所看到的,这需要不超过n次迭代,因此线性时间算法也可以内联旋转(除了少量临时变量之外不需要额外的存储空间)。

      这是一个实现上述算法的函数,您可以尝试一下:

      void rotate(char *ar, int q)
      {
          if (strlen(ar) < 2)
          {
              return;
          }
      
          if (q <= 0)
          {
              return;
          }
      
          char ch1;
          char ch2;
          int x1;
          int x2;
          int i;
          int n;
      
          n = strlen(ar);
      
          q %= n;
      
          if (q == 0)
          {
              return;
          }
      
          x1 = q;
          ch1 = ar[x1];
          x2 = 0;
          ch2 = ar[x2];
      
          for (i=0;i<n;i++)
          {
              ar[x2] = ch1;
              ch1 = ch2;
      
              x1 = x2;
      
              x2 -= q;
      
              if (x2 < 0)
              {
                  x2 += n;
              }
      
              ch2 = ar[x2];
          }
      }
      

答案 6 :(得分:0)

这是我通过修改代码here得到的:

template<class It>
It rotate(It begin, It const middle, It end)
{
    typename std::iterator_traits<It>::difference_type i = 0, j;
    if (begin != middle && middle != end)
    {
        while ((i = std::distance(begin, middle)) !=
               (j = std::distance(middle,   end)))
        {
            It k = middle;
            std::advance(
                k,
                std::max(typename std::iterator_traits<It>::difference_type(),
                j - i));
            std::swap_ranges(k, end, begin);
            if (i > j) { std::advance(begin, j); }
            else { std::advance(end, -i); }
        }
    }
    return std::swap_ranges(middle - i, middle, middle);
}

答案 7 :(得分:0)

以下是sdtom解决方案的代码

void rotateArray(int arr[], int low, int high)
{
    while  (low<high) {
        int temp = arr[low];
        arr[low]=arr[high];
        arr[high]=temp;
        low++;
        high--;
    }
}
void rotate (int arr[], int k,int uperLimit)
{
    rotateArray(arr,0,k);
    rotateArray(arr,k+1,uperLimit-1);
    rotateArray(arr,0,uperLimit-1);

}

答案 8 :(得分:0)

https://stackoverflow.com/q/17119000/2383578:这与此处讨论的有些相似。将数组旋转特定量。

答案 9 :(得分:0)

有很多方法可以通过d个位置进行数组旋转。

  1. 块交换算法。
  2. Juggling Algorithm。
  3. 逆转算法。
  4. 以下链接来自Programming Pearls pdf。看一下这个。用代码非常清楚地解释。

    http://www.cs.bell-labs.com/cm/cs/pearls/s02b.pdf