【问题标题】:byte swapping/reversing a character array字节交换/反转字符数组
【发布时间】:2013-02-25 04:20:14
【问题描述】:

我正在寻找一种方法来反转字符数组中的字节。我还需要反转正在交换的字节的各个位,然后再将它们放置在正确的位置。 例如,假设我有一个 char arr[1000],其 arr[0] = 00100011 和 arr[999] = 11010110,我想交换 arr[0] 和 arr[999] 并反转它们中的每个位。所以输出将是 arr[999]= 11000100(arr[0] 的反转位)和 arr[0] = 01101011(arr[999] 的反转位)。

我有一些代码可以在一个字节内进行位反转:

static  char reverseByte(char val)
{
    char result = 0;

    int counter = 8;
    while (counter-- < 0)
    {
        result <<= 1;
        result |= (char)(val & 1);
        val = (char)(val >> 1);
    }

    return result;
}

但这意味着运行一个外部循环来进行字节交换,然后为内部的每个字节运行上面的小循环,即在上述情况下为 1000。这是正确的方法吗?有没有更好的方法来实现这一目标? 任何帮助将不胜感激。

【问题讨论】:

  • 您要优化什么以实现“高效”?这不能比O(n) 时间和空间(按位的顺序)做得更好。现在,在某些情况下,系数可能比其他情况下更好。
  • 什么?你不需要递归吗? (查找表可能是最快的。)
  • @RageD 我正在大字符数组上尝试此操作,并希望反转字节中的各个位

标签: c arrays char reverse


【解决方案1】:

这个怎么样?

#include <stdio.h>
#include <limits.h>

#if CHAR_BIT != 8
#error char is expected to be 8 bits
#endif

unsigned char RevByte(unsigned char b)
{
  static const unsigned char t[16] =
  {
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
  };
  return t[b >> 4] | (t[b & 0xF] << 4);
}

void RevBytes(unsigned char* b, size_t c)
{
  size_t i;
  for (i = 0; i < c / 2; i++)
  {
    unsigned char t = b[i];
    b[i] = RevByte(b[c - 1 - i]);
    b[c - 1 - i] = RevByte(t);
  }
  if (c & 1)
    b[c / 2] = RevByte(b[c / 2]);
}

int main(void)
{
  int i;
  unsigned char buf[16] = 
  {
    0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
    0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF
  };

  RevBytes(buf, 16);

  for (i = 0; i < 16; i++)
    printf("0x%02X ", buf[i]);
  puts("");

  return 0;
}

输出(ideone):

0xF0 0xE0 0xD0 0xC0 0xB0 0xA0 0x90 0x80 0x70 0x60 0x50 0x40 0x30 0x20 0x10 0x00

【讨论】:

    【解决方案2】:

    反转集合的元素是一个老技巧 - 你交换 first 和 last,然后 first+1 和 last-1,然后...直到 first+i 等于或比 last-j 更远。

    你需要补充的是

    -在交换它们之前翻转两个条目的位

    -如果中间还有一个元素,就当场翻转它的位

    【讨论】:

      【解决方案3】:

      要做到这一点 - 假设您的位反转方法是正确的 - 如果您可以节省额外的 char 存储空间,您可以简单地遍历字节。考虑以下方法:

      static void swapReverseBytes(char* arr, size_t len)
      {
        int i = 0;
        char tmp = 0;
        if(arr == NULL || len < 1)
          return;
        if(len == 1) {
          arr[0] = reverseByte(arr[0]);
          return;
        }
        for(i = 0 ; i < (len / 2) ; ++i) {
          tmp = arr[len - i - 1];
          arr[len - i - 1] = reverseByte(arr[i]);
          arr[i] = reverseByte(tmp);
        }
      }
      

      这是一个粗略的草图(我认为应该编译),假设我没有错误,这应该可以工作。如前所述,使用LUT 反转位可能是最快的,但字节交换将相对相似,因为您需要实际移动每个字节,除非您保留有关数组遍历顺序的某些状态。如果是这种情况,很可能简单地使用某种状态(即标志)来确定是应该正常遍历数组(1...n)还是以相反的顺序遍历数组(n...1)。无论如何,交换在 Big-O 中是“免费的”,但在实践中可能(不一定)显示出性能影响(因为不会有字节顺序的“实际”交换) .请注意,如果用户期望一个已排序的数组,这将不起作用 - 此技巧仅在这是内部的情况下才有效(或者您有某种封装,例如在 C++ 类中)。

      【讨论】:

        【解决方案4】:

        要做到这一点 - 假设您的位反转方法是正确的 - 如果您可以节省额外的 char 存储空间,您可以简单地遍历字节。考虑以下方法:

        static void swapReverseBytes(char* arr, size_t len)
        {
          int i = 0;
          char tmp = 0;
          if(arr == NULL || len < 1)
            return;
          if(len == 1) {
            arr[0] = reverseByte(arr[0]);
            return;
          }
          for(i = 0 ; i < (len / 2) ; ++i) {
            tmp = arr[len - i - 1];
            arr[len - i - 1] = reverseByte(arr[i]);
            arr[i] = reverseByte(tmp);
          }
        }
        

        这是一个粗略的草图(我认为应该编译),假设我没有错误,这应该可以工作。如前所述,使用LUT 反转位可能是最快的,但是字节交换方法将相对相似,因为您需要实际移动每个字节,除非您保留有关数组遍历顺序的某些状态。如果是这种情况,很可能简单地使用某种状态(即标志)来确定是应该正常遍历数组(1...n)还是以相反的顺序遍历数组(n...1)。无论如何,交换在 Big-O 中是“免费的”,但在实践中可能(不一定)显示出性能影响。因此,如果您的优化确实在速度上并且空间中的额外int 不是太多,那么这种状态对您来说可能是值得的。请注意,此技巧仅在这是内部的情况下才有效。如果这个方法对用户是公开的并且他或她不知道这个标志,那么这实际上不会翻转任何东西。使用它的另一个选项是,如果您可以使用C++,您可以创建一个为用户封装此功能的类。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多