简体   繁体   English

转换数组C ++中的元素

[英]Shifting elements in an array C++

I've developed a method called "rotate" to my stack object class. 我已经为我的堆栈对象类开发了一种称为“旋转”的方法。 What I did was that if the stack contains elements: {0,2,3,4,5,6,7} I would needed to rotate the elements forwards and backwards. 我要做的是,如果堆栈包含元素:{0,2,3,4,5,6,7}我需要向前和向后旋转元素。

Where if i need to rotate forwards by 2 elements, then we would have, {3,4,5,6,7,0,2} in the array. 如果我需要向前旋转2个元素,那么数组中将有{3,4,5,6,7,0,2}。 And if I need to rotate backwards, or -3 elements, then, looking at the original array it would be, {5,6,7,0,2,3,4} 而且如果我需要向后旋转或-3个元素,那么,看一下原始数组,它就是{5,6,7,0,2,3,4}

So the method that I have developed works fine. 因此,我开发的方法效果很好。 Its just terribly ineffecient IMO. IMO效率极低。 I was wondering if I could wrap the array around by using the mod operator? 我想知道是否可以使用mod运算符将数组包装起来? Or if their is useless code hangin' around that I havent realized yet, and so on. 或者,如果它们是我没意识到的无用的代码,'等等。

I guess my question is, How can i simplify this method? 我想我的问题是,如何简化这种方法? eg using less code. 例如使用更少的代码。 :-) :-)

void stack::rotate(int r)
{
    int i = 0;
    while ( r > 0 ) // rotate postively.
    {
        front.n = items[top+1].n;
        for ( int j = 0; j < bottom; j++ )
        {
            items[j] = items[j+1];                                  
        }
        items[count-1].n = front.n;
        r--;
    }

    while ( r < 0 )  // rotate negatively.
    {
        if ( i == top+1 )
        {
            front.n = items[top+1].n;  
            items[top+1].n = items[count-1].n; // switch last with first
        }

        back.n = items[++i].n; // second element is the new back
        items[i].n = front.n; 
        if ( i == bottom )
        {
            items[count-1].n = front.n; // last is first
            i = 0;  
            r++;   
            continue;
        }
        else
        {
            front.n = items[++i].n;
            items[i].n  = back.n;
            if ( i == bottom )
            {
                i = 0;
                r++; 
                continue;
            }
        }
    }
}

Instead of moving all the items in your stack, you could change the definition of 'beginning'. 您可以更改“开始”的定义,而不是移动堆栈中的所有项目。 Have an index that represents the first item in the stack, 0 at the start, which you add to and subtract from using modular arithmetic whenever you want to rotate your stack. 有一个索引,该索引代表堆栈中的第一项,开始时为0,每当您要旋转堆栈时,就可以使用模块化算术对该索引进行加减。

Note that if you take this approach you shouldn't give users of your class access to the underlying array (not that you really should anyway...). 请注意,如果您采用这种方法,则不应授予您的类用户对基础数组的访问权限(无论如何,您实际上不应……)。

Well, as this is an abstraction around an array, you can store the "zero" index as a member of the abstraction, and index into the array based on this abstract notion of the first element. 好吧,由于这是围绕数组的抽象,因此您可以将“零”索引存储为抽象的成员,并根据第一个元素的抽象概念将索引存储到数组中。 Roughly... 大致...

class WrappedArray
{
  int length;
  int first;
  T *array;

  T get(int index)
  {
    return array[(first + index) % length];
  }

  int rotateForwards()
  {
    first++;
    if (first == length)
      first = 0;
  }
}

You've gotten a couple of reasonable answers, already, but perhaps one more won't hurt. 您已经获得了几个合理的答案,但是也许再也不会感到伤害。 My first reaction would be to make your stack a wrapper around an std::deque, in which case moving an element from one end to the other is cheap (O(1)). 我的第一个反应是使您的堆栈成为std :: deque的包装,在这种情况下,将元素从一端移动到另一端很便宜(O(1))。

