C++ 如何在c++;?
我正在尝试实现一个函数,用于将对象数组移到数组的右侧。我在互联网上发现的只是循环移位的实现,但这不是我想要的。我想把元素移到右边,如果右边有空白的话。 假设您创建了一个对象数据包数组,其大小为10C++ 如何在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 } 在数组
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的未定义行为。感谢修改您的答案。@sgrohmemmove
不会复制。它所做的(通常)是比较源地址和目标地址,如果目标地址高于源地址,则从最后一个移动到第一个。(换句话说,它会根据最合适的选项自动选择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);