如何将两个数合并成一个数又能恢复回原来两个数

前言

如何将两个数合并成一个数又能恢复回原来两个数?这个问题在某次撸代码地时候忽然产生,当时没有想到如何解决,但最近忽然想到了思路,然后趁着这个五一假期实现一下。

原理

这个问题,可不能使用普通的加减乘除解决,因为即使合并得到新数,也无法恢复成之前合并前的那两个数,如 1+3=4,但是4可以有 2+2…很多种方式。
我们可以采用二进制的方式解决这个问题。

合并

假设有两个数 1,3,在计算机语言里,默认是用 int 类型存放数值,一个 int类型 有32 个位,将 13分别转成二进制可得到:0000000000000000000000000000000100000000000000000000000000000011,然后这两个值拼接起来就可以形成一个新的值,即0000000000000000000000000000000100000000000000000000000000000011,可以使用long类型保存,因为long类型有64位,刚好满足这两个值的拼接起来的长度。由此得到新值4294967299

恢复

现在需要将4294967299 恢复成 1,3,如何处理?很简单,由于42949672991,3二进制拼接起来得到的,只要将4294967299转成二进制0000000000000000000000000000000100000000000000000000000000000011,又因为1,3分别占32位,所有,以第32位[从0开始]为分界点,分别得到00000000000000000000000000000001,00000000000000000000000000000011,将其转为10进制,即可得到1,3

实现

合并

还是以1,3为例子。先初始化 result 的值为 left,由于 resultlong 类型,所以共有64位,此时 result0000000000000000000000000000000000000000000000000000000000000001。左移32位,得到0000000000000000000000000000000100000000000000000000000000000000。接着合并rightresult 的 后32位中,我们可以才有 |运算符,刚可以将值为1的位保留起来,从而得到 0000000000000000000000000000000100000000000000000000000000000011,转成10进制就得到4294967299

 /**
     * 将合并 left,right 成一个数
     * @param left 用于合并的数1
     * @param right 用于合并的数2
     * @return left,right 合并后的数
     */
    private static long mergeNum(int left, int right){
        if(left<0||right<0){
            //不支持负数合并
            throw new RuntimeException("not support negative to merge ");
        }
        long result=left;
        result<<=32;
        result|=right;
        return result;
    }

算法最大支持Integer.MAX_VALUE参数,因为Integer.MAX_VALUE 只占31位,最高位始终为0,也使得到右移时,不会因为最高位而导致补1的情况发送。参考博客
至于为什么不支持复数,因为负数的二进制需要经过反码,补码,与当前合并算法不兼容,加上没有暂时没有想到更好的算法,所以暂时不考虑这负数的情况。参考博客

恢复

还是以4294967299为例子。由上可知,4294967299是由1,3的二进制数拼接起来得到的。所以要算出 1,就是将val 右移32位补0,即可得到0000000000000000000000000000000000000000000000000000000000000001,转为二进制就是 1。最后要算出3。首先需要将高32位去除,可以才有左移方式将高32位变成低32位:0000000000000000000000000000001100000000000000000000000000000000,然后右移32位,使得高32位变成低32位,得到0000000000000000000000000000000000000000000000000000000000000011,转为二进制就是 3

/**
     * 将 val 恢复成合并前的两个数
     * @param val 合并后的数
     * @return 合并 val 前的两个数
     */
    private static int[] splitNum(long val){
        long left=val>>32;
        long right=(val<<32)>>32;
        return new int[]{Long.valueOf(left).intValue(),Long.valueOf(right).intValue()};
    }

源码

package org.example;

public class AlgorithmTest {
    public static void main(String[] args) {
        test(Integer.MAX_VALUE,Integer.MAX_VALUE);
        test(123,143);
        test(1,3);
        test(0,123);
        test(24,0);
    }

    private static void test(int left ,int right){
        System.out.println("------test["+left+","+right+"]------");
        outBinary("left",left);
        outBinary("right",right);
        long mergeNum= mergeNum(left,right);
        outBinary("mergeNum",mergeNum);
        int[] splitNums = splitNum(mergeNum);
        System.out.printf("------mergeNum=%d,splitNum=[%d,%d]\r\n",mergeNum,splitNums[0],splitNums[1]);
    }

    /**
     * 将 val 恢复成合并前的两个数
     * @param val 合并后的数
     * @return 合并 val 前的两个数
     */
    private static int[] splitNum(long val){
        long left=val>>32;
        long right=(val<<32)>>32;
        return new int[]{Long.valueOf(left).intValue(),Long.valueOf(right).intValue()};
    }

    /**
     * 将合并 left,right 成一个数
     * @param left 用于合并的数1
     * @param right 用于合并的数2
     * @return left,right 合并后的数
     */
    private static long mergeNum(int left, int right){
        if(left<0||right<0){
            //不支持负数合并
            throw new RuntimeException("not support negative to merge ");
        }
        long result=left;
        result<<=32;
        result|=right;
        return result;
    }

