将数字编码为可排序字符串的节省空间的方法

时间:2015-02-09 16:02:57

标签: string algorithm sorting

从整数列表开始,任务是将每个整数转换为字符串,以便在按字典顺序排序时,生成的字符串列表将按数字顺序排列。

这是必需的,以便只能对字符串进行排序的特定系统将生成按数字顺序的输出。

示例:

给出整数

1, 23, 3

我们可以像这样将字符串转换为字符串:

"01", "23", "03"

以便在排序时变为:

"01", "03", "23"

这是正确的。错误的结果是:

"1", "23", "3"

因为该列表按"字符串顺序"排序,而不是按数字顺序排序。

我正在寻找比简单的零填充方案更高效的东西。为了覆盖所有可能的32位整数,我们需要填充到10位数,这是低效的。

3 个答案:

答案 0 :(得分:4)

由于A的ASCII码大于9,因此您可以将它们编码为十六进制字符串。

整数

1, 23, 3

可以编码为

00000001, 00000017, 00000003

和32位整数始终可以编码为8个字符的字符串。 (假设未签名)

答案 1 :(得分:4)

TL; DR

根据数字的数量级(OM)和其他字符对数字进行编码,以便根据需要对数字进行排序:jj-a123将被编码为zjzjz-zaC1B2A3

更长的解释

这在某种程度上取决于最终将用于排序的排序算法以及人们希望如何根据字母和数字对任何给定的标点符号进行排序,但如果它是" ascii- betical"或类似的,你可以编码一个数字的每个数字来表示它在数字中的数量级(OM),同时编码其他字符,以便它们根据你想要的排序顺序排序。

为简单起见,我建议开始使用" high"编码每个非数字字符。值(例如小写z或甚至~,如果最终值为ASCII),以便在编码数字后排序。然后缓存遇到的每个数字,直到遇到另一个非数字,然后使用表示其OM的值对每个缓存的数字进行编码。如果在非数字之间遇到数字12945,则输出E以编码OM为5,然后输出该数字量级的数字1,然后输出下一个OM 4(D)及其相关数字2。继续,直到刷新所有数字,然后继续使用非数字。

非数字将被单独处理并相对于数字的OM进行排名。如果他们希望他们排序"以上"数字(可能是空格字符或某些其他被认为特殊的字符)它们将通过预先设置一个低值字符(如空格字符,如果最终值将被处理并按ASCII分类)进行编码。当/如果遇到另一个数字,一旦所有连续的数值被缓存,就开始根据OM开始缓存和编码。

