简体   繁体   English

C 中有数组的“位移”操作吗?

[英]Is there a “bit shifting” operation in C for arrays?

In C we can use a left bit shift to move each digit of a number's binary representation to the left by one space which is regarded to be O(1) time.在 C 中,我们可以使用左移将数字的二进制表示的每个数字向左移动一个空格,这被认为是 O(1) 时间。 For example, 0010 << 1 = 0100例如, 0010 << 1 = 0100

Is there a similar function/operation in C that can do this for arrays in O(1) time? C 中是否有类似的函数/操作可以在 O(1) 时间内对数组执行此操作? For example, [1, 2, 3, 4, 5] shifted by one space gives [2, 3, 4, 5, 0].例如,将 [1, 2, 3, 4, 5] 移动一个空格得到 [2, 3, 4, 5, 0]。

One way that came to my mind was by using memcpy() like this:我想到的一种方法是使用memcpy()像这样:

int arr1[] = {1, 2, 3, 4, 5};
memcpy(arr1, arr1+1, 4*sizeof(int));

for(int i=0 ; i<5 ; i++)
{
        printf("%d ", arr1[i]);
}

Output: 2, 3, 4, 5, 5输出:2、3、4、5、5

The only problem with this is that, I guess memcpy() isn't exactly O(1).唯一的问题是,我猜memcpy()不完全是 O(1)。 I was hoping that might be some low-level function/method in C that can manipulate memory quickly to achieve this, but I haven't been able to find anything while googling so far.我希望这可能是 C 中的一些低级函数/方法,可以快速操纵内存来实现这一点,但到目前为止我在谷歌搜索时找不到任何东西。

Edit: On searching, I found out that bit shifting uses a special circuit which probably allows the shifting operation to be much faster than something like memcpy .编辑:在搜索时,我发现位移使用了一个特殊的电路,它可能允许位移操作比memcpy东西快得多。 This leads to my question of whether there is a way to represent the array as a string of bits and perform traditional bit shifting on that bit string?这引出了我的问题,是否有一种方法可以将数组表示为位串并对该位串执行传统的位移位?

Edit 2 : I know what I'm trying to achieve cannot be done in literal O(1) time.编辑 2 :我知道我想要实现的目标无法在 O(1) 时间内完成。 I would be satisfied by any answers that suggest how I could improve the speed of shifting the array so that it somewhat seems like an O(1) operation (even though it actually isn't).我会对任何建议我如何提高移动数组速度的答案感到满意,以便它看起来有点像 O(1) 操作(即使它实际上不是)。

Is there a similar function/operation in C that can do this for arrays in O(1) time? C 中是否有类似的函数/操作可以在 O(1) 时间内对数组执行此操作? For example, [1, 2, 3, 4, 5] shifted by one space gives [2, 3, 4, 5, 0].例如,将 [1, 2, 3, 4, 5] 移动一个空格得到 [2, 3, 4, 5, 0]。

No. But you can produce the same result by just storing an offset and using modulo accesses不。但是您可以通过仅存储偏移量并使用模访问来产生相同的结果

struct array {
  int offset;
  int size;
  int elems[];
};

struct array* alloc_array(int size)
{
  struct array *a = malloc(sizeof(struct array) + sizeof(int)*size);
  a->offset = 0;
  a->size = size;
  return a;
}

/* Constant-time shift!
   Just use shiftleft with a negative distance to shift right */
void shiftleft(struct array *a, int distance)
{
  a->offset += distance;
}

/* Note we actually made each of our N element accesses slightly more expensive.
   However, that was already linear (ie, when you print all elements)
   so we still have the desired asymptotic complexity.
*/
int elem(struct array *a, int idx)
{
  return a->elems[(idx + a->offset) % a->size];
}

NB.注意。 This is totally un-tested, it's just a sketch so you get the idea.这是完全未经测试的,它只是一个草图,所以你明白了。 Also, I've assumed you actually want an element shift, since that's what you showed.另外,我假设您实际上想要元素转换,因为这就是您所展示的。 If you want to shift an array N bits to the left, it's a little more involved.如果您想将数组左移 N,则涉及更多。


I found out that bit shifting uses a special circuit我发现位移位使用了一个特殊的电路

