如何在c ++中将数组移到右边?

时间:2012-10-03 07:22:05

标签: c++ arrays shift

我正在尝试实现一个将对象数组移动到数组右侧的函数。我在互联网上找到的所有内容都是循环移位的实现,但这不是我想要的。如果theres实际上是空的,那么我想将元素向右移动。 假设您创建了一个对象数据包数组,其大小为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]。但这似乎不是很有效。

还有其他想法吗?

7 个答案:

答案 0 :(得分:9)

假设数组有n个元素:

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

另一种方法是不移动数组的元素,而是移动用于访问它的索引。基本上,你想要做的是添加1模数n。

答案 1 :(得分:4)

从右到左迭代数组,将元素n-1分配给元素n。当您到达第一个元素时,请为其指定null。 (无论那意味着什么)

答案 2 :(得分:2)

如果你要做很多事情(并且数组不小),可以考虑使用std::deque,因为它允许在两端有效插入和删除。然后,可以从后面弹出N null并在前面推送N null来替换N个位置的右移。您也可以使用std::rotate

答案 3 :(得分:2)

对于POD和非POD类型的任何容器(包括原始数组),请使用以下命令:

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

它适用于POD和非POD类型,因为copy_backward负责值类别,如果它是POD,那么它使用memmove(至少在gcc使用的std库中)。

随机访问迭代器的

std::advance使用简单的加法/减法。

std::fill也会像std::copy*一样照顾POD。

指针类型的

value_type()只是NULL,对于bool false,对于整数类型0等等。

数组用法:

  int* a[] = { 0, new int(1), new int(2), 0, 0, new int(3) };

  std::for_each(a, a + sizeof(a) / sizeof(*a), [](int* a) { !a ? (std::cout << "null\n") : (std::cout << *a << "\n"); });

  shiftRight(a, a + sizeof(a) / sizeof(*a), 3);
  std::cout << "-----------------------------------------------------\n";

  std::for_each(a, a + sizeof(a) / sizeof(*a), [](int* a) { !a ? (std::cout << "null\n") : (std::cout << *a << "\n"); });

按预期输出:

null
1
2
null
null
3
-----------------------------------------------------
null
null
null
null
1
2

答案 4 :(得分:1)

C ++中明显的答案是使用std::vector,在这种情况下,使用它 变得如此简单:

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

您可能还会考虑std::deque,这将允许push_front, 而不是insert。对于这种简单复制的小阵列 对象。 std::vector的简单性通常会胜出。

如果必须使用C样式数组,例如:

if ( *(end( a ) - 1) == NULL ) {
    std::copy_backwards( begin( a ), end( a ) - 1, end( a ) );
    a[0] = NULL;
}

应该这样做。

答案 5 :(得分:0)

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

循环方式有什么问题?它非常有效。例如:

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

答案 6 :(得分:0)

在C ++ 11中,我们有std::rotate

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