What you are after here is a circular list. 您需要的是一份通函。
If you insist on storing items in an array just use top offset and size for access. 如果您坚持将项目存储在数组中,请使用顶部偏移量和大小进行访问。 This approach makes inserting elements after you reached allocated size expensive though (re-allocation, copying). 尽管达到分配的大小后,这种方法使插入元素变得昂贵(重新分配,复制)。 This can be solved by using doubly-linked list (ala std::list) and an iterator, but arbitrary access into the stack will be O(n). 这可以通过使用双向链表(ala std :: list)和迭代器来解决,但是对堆栈的任意访问将是O(n)。

现在,通常的“已经在Boost中”答案:有一个Boost.CircularBuffer

If for some reason you'd prefer to perform actual physical rotation of array elements, you might find several alternative solutions in "Programming Pearls" by Jon Bentley (Column 2, 2.3 The Power of Primitives ). 如果由于某种原因您希望对数组元素进行实际的物理旋转,则可以在Jon Bentley的“ Programming Pearls”(第2栏,第2.3章“原始函数的力量” )中找到几种替代解决方案。 Actually a Web search for Rotating Algorithms 'Programming Pearls' will tell you everything. 实际上,通过Web搜索Rotating Algorithms 'Programming Pearls'可以告诉您所有信息。 The literal approach you are using now has very little practical value. 您现在使用的文字方法几乎没有实际价值。

If you'd prefer to try to solve it yourself, it might help to try looking at the problem differently. 如果您想自己解决问题,尝试以不同的方式看待问题可能会有所帮助。 You see, "rotating an array" is really the same thing as "swapping two unequal parts of an array". 您会看到,“旋转数组”与“交换数组中两个不相等的部分”实际上是一样的。 Thinking about this problem in the latter terms might lead you to new solutions :) 在后面的术语中考虑此问题可能会导致您找到新的解决方案:)

For example, 例如,

  • Reversal Approach . 逆转法 Reverse the order of the elements in the entire array. 颠倒整个数组中元素的顺序。 Then reverse the two parts independently. 然后独立地反转两个部分。 You are done. 大功告成

For example, let's say we want to rotate abcdefg right by 2 例如,假设我们要将abcdefg向右旋转2

abcde fg -> reverse the whole -> gf edcba -> reverse the two parts -> fg abcde ABCDE fg - > 扭转整个 - > gf EDCBA - > 扭转两个部分组成 - > fg ABCDE

PS Slides for that chapter of "Programming Pearls". PS针对“ Programming Pearls”这一章的幻灯片 Note that in Bentley's experiments the above algorithm proves to be quite efficient (among the three tested). 请注意,在Bentley的实验中,上述算法被证明是非常有效的(在所测试的三个算法中)。

The function rotate below is based on reminders (do you mean this under the 'mod' operation?) 下面的rotate功能基于提醒(您的意思是在“ mod”操作下吗?)

It is also quite efficient. 这也是非常有效的。

// Helper function.
// Finds GCD. 
// See http://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations
int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}

// Number of assignments of elements in algo is
// equal to (items.size() + gcd(items.size(),r)).
void rotate(std::vector<int>& items, int r) {
  int size = (int)items.size();
  if (size <= 1) return; // nothing to do
  r = (r % size + size) % size; // fits r into [0..size)
  int num_cycles = gcd(size, r);
  for (int first_index = 0; first_index < num_cycles; ++first_index) {
    int mem = items[first_index]; // assignment of items elements
    int index = (first_index + r) % size, index_prev = first_index;
    while (index != first_index) {
      items[index_prev] = items[index]; // assignment of items elements
      index_prev = index;
      index = (index + r) % size;
    };
    items[index_prev] = mem; // assignment of items elements
  }
}

Of course if it is appropriate for you to change data structure as described in other answers, you can obtain more efficient solution. 当然,如果如其他答案中所述适合更改数据结构,则可以获得更有效的解决方案。

I don't understand what the variables front and back mean, and why you need .n . 我不明白什么是变量frontback的意思是,为什么你需要.n Anyway, this is the shortest code I know to rotate the elements of an array, which can also be found in Bentley's book. 无论如何,这是我知道的旋转数组元素的最短代码,也可以在Bentley的书中找到。

#include <algorithm>

std::reverse(array    , array + r   );
std::reverse(array + r, array + size);
std::reverse(array    , array + size);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM