标准位置到双射基础转换

Standard Positional to Bijective Base Conversion

我们知道 b-based standard positional 数字系统使用数字, 0, 1, 2, ..., b-1。但是 bijective number system 使用数字,1, 2, ..., b。所以 4-based 标准数字系统序列看起来像,

0
1
2
3
10
11
12
13
20
21
22
23
30
31
32
33 (base-4, 16th number standard)
100 (base-4, 17th number standard)
101
.
.
.

另一方面,4-based 的双射数系统看起来像,

λ (base-4, 1st number, empty-string)
1
2
3
4
11
12
13
14
21
22
23
24
31
32
33 (base-4, 16th number bijective)
34 (base-4, 17th number bijective)
41 
.
.
.

示例:

34152(双射基数 5)= 3×54 + 4×53 + 1×52 + 5×51 + 2×1 = 2427(十进制)。 119A(双射基数 10,"A" 表示数字值十)= 1×103 + 1×102 + 9×101 + 10×1 = 1200(十进制)。

我想知道是否有任何简单的方法可以在相同的基础上找到 n'th 位置双射值。

例如,

让我们说 base-4 5th 位置值 = 10(标准)5th 位置值 = 11(双射)。任何伪代码都可以理解这个概念。

如果标准 base-n 系统中的数字包含 no 个零,则该数字与双射 base-n 具有相同的表示形式。

因此您需要在标准数字中查找零。当你找到一个零时,用双射中的最大符号替换它,并将元素向左递减。

简单示例:

10 decimal ->  A bijective because 0 becomes A and 1 decrements to zero
20 decimal -> 1A bijective because 0 becomes A and 2 decrements to 1

作为一种特殊情况,您必须处理零序列。

简单示例:

200 decimal ->  19A bijective (i.e. step 1: 1A0 step 2: 19A)

你也可以这样看

200 decimal is constructed as 2*100 + 0*10 + 0*1 = 200 decimal

对于双射你不能有零所以你会做:

19A bijective is constructed as 1*100 + 9*10 + 10*1 = 200 decimal

要完成更复杂一点的示例:

110 decimal ->  AA bijective (i.e. step 1: 10A step 2: AA)

这个例程实现了转换。 (解决了 @4386427 的方法。)如果你想要其他版本,其中 100 (base 4 std) -> 41 (base 4 bij') 然后用 -D NO_EMPTY_STRING

编译
#include <stdio.h>
#include <string.h>
void print_be_digits(const char *prefix, const unsigned char *le_num, size_t len)
{
  size_t i;
  printf("%s", prefix);
  for(i=0; i<len; i++)
  {
    printf("%d ", (int)le_num[len-i-1]);
  }
  printf("\n");
}

void nth_bij(int n, int k)
{
  ssize_t i;
  size_t std_len;
  size_t bij_len;
  size_t work;
  unsigned char le_std_digits[256];
  unsigned char le_bij_digits[256];

  //convert to standard radix-k digits
  work = n;
  for(std_len = 0; work; std_len++)
  {
    le_std_digits[std_len] = work % k;
    work /= k;
  }

  print_be_digits("  std: ", le_std_digits, std_len);

  //convert standard to bij
  memcpy(le_bij_digits, le_std_digits, std_len);
  bij_len = std_len;

  #ifdef NO_EMPTY_STRING
  // Step 1: increment LSd
  le_bij_digits[0]++;
  #endif

  // Step 2: borrow on zeros
  // scan back from the end
  for(i=bij_len-1; i>= 0; i--)
  {
    //if we find a zero, borrow, and ripple toward MSd as necessary
    if(le_bij_digits[i] == 0)
    {
      size_t j;

      //Ripple borrow toward MSd, as necessary
      for(j=i+1; j<bij_len; j++)
      {
        le_bij_digits[j-1] = k; //k is the radix

        if(--le_bij_digits[j])
        {
          break;
        }
      }//end ripple

      //adjust bij_len if we rippled to the end
      if(j == bij_len)
      {
        bij_len--;
      }
    }
  }//end scan
  print_be_digits("  bij: ", le_bij_digits, bij_len);
}

简单驱动程序:

int main(int argc, char *argv[])
{
  printf("Test: 16 decimal (->base 4): \n");
  nth_bij(16,4);
  printf("\n");

  printf("Test: 8 decimal (->base 2): \n");
  nth_bij(8,2);
  printf("\n");

  printf("Test: 13 decimal (->base 2): \n");
  nth_bij(13,2);
  printf("\n");

  printf("Test: 2427 decimal (->base 5): \n");
  nth_bij(2427, 5);
  printf("\n");

  printf("Test: 1200 decimal (->base 10): \n");
  nth_bij(1200, 10);
  printf("\n");
}

为我的版本编译:

$ gcc -D NO_EMPTY_STRING bij.c
$ ./a.exe
Test: 16 decimal (->base 4):
  std: 1 0 0
  bij: 4 1

Test: 8 decimal (->base 2):
  std: 1 0 0 0
  bij: 1 2 1

Test: 13 decimal (->base 2):
  std: 1 1 0 1
  bij: 2 2 2

Test: 2427 decimal (->base 5):
  std: 3 4 2 0 2
  bij: 3 4 1 5 3

Test: 1200 decimal (->base 10):
  std: 1 2 0 0
  bij: 1 1 10 1

为@4386427 的版本编译:

$ gcc bij.c
$ ./a.exe
Test: 16 decimal (->base 4):
  std: 1 0 0
  bij: 3 4

Test: 8 decimal (->base 2):
  std: 1 0 0 0
  bij: 1 1 2

Test: 13 decimal (->base 2):
  std: 1 1 0 1
  bij: 2 2 1

Test: 2427 decimal (->base 5):
  std: 3 4 2 0 2
  bij: 3 4 1 5 2

Test: 1200 decimal (->base 10):
  std: 1 2 0 0
  bij: 1 1 9 10