或者,以相反的顺序处理字符串将排除除了单个"它是否为数字之外需要缓存数字?"测试和"是数字的最后一个字符?"测试。如果第一个不是真的,那么使用(#?)中的一个"非数字" OM字符。如果第一次测试为真,那么使用最低的OM"数字"字符(我的示例中为A)。如果两个测试均为真,则在使用前增加您的OM字符(A - > BE - > F)。

可以应用某些级别的附加过滤 - 甚至是翻译。如果想要允许基于罗马数字的精确排序,可以将它们编码为具有适当OM的十进制(或甚至十六进制)数字。

将小数点(句号或逗号,取决于)视为实际小数分隔符,并且与其他标点符号不同可能超出此编码方案的真实效用,因为字母数字字段很少使用句点或逗号作为小数分隔符。如果希望以这种方式使用它们,算法将简单地检测小数分隔符(在数字之间适当的句点或逗号)并且不将该分隔符之后的数字部分编码为除正常文本之外的任何数字部分。在正常的基于ASCII的排序中,小数部分实际上是正确排序的,因为更多的数字表示更高的精度 - 而不是更大的数量。

实施例

non-encoded                 encoded
-----------                 -------
12345                       E1D2C3B4A5
a100                        zaC1B0A0
a20                         zaB2A0
a2000                       zaD2C0B0A0
x100.5                      zxC1B0A0z.A5
x100.23                     zxC1B0A0z.B2A3
1, 23, 3                    A1z,z B2A1z,z A3
1, 2, 3                     A1z,z A2z,z A3
1,2,3                       A1z,A2z,A3

潜在优势

稍微超出简单的数字排序,这种编码方法的一些优点是灵活性的几个方面,最终有效的排序顺序 - 你实际上是为每个字符编码一个类别 - 数字根据他们的位置获得一个类别/ em>在更大的数字字符串中称为数字,而其他字符只是按正常方式排序(例如ASCII),但数字后排序。应在数字或其他订单之前排序的任何例外都在一个或多个其他类别中。 ASCII可以有效地重新编码,以非ASCII方式排序:

  • 您可以对小写字母进行编码,以便在大写字母之前或之后进行排序。要切换大小写和大写,请使用y编码小写字母,使用z编写大写字母。对于不区分大小写的排序,使用相同的编码字符对Aa进行分类会在Bb之前对它们进行排序,但{{1}尽管如此,总是会在A
  • 之前排序
  • 如果您希望扩展ASCII字符(例如使用变音符号)与其ASCII表兄弟一起排序,则可以编码aÀÁÂ,{{ 1}},ÃÄ以及Å使用Æ作为OM字符,编码AaB CÇbEÈÉ {{1}同样的类别内排序顺序警告仍然适用,并且需要对像资本Eth这样的字符做出一些决定,并且在某种程度上需要像Thorn和Sharp S(Ê,{{1关于他们是否会根据外观或发音的相似性进行排序,或者更确切地说,或许是按字母顺序排序。
  • 。}和Ë
  • 基本上是人类可读的小优势,努力

注意事项

虽然这允许许多类别'要定义的字符,请务必记住,数字的每个数量级都是它自己的类别 - 您需要知道数据不会包含OM中大于250的数字,具体取决于您希望的其他类别数量定义(ASCII c保留用于存储字符串,并且至少需要一个其他字符来表示"不是数字" - 至少对于字母数字数据 - 最多可能是254个订单但是,对于我能想象到的任何情况,这应该是充足的。我不确定量子计算会带来什么其他问题,但它可能是一个量子解决方案,无论它是什么。

最后,如果连字符被编码为非数字字符,并且所有非数字编码的OM都高于数字,则负数将被编码为大于任何正数。如果负数需要根据幅度正确排序,则连字符应编码为低于数字的OM(可能仅在数字前面)。

答案 2 :(得分:2)

对于整数,在每个数字前加上长度。为了使其更具可读性,请使用'长度为1,' b'长度为2.示例:

non-encoded  encoded
1            "a1"
3            "a3"
23           "b23"

此方案比为每个数字添加前缀稍微简单一些,但仅适用于数字,而不适用于与文本混合的数字。它也可以用于负数,甚至BigDecimal数,也可以使用一些技巧。我写了an implementation in Apache Jackrabbit 2.x,使BigDecimal可索引(可排序)为文本。为此,我使用了一种仅使用字符' 0'到' 9'并包括:

  • 一个字符:signum(value)+ 2
  • 一个字符:signum(指数)+ 2
  • 一个字符:长度(指数) - 1
  • 多个字符:exponent
  • 多个字符:value(反转为-1)

如果值为零,则仅对符号进行编码。如果为零,则不对指数进行编码。负值被反转"逐个字符(0 => 9,1 => 8,依此类推)。这同样适用于指数。

示例:

non-encoded  encoded
0            "2"
2            "322" (signum 1; exponent 0; value 2)
120          "330212" (signum 1; exponent signum 1, length 1, value 2; value 12)
-1           "179" (signum -1, rest inverted; exponent 0; value 1 (-1, inverted))

支持BigDecimal(BigInteger.ONE,Integer.MIN_VALUE)和BigDecimal(BigInteger.ONE,Integer.MAX_VALUE)之间的值。