C++ 如何在c++;?

C++ 如何在c++;?,c++,arrays,shift,C++,Arrays,Shift,我正在尝试实现一个函数,用于将对象数组移到数组的右侧。我在互联网上发现的只是循环移位的实现,但这不是我想要的。我想把元素移到右边,如果右边有空白的话。 假设您创建了一个对象数据包数组,其大小为10 Packet* a[] = { p4 , p3 , p2 , p1, null, null, null, null, null, null } 移位功能只是将所有东西向右移位 { null ,p4 , p3 , p2 , p1, null, null, null, null, null } 在数组

我正在尝试实现一个函数,用于将对象数组移到数组的右侧。我在互联网上发现的只是循环移位的实现,但这不是我想要的。我想把元素移到右边,如果右边有空白的话。 假设您创建了一个对象数据包数组,其大小为10

Packet* a[] = { p4 , p3 , p2 , p1, null, null, null, null, null, null }
移位功能只是将所有东西向右移位

{ null ,p4 , p3 , p2 , p1, null, null, null, null, null }
在数组末尾有一个元素的情况下

{ p10, p9, p8, p7 ,p6 ,p5 ,p4 , p3 , p2 , p1}
这个函数不会改变任何东西

 { p4 , p3 , p2 , p1, null, null, null, null, null, null }
我的实现思想是将数组复制到临时数组中, 擦除原始阵列上的所有内容,然后复制到其中,但从位置[1]开始,而不是从位置[0]开始。但这似乎不是很有效


还有其他想法吗?

从右到左迭代数组,将元素
n-1
分配给元素
n
。到达第一个元素时,将
null
赋值给它。(无论这意味着什么)

您可以尝试实现一个链表,该链表允许您移动/取消移动或推/弹出元素(在这种情况下,空间将被释放)

这种循环方式有什么问题?它相当有效。例如:

bool insert(Packet *queue[], int *rear, int front, Packet *value)
{
  int tmp = (*rear+1) % MAX;
  if (tmp == front) 
    return false;

  *rear = tmp;
  queue[*rear] = value;
  return true;
}

bool delete(Packet *queue[], int rear, int *front, Packet **value) 
{
  if (*front == rear) 
    return false;

  *front = (*front+1) % MAX;
  *value = queue[*front];
  return true;
}

假设数组有n个元素:

if(a[n-1]==null){
   memmove(a+1, a, (n-1)*sizeof(Packet*));
   a[0]=null;
}

另一种方法不是移动数组的元素,而是移动用于访问它的索引。基本上,你要做的是添加1个模N.< /P> < P>如果你要做很多(而且数组不小),考虑使用,因为它允许在两端高效插入和移除。然后,将
N
位置向右移动可以替换为从后面弹出
N
nulls并在前面推
N
nulls。你也可以用它。

C++中的明显答案是使用<代码> STD::vector < /C> >,在这种情况下,它使用 变得非常简单:

if ( a.back() == NULL ) {
    a.insert( a.begin(), NULL );
    a.pop_back();
}

您也可以考虑<代码> STD::DeQue/Cuff>,这将允许<代码> PursPrdAs 而不是插入。对于这样小的数组,易于复制 物体。

std::vector
的简单性通常胜出

如果必须使用C样式的数组,则类似于:

if ( *(end( a ) - 1) == NULL ) {
    std::copy_backwards( begin( a ), end( a ) - 1, end( a ) );
    a[0] = NULL;
}
应该这样做。

对于吊舱和非吊舱类型的任何容器(包括原始阵列),请使用以下命令:

template <class Iterator, class Distance>
void shiftRight(Iterator begin, Iterator end, Distance dist)
{
    typedef typename std::iterator_traits<Iterator>::value_type value_type;
    Iterator newBegin = begin, oldEnd = end;
    std::advance(newBegin, dist);
    std::advance(oldEnd, -dist);
    std::copy_backward(begin, oldEnd, end);
    std::fill(begin, newBegin, value_type());
}
按预期产出:

null
1
2
null
null
3
-----------------------------------------------------
null
null
null
null
1
2
在C++11中,我们有


因此,如果最后一个元素已填充,是否不移动?为什么不单独检查,然后快速的<代码> STD::旋转< /代码>?标题的问题表示C,但是标签表示C++。克里斯评论中的建议仅是C++。爱德华多的答案可能是C++中的一个很差的想法,我只考虑C。请具体说明语言。是的,我同意Nathan的观点,只在CDo中使用它。你关心当你移位时,指向数组中间的指针/引用/迭代器会发生什么情况吗?这与下面的答案不同,在一些答案中,refereand的值发生变化,在一些答案中refereand的值不发生变化,在其中一个答案中(在撰写本文时),引用本身无效。
memcpy
如果对象重叠,则具有未定义的行为(这里就是这种情况)。当然,您可以使用
memmove
。如果他使用C++,那么,<代码> CopyOffeld会是更好的选择。杰姆斯,好点。我对解决方案进行了编辑,以纳入您的建议。正如@JamesKanze所说,memmove是最安全的,通过先制作临时副本来防止memcpy的未定义行为。感谢修改您的答案。@sgroh
memmove
不会复制。它所做的(通常)是比较源地址和目标地址,如果目标地址高于源地址,则从最后一个移动到第一个。(换句话说,它会根据最合适的选项自动选择
copy
copy_backward
)此外:问题有一个指针数组,可以使用
memmove
进行复制。这个答案使用
sizeof(Packet)
而不是
sizeof(Packet*)
,因此它在
Packet
对象数组上运行,而不是指针数组。如果你真的想,你可以在C++中的用户定义对象上使用<代码> MeMeXe>代码,但是只有当它们是POD(C++ 03)或是可被简单地复制的(C++ 11)时,“STD的简单::向量通常获胜”——我不知道人们经常测试这些规则。除非你计算出哪一个更慢并选择它,否则有人会指责你过早优化,但我仍然坚信:
deque
有更多的功能,所以使用它,除非你需要
vector
以获得
操作符[]
/迭代的连续性或速度。尽管我对此深信不疑,但我仍然没有真正遵循建议,我通常使用
vector
,除非我打算使用该功能(如本例中前面的insert)。@SteveJessop在实践中,我几乎只使用
std::vector
,除非存在迭代器寿命问题(这只能通过
std::list
)来解决。或者探查器会这样说。但是,在这种情况下,这确实取决于你的习惯或惯例。人们可以很容易地认为
deque
更自然,因为你想要一个
推前
。“通常胜出”实际上与我的习惯有关(代码< STD::DEQU<代码>意味着有特殊的约束)。我的理解是,问题只关于C。C++中有更简单的解决方案(见上面的帖子)。如果需要更长的向右移动,比如说10个位置,这个循环可以应用多次。如果是这样的话,这仍然是最好的方法吗?
null
1
2
null
null
3
-----------------------------------------------------
null
null
null
null
1
2
int [] values = {1, 2, 3, 4, 5};
std::rotate(
    std::begin(values),
    std::next(std::begin(values)), // the new 'top'
    std::end(values));
*std::rbegin(values) = 0;

assert(values[0] == 2);
assert(values[1] == 3);
assert(values[2] == 4);
assert(values[3] == 5);
assert(values[4] == 0);