精华内容
下载资源
问答
  • 使用二进制表示数据状态

    千次阅读 2020-04-30 14:51:44
    使用二进制的方式来表示数据状态(支持无顺序状态) 文章目录使用二进制的方式来表示数据状态(支持无顺序状态)1. 背景介绍2. 通过一个案例引发思考2.1 当签章有顺序时,我们是如何设计的?2.2 当签章顺序无法控制...

    使用二进制的方式来表示数据状态(支持无顺序状态)

    1. 背景介绍

    我将分享一个案例,引发思考。该方案拥有多种解决方案,所以各有优势,也各有缺点,读者自行思考,自行选择解决方案,我主要想给大家分享 “使用二进制的方式表示数据状态” 这一类解决方案。下面,我将提出一个案例,大家可以想一下可以用何种方式来解决这个问题。

    2. 通过一个案例引发思考

    我们在大学实习的时候,肯定是需要签订《三方协议》的,该协议涉及三方,即:“学校”、“自己”、“实习公司”,我们将这三方假设为三个用户。
    在这里插入图片描述
    我们在签订三方协议的时候,是没有签订顺序的,谁都可以先盖章签字。那么,在这种背景下,我们可以如何设计我们的系统,来表示这种无顺序的状态呢?

    2.1 当签章有顺序时,我们是如何设计的?

    如果《三方协议》的签订是有顺序的,假设顺序为 “自己” --> “实习公司” --> “学校”。那么我们会如何设计?
    其实,一张表即可完成设计

    contract_id sign_status
    1 0

    contract_id :三方协议合同id
    sign_status:合同签订状态:0-未签订、1-学生已签订、2-实习公司已签订、3-学校已签订

    当状态为 3 的时候,即可认定为该合同已签订完毕。这就是有顺序的设计方式。

    但是我们生活中的签订,却是无顺序的。

    2.2 当签章顺序无法控制时,我们是如何设计的?

    由于我们无法控制谁先签,谁后签,所以原本的设计方案就不可行了。
    使用二进制表示状态,是什么意思?

    我们有 3 个用户,对应二进制 000 ,若有一方签订了,则将属于他的那个 0 设置为 1 ,即可表示该用户已签订。假设二进制的 3 个 0 ,从左到右分别对应:学校、实习公司、学生。此时的二进制状态为 000 ,数据库存储的十进制状态为 0 ,代表未签订状态。

    contract_id sign_status
    1 0

    contract_id :三方协议合同id
    sign_status:合同签订状态:000-未签订、001-学生已签订、010-实习公司已签订、100-学校已签订

    在这里插入图片描述

    接着,假设学生第一个签章了,那么就将属于学生的那个 0 ,改为 1 ,此时的二进制状态为 001,对应数据库十进制状态为 1 ,代表学生已签章。如图所示:

    contract_id sign_status
    1 1

    在这里插入图片描述
    接着,学校开始签章,二进制状态变为 101 ,对应数据库存储的十进制状态为 5

    contract_id sign_status
    1 5

    在这里插入图片描述
    最后是实习公司签章:

    contract_id sign_status
    1 7

    在这里插入图片描述
    可以看出,当二进制状态为 111 ,即十进制为 7 的时候,表示《三方协议》已签章完毕。

    3. 无顺序状态改变的问题解决了,那么我们如何进行搜索呢?

    3.1 案例介绍

    同样的,我介绍一个案例供大家思考。

    我们现在有一个系统,是录入新闻信息,然后用户可以在前台根据分类查看新闻。假设前台的新闻分类有:0-全部、1-股票、2-理财、3-黄金、4-基金。我们在后台新增的新闻,他的分类可以是多选的,如 ["黄金","基金"],在这种情况下,前台用户可以在 全部、黄金、基金 这 3 个分类下面找到该新闻。

    3.2 未使用二进制状态的数据库设计

    一般这种情况,我们会使用一张中间表,来存储新闻类别(也可以使用字符串字段来表示,如"1,2,3,4",但是我个人认为这样做不优雅。假设,我们类别多了,我需要搜索分类id为 2 的新闻信息,如果使用 contrains('2') 关键字,请问,是否会搜索出 分类id=12 的分类信息。当然,我只是举了这一个例子,无论采用何种方法,我认为使用字符串表示状态,在进行搜索的时候都不够优雅)
    在这里插入图片描述

    3.3 使用二进制状态的数据库设计

    如果前端嫌二进制处理麻烦,我们可以使用 null-全部、1-股票、2-理财、3-黄金、4-基金 ,来对接前端,使用二进制状态对接数据库。
    我们可以参照上面《三方协议》的案例,使用二进制来表示新闻的状态

    news_id type
    1 7

    news_id :新闻id
    type:新闻类型:0001-股票、0010-理财、0100-黄金、1000-基金
    当新闻即为黄金分类,又为基金分类的时候,他的二进制状态为:1100,对应十进制:12
    在这里插入图片描述

    1. 我们如何将前端传递的 [1,2,3,4] 对应数据库的表现形式?【★】

    前端传递的参数:null-全部、1-股票、2-理财、3-黄金、4-基金
    数据库保存的状态:0001-股票、0010-理财、0100-黄金、1000-基金
    我们可以看出,前端传递的数字,其实就是对应数据库二进制状态从右开始数,第n个1的位置,因此,我们需要写一个工具类,使他们可以进行相互转换,即:
    [1,2,3,4] ⇒ 15
    7 ⇒ [1,2,3]
    工具类请点击查看:2.工具类。下面我将介绍工具类的实现原理,感兴趣的朋友可以看一看。

    1.1 位偏移运算(<<)

    将 [1,2,3,4] 转为 1111 即 15

    如果不懂该运算的朋友,可以去网上搜一下左偏移、右偏移。我简单介绍下。

    1 << 1 = 2 (0001 向左偏移1位 = 0010。对应十进制 2)
    2 << 1 = 4 (0010 向左偏移1位 = 0100。对应十进制 4)
    2 << 2 = 8 (0010 向左偏移2位 = 1000。对应十进制 8)
    3 << 1 = 6 (0011 向左偏移1位 = 0110。对应十进制 6)
    

    右偏移同理

    1 >> 1 = 0 (0001 向右偏移1位 = 0000。对应十进制 0)
    2 >> 1 = 1 (0010 向右偏移1位 = 0001。对应十进制 1)
    2 >> 2 = 0 (0010 向右偏移2位 = 0000。对应十进制 0)
    3 >> 1 = 1 (0011 向右偏移1位 = 0001。对应十进制 1)
    

    我们假设想要查看3-黄金分类,那么我们就需要将 3 转换为二进制数 0100,对应十进制为 4
    我们假设想要查看3-黄金 或者 4-基金的分类,那么我们就需要将 [3,4] 转换为二进制数 1100,对应十进制为 12
    代码实现如下

        /**
         * 将数组里面的数字对应至二进制 1 的位置(从右开始数)
         * 如:[1,3] 代表,二进制数中,第1的和第三的位置为 1,其他位置为 0,即:0101
         * 则 [1,3] 将会被转换为十进制数字:5
         *
         * @param numberList 数字列表
         * @return 二进制填充 1 后对应的十进制
         */
        public static int convert2Binary(List<Integer> numberList) {
            int number = 0;
            for (Integer cursor : numberList) {
                if (cursor == 0)
                    number += 0;
    
                number += 1 << (cursor - 1);
            }
            return number;
        }
    
    1.2 按位与运算(&)来进行搜索

    将 12 转为 [3,4]

    将前端传递的 [1,2,3,4] 转换为对应的二进制数字后,此时我们又需要用到 &运算,不懂的朋友可以去搜一下,我简单概括下,其实就是取两个数的二进制 1 的交集,如图所示
    在这里插入图片描述
    该运算的算法是,将指定数 & 1,从二进制数的最右边开始,若结果为 1 ,则表示该位置有值,记录下当前的位置,该位置即是对应前端的 [1,2,3,4] 的值。如图所示:
    在这里插入图片描述
    此时,我们便实现了互转,代码如下:

    /**
     * 获取 二进制 中,出现 1 的位置(从右开始数)
     * 如:3 对应的二进制为 : 0011
     * 则,该方法返回 [1,2]
     *
     * @param number 十进制数
     * @return 出现 1 数字的位置
     */
    public static List<Integer> find1Cursor(int number) {
        if (number < 0)
            return new ArrayList<>();
    
        List<Integer> cursorList = new ArrayList<>();
    
        int cursor = 0;
    
        if (number == 0) {
            cursorList.add(cursor);
            return cursorList;
        }
    
        while (true) {
    
            if (number == 0)
                break;
    
    
            //移动坐标
            ++cursor;
            //如果低位二进制有 1 值,则将坐标保存到数组中
            if ((number & 1) == 1) {
                cursorList.add(cursor);
            }
    
            number >>= 1;
        }
        return cursorList;
    }
    

    2.工具类【★】

    /**
     * 二进制转换工具
     *
     * @author Chimm Huang
     * @author chimmhuang@163.com
     * @date 2020/3/12
     */
    public class BinaryUtil {
    
        private BinaryUtil() { }
    
        /**
         * 获取 二进制 中,出现 1 的位置(从右开始数)
         * 如:3 对应的二进制为 : 0011
         * 则,该方法返回 [1,2]
         *
         * @param number 十进制数
         * @return 出现 1 数字的位置
         */
        public static List<Integer> find1Cursor(int number) {
            if (number < 0)
                return new ArrayList<>();
    
            List<Integer> cursorList = new ArrayList<>();
    
            int cursor = 0;
    
            if (number == 0) {
                cursorList.add(cursor);
                return cursorList;
            }
    
            while (true) {
    
                if (number == 0)
                    break;
    
    
                //移动坐标
                ++cursor;
                //如果低位二进制有 1 值,则将坐标保存到数组中
                if ((number & 1) == 1) {
                    cursorList.add(cursor);
                }
    
                number >>= 1;
            }
            return cursorList;
        }
    
        /**
         * 将数组里面的数字对应至二进制 1 的位置(从右开始数)
         * 如:[1,3] 代表,二进制数中,第1的和第三的位置为 1,其他位置为 0,即:0101
         * 则 [1,3] 将会被转换为十进制数字:5
         *
         * @param numberList 数字列表
         * @return 二进制填充 1 后对应的十进制
         */
        public static int convert2Binary(List<Integer> numberList) {
            int number = 0;
            for (Integer cursor : numberList) {
                if (cursor == 0)
                    number += 0;
    
                number += 1 << (cursor - 1);
            }
            return number;
        }
    }
    

    3.4 数据库的sql进行分类查询

    在数据库中,我们使用&运算,数据库会返回非0的数据,
    假设我们要查询 [3,4] 的分类,我们的 sql 如下:

    SELECT * FROM `news` WHERE news_type & 12
    

    只要具备 3-黄金4-基金 分类的新闻,就可以被数据库查询出来。
    通用mapper可以自己定义criteria添加查询条件,如:

    // 设置查询条件
    Example example = Example.builder(News.class)
            .build();
    example.createCriteria()
            .andCondition("news_type &", type);
    

    4. 优缺点

    优点:少建立一张表,少一次多表查询
    缺点:可读性太差

    5.联系作者

    书写的能力还需要锻炼,我个人会经常分享一些知识,不论是否深奥,分享这些东西,一个原因是想分享,二个原因也是为了锻炼自己的书写水平,革命还尚未成功,我还需更加努力。
    emailchimmhuang@163.com
    微信905369866

    展开全文
  • 二进制状态压缩

    2019-04-05 18:14:51
    二进制状态压缩 定义 二进制状态压缩是长度为m的...取出整数n在二进制表示下的后k位 n & ( (1<< k) -1 ) 将整数n在二进制表示下的第k位取反 n xor (1<<k) (最右为第0位) 对整数n在二进制的表示下的...

    二进制状态压缩

    定义

    二进制状态压缩是长度为m的bool数组转换为m位二进制整数并存储的方法

    常用操作汇总

    取出整数n在二进制下表示的第k位  (n>>k) & 1
    取出整数n在二进制表示下的后k位  n & ( (1<< k) -1 )
    将整数n在二进制表示下的第k位取反  n xor (1<<k) (最右为第0位)
    对整数n在二进制的表示下的第k位赋值1 n|(1<<k)
    对整数n在二进制的表示下的第k位赋值0 n & (~(1<<k))
    
    展开全文
  • 数据的二进制表示

    千次阅读 2020-02-05 17:07:43
    数据的二进制表示 文章目录数据的二进制表示基础定义二进制 基础定义 位: IC 电子元件有不同形状,但是其内部的组成单元称为一个个的引脚。只有直流电压0V 或 5V 两个状态。与 “0” 与“1”的表达不谋而合 字节...

    基础定义

    : IC 电子元件有不同种形状,但是其内部的组成单元称为一个个的引脚。只有直流电压0V 或 5V 两个状态。与 “0” 与“1”的表达不谋而合
    在这里插入图片描述

    字节:8 位二进制数被称为一个 字节

    为什么拟定 8 位为一个字节?
    因为 8 位能够涵盖基本的字符编码(英文 26 个字母大小写 + 基本符号位等)

    实例:

     一个英文字母-----占一字节
    
    一个中文字-------占二个字节
    
    一个整数---------占二个字节
    
    一个实数---------占四个字节
    

    图:
    在这里插入图片描述

    二进制

    位权:进制数值中某个位的权重值
    例如:
    十进制数 39 的各个数位的数值,并不只是简单的 3 和 9
    3 表示的是3×10 = 30,9 表示的是 9×1 = 9
    这里和各个数位的数值相乘的 10 和 1,就是位权

    基数:数值的表现方法,进位计数制中各数位上可能有的数值的个数。十进制数的基数是 10,二进制数的基数是 2

    二进制转十进制的理解
    核心:基数 x 位权

    十进制数:
    如 39 这个十进制数,表示的就是 30+9

    二进制数:
    00100111 用十进制数表示的话是 39,因为(0×128)+(0×64)+(1×32)+(0×16) +(0×8)+(1×4)+(1×2)+(1×1)= 39

    补数:将二进制数的值取反后加 1 的结果

    为什么使用补数后就能正确地表示负数了呢?
    实际上是验证:补数与原来的数相加是否为 0
    “将二进制数的值取反后加 1 的结果,和原来的值相加,结果为 0”这一法则
    例子:
    00000001+11111111
    图:
    在这里插入图片描述

    减法运算
    计算机在做减法运算时,实际上内部是在做加法运算。

    进位法则: 对各个进制的数都满足,满基数,向(当前位权+1)进1
    备注:楼主表示纠结这个概念了半天| :( |

    符号位
    二进制数中表示负数值时,一般会把最高位作为符号来使用,因此我们把这个最高位称为符号位。符号位是 0 时表示正数 ,符号位是1 时表示负数。
    错误事例
    “1 的二进制数是 00000001,因此-1 就是 10000001”
    正确事例
    “1 的二进制数是 00000001,因此-1 就是 11111111”

    符号位的应用
    有的可以处理负数,有的则不能处理。例如,C 语言的数据类型中,既有不能处理负数的 unsigned short 类型,也有能处理负数的 short 类型。这两种类型,都是 2 字节(= 16 位)的变量,都能表示 2 的 16 次幂 = 65536 种值,这一点是相同的。
    不过,值的范围有所不同,short 类型是- 32768~32767,unsigned short 类型是 0~65535。此外,short 类型和 unsigned short 类型的另一个 不 同 点 在于,short 类 型 是 将 最 高 位 为 1 的 数 值 看 作 补 数, 而unsigned short 类型则是 32768 以上的值。

    为什么总说最高位为 1 时是负数,为 0 时是正数?那么十进制的255用二进制表示就是1111-1111,可是二进制最高位是1的时候是负数,这个应该怎么理解?

    整数分为“有符号整数”和“无符号整数”,以8位的二进制而言:
    如果按无符号整数来用,那么最小值0(二进制0000-0000),最大值是255(1111-1111),总数是256个
    而如果作为有符号整数来用,则最小值为-128(二进制1000-0000),最大值为127(0111-1111),总数也还是256个
    题目中的 " 1111-1111 " 在 “有符号整数”中就不能够表示为 255 了,所以在依据最高位来判断正负数时,应该视具体情况而定

    逻辑右移与算数右移的区别
    算数右移有移位后在最高位补 0 和补 1 两种情况(视数值为正数或者负数)
    当二进制数的值表示图形模式而非数值时,移位后需要在最高位补 0。类似于霓虹灯往右滚动的效果。这就称为 逻辑右移
    图:
    在这里插入图片描述
    符号扩充
    符号扩充就是指在保持值不变的前提下将其转换成 16 位和 32 位的二进制数
    不管是正数还是用补数表示的负数,都只需用符号位的值(0 或者 1)填充高位即可
    图:
    在这里插入图片描述
    逻辑运算
    包括逻辑非(NOT 运算)、逻辑与(AND 运 算)、逻辑或(OR 运算)和逻辑异或(XOR 运算 A)四种

    逻辑异或 指的是排斥相同数值的运算。“两个数值不同”
    图:
    在这里插入图片描述

    展开全文
  • 二进制表示集合

    千次阅读 2014-06-23 10:18:59
    25表示二进制是11001,第1,4,5位是1,就说明集合中含有1,4,5这三个数,其余位是0,则表示集合中不含其它数。 这样表示对吗? 答案是肯定的。因为,对于一个集合,任意一个数只有两个状态,属于or不属于,0表示...

    将一个集合与一个二进制数对应,再将二进制数与十进制数对应。为了方便操作,单词的编号也可以从1…N,改成0…N-1。比如:集合[1,4,5]->集合[0,3,4]->11001(2)->2^0+2^3+2^4=25。这样操作不但节省了空间,而且在进行集合操作时可以用位操作,又节省了时间。

    简单说就是把集合用一个数表示:
    [1,4,5]就表示为25,25就是集合[1,4,5].

    为什么呢?
    25表示成二进制是11001,第1,4,5位是1,就说明集合中含有1,4,5这三个数,其余位是0,则表示集合中不含其它数。

    这样表示对吗?
    答案是肯定的。因为,对于一个集合,任意一个数只有两个状态,属于or不属于,0表示不属于,1表示属于,完全可以。

    再就几个例子:
    集合[2,4],可表示为1010,转化为十进制就是10,然后10就可表示集合[2,4];
    集合[1,2,5,7],可表示为1010011,转化为十进制是83,83就表示集合[1,2,5,7];
    数23,变为二进制是10111,对应的集合就是[1,2,3,5];

    这样一个数就可以表示一个集合了,简洁明了,还可以进行位运算。但有限制,集合里的数不能太大,若是有个100000,你就需要2^(100000-1)这么大的数存了。那就得不偿失了。

    展开全文
  • 二进制:基础、正负数表示、存储与运算

    万次阅读 多人点赞 2018-09-11 11:35:53
    一、概述 众所周知,计算机是由各种...所谓二进制表示从0开始,“逢二进一”(N进制则逢N进一)。比如十进制的0、1、2的二进制表示为0、1 、10。 二、进制转换 网上有很多进制转换的方法,我这里就不多做阐述,只...
  • 想必大家都知道计算机内部是由 IC 这种电子部件构成的。CPU(微处理器)和内存也是IC的一。IC有几不同的形状,有的像一条黑色蜈蚣,在其两侧有数个乃至数百个引脚;...也就是说,IC的一个引脚,只能表示两个状态
  • 二进制,是最简单的 1.表示简单 自然界有很多两相对对立,稳定的两种状态,可以代表0 1 ...而二进制只有3可能 3.二进制与逻辑运算正好可以统一起来 与或非 异或运算 XOR 运算 就等同于两个一位二进制数相加 ...
  • 二进制

    2018-12-10 11:07:39
    二进制是计算技术中广泛采用的一数制。二进制数据是用0和1两个数码来表示的数。它的基数为2,进位规则是“逢二进一”,借位规则是“借一当二”(十进制加减法是“逢十进一”、“借一当十”)。数字电子电路中,&...
  • 二进制状态

    2019-02-01 02:46:55
    其中每一位0和1都可以看做一种状态的开和关,所以就有了这样的一种状态码存储方式:把同一对象的多种状态按位组合到一个整数中。 例如我们最最常见的 *nix 文件权限: 第9位 第8位 第7位 第6位 第5位 第4位 第3位 ...
  • 解法一:举例说明,为了减少复杂度,就使用八位二进制吧。设 A = 0010 1011, B = 0110 0101. 1. C = A & B = 0010 0001; 2. D = A | B = 0110 1111; 3. E = C ^ D = 0100 1110;...至于如何判断E的二进制表示中有
  • 想要了解二进制数是如何表示计算机信息的?先要追本溯源, 二进制(binary)在数学和数字电路中指以2为基数的记数系统,以2为基数代表系统是二进位制的。这一系统中,通常用两个不同的符号0(代表零)和1(代表一)...
  • 二进制状态压缩 二进制状态压缩,是指将一个n位的 bool 数组...取出 n 在二进制表示下的0~ k-1 位(后k位) n & ((1<<k) - 1) 我们以13 (1101)为例,看一下位运算的实现过程 1. 取出第k位: (n...
  • 假如使用二进制的 111 来表示增、删、改 这三个权限 这时 4 代表 增 权限 值 增 4 删 2 改 1 相关二进制操作 ** 增加权限 假如原来的权限是 000 我们想添加一个 删除权限 可以用原来的...
  • 二进制状态枚举

    2018-07-26 15:53:04
    在写程序的时候,有时候我们可能需要暴力枚举出所有的情况,这时可以考虑通过二进制来枚举子集来尝试解决问题。 解释 假设我们现在有5个小球,上面分别标号了0,1,2,3,4代表这些小球的权值,现在要像你求出这些小球...
  • 一:表示法: 1、正数5的表示法 假设有一个 int 类型的数,值为5,那么,我们知道它在计算机中表示为: 00000000 00000000 00000000...一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。 比如 000000
  • 某些应用场景:如用户是否实名制,是否绑定...是否实名制(isRealName),如此便完成以上状态的并存或者单个状态,那么问题来了,如果我后续业务中还有加入其他的状态如是否注册邮箱,是否绑定银行卡等等(又改...
  • 二进制位运算和状态存储

    千次阅读 2018-05-25 08:15:46
    在系统设计中只要是状态只有两种状态(0,1)的都可以用二进制位来表示,如果有多个状态用多个位或者还是新加字段吧。(1)可以节省字段。一个字段只需要一个数字 就可以标识很多设置和信息。(2)可以处理位置...
  • 2 ,即QQ的二进制,说明已经绑定了QQ 综上所述,只要判断state&是否为0,即可得出是否绑定 这样存可取,是不是比原来声明8个boolean类型的变量要好呢?在我们阅读源码的时候也经常会遇到这样的存取方式,了解便好...
  • java使用二进制进行判断权限,拥有状态等,数据库oracle权限计算
  • 什么是二进制,为什么要用二进制

    千次阅读 2019-11-18 15:26:13
    计算机最早是机电设备,一般用十进制计数,比如用齿轮数来代表十进制,再到晶体管计算机,晶体管计算机只用开/关两种状态就可以代表信息,就叫二进制,意思是“用两种状态表示”。 (如果你觉得两种状态不够多,那也...
  • 二进制状态压缩基础

    2018-04-17 17:58:32
    拜读了lyd的新书。对位运算这一节的某些技巧以10010为例自己实现...int turnten(int n)//二进制转十进制 { return n==1?1:turnten(n/10)%10*2+n%10; } int turntwo(int n)//十进制转二进制 { return n==1?1:turn...
  • int main() { int s; while(cin>>s) { print(s); for(int i=s; i>=0; i=(i>0?(i-1)&s:-1)) { print(i); } } return 0; } 代码中的i表示的是所有s中为0,i中也为0
  • 在计算机中数据运算的本质其实各种门...为了方便数据表示,计算机中定义多种数据类型,每数据类型取值范围和占用的内存不同,我们可以根据他们占用的内存来计算出他们的取值范围。比如C语言中unsigned int类型(这里先
  • 二进制内容

    2020-04-25 09:58:11
    二进制是计算机技术中心采用的一记数方法。二进制的数据是用0和1来表示。(参照比对十进制0-9)。基数是2,同时也是称之为逢二进一。 为什么要采用二进制呢 再计算机中,计算机内部硬件数据的交流方式是采用的0和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 334,788
精华内容 133,915
关键字:

二进制可表示多少种状态