位运算 - 位图存储数字(替代数组)

package class05;

import java.util.HashSet;

/**
 * 用位图存储数字,而不是使用int[] 数组, 这样能大大节省空间, 最少节省32倍空间。
 * 这里使用long[] 表示位图, 每个long能存储64个数字,如果数组长度为10,那么能存储640个数字, 存储数字范围从1到640,是连续的数字范围
 * 注意:这里的每一位表示一个数字,不会用2位或者多位表示一个存储的数字
 * 每一位的位置表示一个数字,比如第640位表示数字640
 * 最重要的两种计算是 取余 和 取模, 并且 取余和取模 都用位运算实现
 * 记住,取模主要就是用于确定位置,例如hashMap中确定数组下标,就是一个确切的位置,在这里也是如此
 */

public class Code01_BitMap1 {

   public static class BitMap {

      private long[] bits;

      //构造器

      /**
       *
       * @param max, 表示要存储多少个数字
       */
      public BitMap(int max) {
         bits = new long[(max + 64) >> 6];
      }


      /**
       * 1L << (num & 63) 定位到要操作的那一位,然后按位或。
       * num & 63 取模运算(Note: 只有在对特定值(2^n)取模的时候,才能使用这种方式,其它情况下是错误的)
       * num & 63 等价于num % 64,由于位运算速度快,所以我们使用位运算
       * Note: 只有在对特定值(2^n)取模的时候,才能使用这种方式,其它情况下是错误的
       *
       * 取余运算 num >> 6 等价于 num / 64
       * Note: 只有在对特定值(2^n)取余的时候,才能使用这种方式,其它情况下是错误的
       * @param num
       */
      public void add(int num) {
         bits[num >> 6] |= (1L << (num & 63));
      }

      /**
       * 1L << (num & 63) 定位到要操作的那一位,然后处理。 num & 63 取模运算(Note: 只有在对特定值(2^n)取模的时候,才能使用这种方式,其它情况下是错误的)
       * Note: 只有在对特定值(2^n)取模的时候,才能使用这种方式,其它情况下是错误的
       *
       * 取余运算 num >> 6 等价于 num / 64
       * Note: 只有在对特定值(2^n)取余的时候,才能使用这种方式,其它情况下是错误的
       * @param num
       */
      public void delete(int num) {
         bits[num >> 6] &= ~(1L << (num & 63));
      }

      /**
       * 1L << (num & 63) 定位到要操作的那一位,然后处理。 num & 63 取模运算(Note: 只有在对特定值(2^n)取模的时候,才能使用这种方式,其它情况下是错误的)
       * Note: 只有在对特定值(2^n)取模的时候,才能使用这种方式,其它情况下是错误的
       *
       * 取余运算 num >> 6 等价于 num / 64
       * Note: 只有在对特定值(2^n)取余的时候,才能使用这种方式,其它情况下是错误的
       * @param num
       * @return
       */
      public boolean contains(int num) {
         return (bits[num >> 6] & (1L << (num & 63))) != 0;
      }

   }

   public static void main(String[] args) {
      System.out.println("测试开始!");
      int max = 10000;
      BitMap bitMap = new BitMap(max);
      HashSet<Integer> set = new HashSet<>();
      int testTime = 10000000;
      for (int i = 0; i < testTime; i++) {
         int num = (int) (Math.random() * (max + 1));
         double decide = Math.random();
         if (decide < 0.333) {
            bitMap.add(num);
            set.add(num);
         } else if (decide < 0.666) {
            bitMap.delete(num);
            set.remove(num);
         } else {
            if (bitMap.contains(num) != set.contains(num)) {
               System.out.println("Oops!");
               break;
            }
         }
      }
      for (int num = 0; num <= max; num++) {
         if (bitMap.contains(num) != set.contains(num)) {
            System.out.println("Oops!");
         }
      }
      System.out.println("测试结束!");
   }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值