    /**
     * 输出 val 的二进制值信息
     * @param prefix 输出日志前缀
     * @param val 要输出二进制的值
     */
    private static void outBinary(String prefix,long val){
        System.out.println(prefix+".val="+val);
        StringBuilder sb=new StringBuilder();
        int n=Long.numberOfLeadingZeros(val);
        for (int i = 0; i < n; i++) {
            sb.append(0);
        }
        String valBinaryStr=Long.toBinaryString(val);
        sb.append(valBinaryStr);
        System.out.println(prefix+".valBinaryStr = "+valBinaryStr);
        System.out.println(prefix+".valBinaryStr.length = "+valBinaryStr.length());
        System.out.println(prefix+".sb.toString() = "+sb.toString());
        System.out.println(prefix+".sb.length() = "+sb.length());
    }
}
执行结果
------test[2147483647,2147483647]------
left.val=2147483647
left.valBinaryStr = 1111111111111111111111111111111
left.valBinaryStr.length = 31
left.sb.toString() = 0000000000000000000000000000000001111111111111111111111111111111
left.sb.length() = 64
right.val=2147483647
right.valBinaryStr = 1111111111111111111111111111111
right.valBinaryStr.length = 31
right.sb.toString() = 0000000000000000000000000000000001111111111111111111111111111111
right.sb.length() = 64
mergeNum.val=9223372034707292159
mergeNum.valBinaryStr = 111111111111111111111111111111101111111111111111111111111111111
mergeNum.valBinaryStr.length = 63
mergeNum.sb.toString() = 0111111111111111111111111111111101111111111111111111111111111111
mergeNum.sb.length() = 64
------mergeNum=9223372034707292159,splitNum=[2147483647,2147483647]
------test[123,143]------
left.val=123
left.valBinaryStr = 1111011
left.valBinaryStr.length = 7
left.sb.toString() = 0000000000000000000000000000000000000000000000000000000001111011
left.sb.length() = 64
right.val=143
right.valBinaryStr = 10001111
right.valBinaryStr.length = 8
right.sb.toString() = 0000000000000000000000000000000000000000000000000000000010001111
right.sb.length() = 64
mergeNum.val=528280977551
mergeNum.valBinaryStr = 111101100000000000000000000000010001111
mergeNum.valBinaryStr.length = 39
mergeNum.sb.toString() = 0000000000000000000000000111101100000000000000000000000010001111
mergeNum.sb.length() = 64
------mergeNum=528280977551,splitNum=[123,143]
------test[1,3]------
left.val=1
left.valBinaryStr = 1
left.valBinaryStr.length = 1
left.sb.toString() = 0000000000000000000000000000000000000000000000000000000000000001
left.sb.length() = 64
right.val=3
right.valBinaryStr = 11
right.valBinaryStr.length = 2
right.sb.toString() = 0000000000000000000000000000000000000000000000000000000000000011
right.sb.length() = 64
mergeNum.val=4294967299
mergeNum.valBinaryStr = 100000000000000000000000000000011
mergeNum.valBinaryStr.length = 33
mergeNum.sb.toString() = 0000000000000000000000000000000100000000000000000000000000000011
mergeNum.sb.length() = 64
------mergeNum=4294967299,splitNum=[1,3]
------test[0,123]------
left.val=0
left.valBinaryStr = 0
left.valBinaryStr.length = 1
left.sb.toString() = 00000000000000000000000000000000000000000000000000000000000000000
left.sb.length() = 65
right.val=123
right.valBinaryStr = 1111011
right.valBinaryStr.length = 7
right.sb.toString() = 0000000000000000000000000000000000000000000000000000000001111011
right.sb.length() = 64
mergeNum.val=123
mergeNum.valBinaryStr = 1111011
mergeNum.valBinaryStr.length = 7
mergeNum.sb.toString() = 0000000000000000000000000000000000000000000000000000000001111011
mergeNum.sb.length() = 64
------mergeNum=123,splitNum=[0,123]
------test[24,0]------
left.val=24
left.valBinaryStr = 11000
left.valBinaryStr.length = 5
left.sb.toString() = 0000000000000000000000000000000000000000000000000000000000011000
left.sb.length() = 64
right.val=0
right.valBinaryStr = 0
right.valBinaryStr.length = 1
right.sb.toString() = 00000000000000000000000000000000000000000000000000000000000000000
right.sb.length() = 65
mergeNum.val=103079215104
mergeNum.valBinaryStr = 1100000000000000000000000000000000000
mergeNum.valBinaryStr.length = 37
mergeNum.sb.toString() = 0000000000000000000000000001100000000000000000000000000000000000
mergeNum.sb.length() = 64
------mergeNum=103079215104,splitNum=[24,0]


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
个 Oracle 据库合并一个据库是可行的,但需要进行一些准备工作和注意事项,以确保合并过程顺利进行,并且不会影响到原有据库中的据和应用程序。 以下是一些可行性分析的考虑因素: 1. 据库版本和兼容性:要合并个数据库必须具有相同的 Oracle 版本和兼容性级别,以避免版本不兼容和不支持的功能或语法。 2. 据库结构和对象:要合并个数据库必须有相同的逻辑结构和对象(如表、索引、存储过程等),否则需要进行必要的调整和转换。 3. 据库大小和容量:合并后的据库需要具备足够的存储空间和处理能力,以处理个数据库中的据、对象和应用程序。 4. 据库安全性和权限:合并后的据库需要重新设置安全性和权限,以保证据的保密性和完整性,同时避免未授权的访问和修改。 5. 据库备份和恢复合并过程中需要进行备份和恢复操作,以保证据的安全性和可靠性,同时避免据丢失和损坏。 6. 据库性能和可用性:合并后的据库需要进行性能测试和优化,以确保其可用性和响应速度,同时避免性能瓶颈和故障。 综上所述,将个 Oracle 据库合并一个据库是可行的,但需要进行充分的准备和测试,以确保合并过程的顺利进行和据的安全性、完整性和可用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值