原地旋转 C++实践

发布于 2024-08-11 05:47:34 字数 1245 浏览 2 评论 0 原文

我有一个适用于我的“items”int 数组的工作旋转函数。下面的代码完成了它,只是我不必要地传输了值。我试图实现“就地”旋转。我的意思是,ptr 会递增或递减,而不是从数组中获取值。我需要以这种方式“提高”此方法的效率级别。有什么建议吗?

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++,并且知道它们有许多函数,这些函数已经被编程为可以执行此操作...我正在尝试“构建我自己的”。我想我已经在语法上把它写下来了,但效率始终是我挣扎的地方。作为一个新手,我非常感谢对这方面的批评。

I have a working rotating function going for my "items" int array. The code below gets it done, except that im transferring values out unnecessarily. Im trying to acheive the "inplace" rotation. What I mean by that is where the ptrs would increment or decrement instead of grabbing values out of the array..By which I need to "up" the efficiency level in that way for this method..Any Suggestions?

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++;
  }
 }
 }

Oh yes, Im trying to practice c++ and know their are many functions floating around that are programmed to do this already...Im trying to "build my own". I think i've got it down syntactically, but the efficiency is always where i struggle. As, a novice, I would greatly appreciate critisim towards this aspect..

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

有深☉意 2024-08-18 05:47:34

有一个旋转数组中元素的老技巧(我第一次在编程珍珠中看到它)

假设您想将数组向左旋转三个元素。

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

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

可以就地反转数组的部分,因此不需要任何额外的内存。

There is an old trick for rotating elements in an array (I first saw it in Programming Pearls)

Say you want to rotate an array to the left by three elements.

First reverse the first three elements, next reverse the remaining elements, and then reverse the entire array.

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

Reversing portions of the array can be done in place so you don't need any extra memory.

司马昭之心 2024-08-18 05:47:34

您可以将数据保留在适当的位置,并使用“基本索引”成员来指示数组应从何处开始。然后,您需要在访问数组时使用它来调整索引。数组本身应该是私有的,并且只能通过进行调整的访问器函数来访问。像这样的东西:

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

You can leave the data in place, and have a "base index" member to indicate where the array should start. You then need to use this to adjust the index when accessing the array. The array itself should be private, and only accessed through accessor functions that do the adjustment. Something like this:

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;
};

although I'd call it something like RotatableArray, rather than quack.

是伱的 2024-08-18 05:47:34

像往常一样,如果您确实必须物理旋转元素,那么 C++ 的正确答案是使用 std::rotate,它正是您想要做的。

如果您必须手动实现它(作为练习作业),请查看这些 幻灯片

As usual, if you really have to physically rotate the elements, the correct answer for C++ would be to use std::rotate, which does exactly what you want to do.

If you have to implement it manually (as a practice assignment), take a look at these slides for algorithms from John Bentley's "Programming Pearls".

信仰 2024-08-18 05:47:34

一项一项地轮换确实不是办法。如果你做的事情超过 2 或 3 圈,它就会变得非常慢非常快。

编辑:
作为最后的想法...将元素放入(双)链接的“循环”列表中(因此最后一个元素指向第一个),将需要旋转以仅将头指针移动几个元素。 (头指针是指示循环列表中哪个元素是开始的指针)。

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

doing the rotations one by one is really not the way to go. If you are doing anything more than 2 or 3 rotations it gets really slow really quick.

edit:
as a final thought... putting the elements in a (double) linked 'looped' list (so the final element points to the first), would require for a rotate to only move the head pointer a few elements. (The head pointer being a pointer to indicate which element in the looped list is the beginning).

this is by far the quickest (and easiest) way to do a rotate on a list of elements

一场春暖 2024-08-18 05:47:34

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

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; }

Really the way to do it is to use indexes instead of pointers.

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; }
墟烟 2024-08-18 05:47:34

我可能有另一种解决方案来内联旋转数组。这种方法不像之前提出的那样采用反转元素集的老技巧,而是按如下方式工作:

初始化:(

注意 q = 左移量,n = 数组长度)

  1. 确定第一个源元素,该元素位于 x1= q%n
  2. 目标元素位于 x2=0 处
  3. char, ch1 是 ar[x1] 元素
  4. char, ch2 是 ar[x2] 元素

在 i=0 到 n-1 上循环,其中 n = 数组长度

  1. 覆盖目标元素 ar[x2] 与 ch1
  2. Set ch1 = ch2
  3. Set x1 = x2
  4. Set x2 = x2 - q
  5. 如果 x2 由于上述减法而为负,则向其添加 n
  6. ch2 = ar[x2]

以下内容可能有助于解释如何进行这有效。

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

abcdefg

cdefgab

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];
    }
}

I may have an alternate solution to rotating the array inline. Rather than the old trick of reversing sets of elements, as proposed earlier, this approach works as follows:

Initialization:

(Note q = amount to shift left, n = length of array)

  1. Determine the first source element, which is located at x1=q%n
  2. The destination element is at x2=0
  3. char, ch1, is the ar[x1] element
  4. char, ch2, is the ar[x2] element

Loop on i=0 to n-1, where n = length of array

  1. Overwrite the destination element, ar[x2] with ch1
  2. Set ch1 = ch2
  3. Set x1 = x2
  4. Set x2 = x2 - q
  5. If x2 is negative due to the above subtraction, add n to it
  6. ch2 = ar[x2]

The following may help explain how this works.

Example, rotate to the left by 2 characters:

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

As you can see, this requires no more than n iterations, so it is linear time algorithm that also rotates inline (requires no additional storage other than the few temporary variables).

Here is a function that implements the above algorithm so you can try it out:

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];
    }
}
笑看君怀她人 2024-08-18 05:47:34

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

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);
}

Here's one that I got by modifying the code 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);
}
喜你已久 2024-08-18 05:47:34

这是 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);

}

Here is code for sdtom solution

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);

}
〆凄凉。 2024-08-18 05:47:34

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

https://stackoverflow.com/q/17119000/2383578 : This is somewhat similar to what is discussed here. Rotating the array by a particular amount.

倾城月光淡如水﹏ 2024-08-18 05:47:34

有很多方法可以按 d 位进行数组旋转。

  1. 块交换算法。
  2. 杂耍算法。
  3. 反转算法。

下面的链接来自Programming Pearls pdf。看看这个。用代码解释的非常清楚。

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

There are many ways to do array rotation by d places.

  1. Block swap algorithm.
  2. Juggling Algorithm.
  3. Reversal Algorithm.

The link below is from Programming Pearls pdf. Check this out. Explained very clearly with code.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文