跪求数字压缩算法

铁锚 2013-11-06 06:01:18
背景:
身份证号码的前17位,是数字类型的字符串:比如"53010119870615158",现在书写的时候占了17个字符,有没有办法将其压缩短一些,比如,10位之类的。

需求:
1. 可以采用十六进制,或者10进制,或者 数字和字母的组合
2. 不易区分的数字字母除外,比如: I 和 1, O 和 0 .
3. 需要生成的新字符,可以转换为原来的值(即无损).
4. 需要有稳定的生成的位数,可以在最开始补0之类的。
请各位大神提供解决方案,或者思路,或者链接都可以。
...全文
573 2 收藏 7
写回复
7 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Wei_An 2014-05-09
我的简陋思路:查表法 原理:因为身份证号码都有特殊的含义,例如行政区域,可以用查表法来进行字符串转换数字数组,对栈内存消耗减少,然后再结合以上的高手思路,或者会更加好。 个人愚见,仅供参考,谢谢!
回复
cnmhx 2013-11-09
自然地使用阿斯克码,2^8=256,相当于256进制。 身份证的17位事实上是16位(没有人的岁数超过999岁)。 这样10^16约为2^48,即使用6个256进制的阿斯克码足矣!
回复
nice_cxf 2013-11-08
直接用long long当数字存就ok了,8字节就够了,还想小的话要细分行政区域出生日期等,也许可以再少点,不过大概也省不了多少了
回复
hello_world_ww 2013-11-07
1.转换为高进制是个不错的思路,但是理论上讲即使100进制也只会将10进制数的串长度减半,所以需要考虑其他办法 2.把17为的身份证号码中间截断为8+9的形式,当做两个unsigined int类型的数按二进制形式写入文件,只需要2*4 bytes,相比于字符串存储的17bytes,压缩率超过50% 再想……
回复
无籽-西瓜 2013-11-06
16进制从0至f用每一个字符代表值,当10进制的17位数转成16位时,可以缩短到12位,你可以从0至z的这些字符都用上,扩展到26进制,也可以把ascii的字符包括进来,40进制都没问题,只要是一个单独的字符都可以用上。
回复
还有多远 2013-11-06
提供个思路,仅供参考: (1)17位身份证号末位(最右边一位)可能是X,可以保留不进行处理 (2)由于36*36 = 1296 > 1000,所以我们可以用一个36进制的两位数(最大是1295)完全表示一个10进制的3位数(最大是999),这样,我们可以把17位身份证的前15位压缩成10位(每三位压缩成两位),再直接拼接上身份证号的后2位,就成了一个12位的固定长度的身份证号(当然也可以再以某种方式处理后两位,使之变成一位) (3)设计一个36进制,例如0~9a~z,这样的话,就可以写出如下的转换:

string compressId(const string& id)
{
    int num, i, k = 0, tmp;
    string compressed(12, ' ');//预留12个字符的空间
    for(i = 0; i < 15; i += 3){
        num = (id[i]-'0')*100 + (id[i+1]-'0')*10 + (id[i+2]-'0');
        tmp = num/36; 
        num %= 36;
        compressed[k++] = tmp > 9 ? tmp-10+'a' : tmp+'0';//36进制数的高位
        compressed[k++] = num > 9 ? num-10+'a' : num+'0';//36进制数的低位
    }
    compressed[10] = id[15];
    compressed[11] = id[16];
    return compressed;
}
string retrieveId(const string& compressed)
{
    int num, i, k = 0;
    string id(17, ' ');//预留17个字符的空间
    for(i = 0; i < 10; i += 2){
        num = (compressed[i] > '9' ? compressed[i]-'a'+10 : compressed[i]-'0') * 36 +
              (compressed[i+1] > '9' ? compressed[i+1]-'a'+10 : compressed[i+1]-'0');
        id[k++] = num/100 + '0';//10进制数的百位
        num %= 100;
        id[k++] = num/10 + '0';//10进制数的十位
        num %= 10;
        id[k++] = num + '0';//10进制数的个位
    }
    id[15] = compressed[10];
    id[16] = compressed[11];
    return id;
}
回复
我也很迷茫 2013-11-06
530101198706015158 我提供一个思路吧.身份证号至少可以分成这三节. 第一节表示一个地址. 第二节表示出生日期. 第三节表示顺序号和男女性别. 我只从出生日期上来考虑. 假设你的系统能运行到2100年. 那么你的系统里人的出生年份将是[1900, 2100]这个区间. 200年而已. 将十进制的200先转为二进制. 再将二进制转为十六进制. 我们知道, 2的8次方是256, 怎么样够了吧. 也就是说, 用16进制的00~FF就可以表示1900~2100年的所有年份了. 还有剩余! 这样, 本来四位年份就变成了两位了对不对~ 我们再继续. 月份, 一年只有12个月. 用一个十六进制就搞定了.又省了一位对不对~ 日期, 最多31. 如果16进制也要两位. 好了. 然后你再去想办法搞到地址对应的身份证前6位. 肯定可以减少的. PS. 以上我是在16进制的范畴下讨论的. 如果你胆子更大一点, 完全可以用更大的进制! 0~9 A~Z a~z可用的进制大的很呢~ 16进制只是其中很小的一份. 再PS. 以上讨论是基于新身份证号的. 现在还有老身份证号. 需要一个额外的位置, 表示这是新的身份证还是老的身份证
回复
相关推荐
发帖
数据结构与算法
创建于2007-08-27

3.2w+

社区成员

数据结构与算法相关内容讨论专区
申请成为版主
帖子事件
创建了帖子
2013-11-06 06:01
社区公告
暂无公告