C#中一些常用的位运算技巧

1.用byte枚举代替bool节约空间

C#中bool值占2个字节,而一个字节用byte储存的话可以存下8个bool,还可以让枚举继承其他类型数据储存更多bool值。
参考https://blog.csdn.net/darkrabbit/article/details/82633601
https://blog.csdn.net/darkrabbit/article/details/82666493
大佬讲的很详细,我是菜逼,我能写的都在注释里面了

using UnityEngine;

public enum boolean8 : byte
{
    //全部关闭
    None=0x00,
    //开关1开启的状态 0000 0001
    B1 = 0x01,
    //开关2开启的状态 0000 0010
    B2 = 0x02,
    //开关3开启的状态 0000 0100
    B3 = 0x04,
    //开关4开启的状态 0000 1000
    B4 = 0x08,
    //开关5开启的状态 0001 0000
    B5 = 0x10,
    //开关6开启的状态 0010 0000
    B6 = 0x20,
    //开关7开启的状态 0100 0000
    B7 = 0x40,
    //开关8开启的状态 1000 0000
    B8 = 0x80,
    //全部开启
    ALL=0xFF,
}
public class Test : MonoBehaviour
{
    void Start()
    {
        boolean8 bools = boolean8.None;
        Debug.Log(CheckBool(bools, boolean8.B2));
        SetSwitch(ref bools, boolean8.B2,0x01);
        Debug.Log(CheckBool(bools, boolean8.B2));

        boolean8 checkBools = boolean8.None;
        SetSwitch(ref checkBools, boolean8.B1, 0x01);
        SetSwitch(ref checkBools, boolean8.B2, 0x01);
        SetSwitch(ref checkBools, boolean8.B3, 0x01);
        Debug.Log(CheckBools(bools, checkBools, 0x01));
        Debug.Log(CheckBools(bools, checkBools, 0x00));

        SetSwitch(ref checkBools, boolean8.B2, 0x00);
        Debug.Log(CheckBools(bools, checkBools, 0x01));
        Debug.Log(CheckBools(bools, checkBools, 0x00));
    }
    /// <summary>
    /// 对某个开关进行控制
    /// </summary>
    /// <param name="currentBools">当前的布尔组 因为enum是值类型 所以传ref地址进来做修改</param>
    /// <param name="boolx">布尔组中的某个开关开启的状态</param>
    /// <param name="isOn">设置是否开启0x00表示关闭 0x01表示开启</param>
    public void SetSwitch(ref boolean8 currentBools,boolean8 boolx, byte isOn) {
        //开启某个开关
        if (isOn==0x01)
        {
            //比如当前开关1111 0000(开启了5,6,7,8号开关),开启2号开关0000 0010, 1111 0000|0000 0010=1111 0010
            currentBools |= boolx;
        }
        //关闭某个开关
        else
        {
            //比如当前开关0000 1111(开启了1,2,3,4号开关),关闭2号开关0000 0010
            //先对2号开关取反 ~0000 0010=1111 1101
            //对原状态进行与计算 0000 1111&1111 1101 = 0000 1101
            currentBools &= ~boolx;
        }
    }
    /// <summary>
    /// 检测某个开关是否开启
    /// </summary>
    /// <param name="currentBools"></param>
    /// <param name="boolx"></param>
    /// <returns></returns>
    public bool CheckBool(boolean8 currentBools,boolean8 boolx) {
        //比如当前开关 1101 0101,想获取2号开关是否开启
        //1101 0101 & 0000 0010 = 0000 0000
        //1101 0110 & 0000 0010 = 0000 0010
        return (currentBools & boolx) == boolx;
    }
    /// <summary>
    /// 查询某几个开关的状态
    /// </summary>
    /// <param name="currentBools">待查询的开关组</param>
    /// <param name="checkBools">需要查询的开关组</param>
    /// <param name="isAllOn">true表示查询开关是否全部开启,false表示查询开关中是否存在开启</param>
    /// <returns></returns>
    public bool CheckBools(boolean8 currentBools,boolean8 checkBools,byte isAllOn) {
        if (isAllOn==0x01)
        {
            return (currentBools & checkBools) == checkBools;
        }
        else
        {
            return (currentBools & checkBools) != boolean8.None;
        }
    }
}

测试结果
在这里插入图片描述

2.异或交换两个数

这是个很常用的小技巧,不需要第三个数字就可以交换两个数

/// <summary>
/// 交换两个数
/// </summary>
/// <param name="a"></param>
/// <param name="b"></param>
public void Exchange(ref int a, ref int b)
{
    //比如a=0000 0001也就是1,b=0000 0010也就是2
    a = a ^ b;//a= 0000 0001^0000 0010=0000 0011
    b = a ^ b;//b=0000 0011^0000 0010=0000 0001=a
    a = a ^ b;//a=0000 0011^0000 0001=0000 0010=b
}

3.左移右移

对于一个数 0000 0001
左移变成 0000 0010相当于*2
同理右移相当于除以2
位运算比乘除法效率高一些

4.相同的数字异或等于0

这个规律某些情况下可以非常高效的解决一些问题
比如一个数组中所有数都是成对出现的,只有一个数除外,如何找到这个数
这是leetcode中的一个经典的题目,答案就是一顿异或,最后相同的数字都会变成0,剩下的就是只出现了一次的数字.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值