PS.附注。 This "special circuit" is one of the CPU's built-in operations which operates in constant time on a fixed-size register.这个“特殊电路”是 CPU 的内置操作之一,它在固定大小的寄存器上以恒定时间运行。 The register size is baked into the CPU hardware.寄存器大小已融入 CPU 硬件。 The size of a C int is chosen to match the CPU register size.选择 C int的大小以匹配 CPU 寄存器大小。

There is no way of performing a constant-time (per register) operation on N register-sized integers (for example) that doesn't take N times as long, so obviously it has linear complexity.没有办法对 N 个寄存器大小的整数(例如)执行不需要 N 倍长的常数时间(每个寄存器)操作,因此显然它具有线性复杂性。


I know what I'm trying to achieve cannot be done in literal O(1) time.我知道我想要实现的目标无法在 O(1) 时间内完成。

Well, asymptotic complexity is only relevant if the number of elements varies.好吧,渐近复杂性仅在元素数量变化时才相关。 If you always operate on arrays of fixed size, even an operation that's linear with the number of elements is constant-time per array.如果您总是对固定大小的数组进行操作,那么即使是与元素数量成线性关系的操作也是每个数组的常数时间。

  • Edit - please stop saying that编辑- 请停止说

    bit-shifting in integers are considered O(1) time since they are so fast, even though they actually aren't O(1)整数中的位移被认为是 O(1) 时间,因为它们非常快,即使它们实际上不是 O(1)

    1. I said it was constant time because it is , assuming a modern ALU with a barrel shifter我说它是恒定时间,因为它,假设一个带有桶形移位器的现代ALU

    2. if it wasn't constant-time, there is no value of "so fast" that would induce me to call it constant-time unless it always took the same number of clock cycles in practice (including reciprocal throughput).如果它不是恒定时间,则没有“如此快”的价值会促使我称其为恒定时间,除非它在实践中总是采用相同数量的时钟周期(包括互惠吞吐量)。 Since there's no practical way to measure when within a single clock cycle it completed, this is a distinction with no practical difference.由于没有实用的方法来测量它在单个时钟周期内何时完成,因此这是一个没有实际区别的区别。

    Again, speed and asymptotic complexity are orthogonal.同样,速度和渐近复杂度是正交的。 There is no sufficiently small coefficient for an O(N) operation to be considered O(1).对于 O(N) 运算来说,没有足够小的系数被视为 O(1)。 There is of course a sufficiently small value of N , which I mentioned below (but you have declined to bound N in your question).当然, N 的值足够小,我在下面提到过(但您拒绝在您的问题中绑定 N )。

If you always operate on arrays of variable but bounded size, you can sort of make the same claim, although if your effective array size covers multiple orders of magnitude it won't be very persuasive.如果您总是对可变但有界大小的数组进行操作,那么您可以做出同样的声明,尽管如果您的有效数组大小涵盖多个数量级,则不会很有说服力。

I would be satisfied by any answers that suggest how I could improve the speed of shifting the array so that it somewhat seems like an O(1) operation (even though it actually isn't).我会对任何建议我如何提高移动数组速度的答案感到满意,以便它看起来有点像 O(1) 操作(即使它实际上不是)。

That makes literally no sense.这完全没有意义。 Asymptotic complexity is not a measure of speed , and optimizing speed has no effect on asymptotic complexity.渐近复杂度不是速度的度量,优化速度对渐近复杂度没有影响。

As said in the comments, you should use memmove instead of memcpy as the source and destination overlap.正如评论中所说,您应该使用 memmove 而不是 memcpy 作为源和目标重叠。

Another problem in your code is that you assume that there will be a "0" after your initialized array that you are free to use.您的代码中的另一个问题是您假设在您可以自由使用的初始化数组之后会有一个“0”。

memmove and memcpy will probably need O(n) time, quicker would be a code something like this: memmove 和 memcpy 可能需要 O(n) 时间,更快的代码是这样的:

int arr1[] = {1, 2, 3, 4, 5, 0};
int *arr2 = &arr1[1];

for(int i=0 ; i<5 ; i++)
{
        printf("%d ", arr2[i]);
}

The cheap way is to not move large amounts of memory around, but just manipulate the index.便宜的方法是移动大量内存,而只是操作索引。


#include <stdio.h>

int main(void)
{
int arr1[] = {1, 2, 3, 4, 5};
int ii, jj;

for(ii=0 ; ii<5 ; ii++)
        {
        jj = (ii<4) ? ii+1 : ii;

        printf("%d ", arr1[jj] );
        }

printf("\n" );
return 0;
}

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

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