`
请输入用户名
  • 浏览: 45896 次
  • 性别: Icon_minigender_1
  • 来自: martian
社区版块
存档分类
最新评论

用二进制的与、或、非运算方便的解决实际问题

阅读更多
二进制的与、或、非运算特殊用法的不同运用场合:
1.权限控制
    下面我用几个数字来代表增,删,改,查。(注:1带有有权限,有几个1,就代表有几个权限,1的位置不同,所带表的权限也不同)
1---------增--------(转二进制)-----(0001)
2---------删----------------------(0010)
4--------改----------------------(0100)
8--------查----------------------(1000)


管理员拥有所有的权限,所以,控制管理员的权限的数字为(15),转化二进制的格式为:(1111)。算法为:“1|2|4|8“
撤销管理员的删权限(2),控制管理员的权限的数字为(13),转化二进制的格式为:(1101)。算法为:”15 & (~2)”
判断管理员的权限中是否有某个权限。如在控制管理员的权限的数字为(13)时,判断管理员是否具有修改的权限(4)。算法为:“13 & 4==0”,假如等于0的话,表示,权限不存在,假如不等于0的话,表示,此权限已经存在。


2.分类组合
   假如一个类要支持很多操作,操作和操作之间可能没有联系,可能有相反关系无法共存,可能有特殊关系必须共存,这种要分很多类还要处理联系的情况下可以考虑采用二进制来解决。
    我这里的例子是java做的文件搜索,用的是递归,搜索的时候可以搜索文件、文件夹,搜索的方式可以有正则表达式匹配、以特定开始、以特定结束、以是否包含的方式。而且除了正则则要单独处理,其他方式直接可以进行组合。
    通过二进制分类

    /** 查找文件夹 */
    public static final int      FIND_DIRECTORY  = 1;
    /** 查找文件 */
    public static final int      FIND_FILE       = 2;
    /** 正则查找 */
    public static final int      FIND_BY_REGEX   = 4;
    /** 起始于 */
    public static final int      FIND_START_WITH = 8;
    /** 结束于 */
    public static final int      FIND_END_WITH   = 16;
    /** 包含于 */
    public static final int      FIND_CONTAIN    = 32;
    // rule
    private int           _rule        = 0;


    当程序传入规则之后,我可以很方便的加入到 _rule中
    /** 添加规则 */
    public int ruleAdd(int r) {

      _rule = _rule | r;
      return _rule;
    }


     去除 和 判断是否有这个规则

    /** 去除规则 */
    public int ruleRemove(int r) {

      _rule = _rule & (~r);
      return _rule;
    }

    /** 是否包含规则 */
    public Boolean hasRule(int r) {

      return (_rule & r) != 0;
    }


    之后处理时进行 if分类 就可以很方便
 /**
     * 判断是否满足规则用户指定的rule (正则表达式 ______ 开始于 __________ 结束于)
     *
     * @param content
     * @return
     */
    public Boolean meetRule(File pathname) {

      Boolean result = true;
      // 查找路径
      if (hasRule(FIND_DIRECTORY)) {
          result = result && pathname.isDirectory();
      }
      // 查找文件
      if (hasRule(FIND_FILE)) {
          result = result && pathname.isFile();
      }
      String fileName = pathname.getName().toUpperCase();
      // 按照开始于查找
      if (hasRule(FIND_START_WITH)) {
          result = result && fileName.startsWith(_fix.get(FIND_START_WITH).toUpperCase());
      }
      // 按照结束于查找
      if (hasRule(FIND_END_WITH)) {
          result = result && fileName.endsWith(_fix.get(FIND_END_WITH).toUpperCase());
      }
      // 文件名包含查找
      if (hasRule(FIND_CONTAIN)) {
          result = result && fileName.contains(_fix.get(FIND_CONTAIN).toUpperCase());
      }
      // 按照正则查找 不区分大小写
      if (_rule == FIND_BY_REGEX) {
          result = result && Pattern.compile(_fix.get(FIND_BY_REGEX), Pattern.CASE_INSENSITIVE).matcher(fileName).find();
      }
      return result;
    }


大体就是这个个意思,完整代码
/**
 * 查找指定路径下 满足条件的文件、文件夹(不区分大小写)
 *
 * @see
 * @author kaven
 * @version 1.0, 2011-8-27
 * @since 1.0, 2011-8-27
 */
public class PathSearch {

    /** 查找文件夹 */
    public static final int      FIND_DIRECTORY  = 1;
    /** 查找文件 */
    public static final int      FIND_FILE       = 2;
    /** 正则查找 */
    public static final int      FIND_BY_REGEX   = 4;
    /** 起始于 */
    public static final int      FIND_START_WITH = 8;
    /** 结束于 */
    public static final int      FIND_END_WITH   = 16;
    /** 包含于 */
    public static final int      FIND_CONTAIN    = 32;

    // rule
    private int           _rule        = 0;
    // 用户输入的用来匹配文件名的字段 或者正则
    private Map<Integer, String> _fix         = new HashMap<Integer, String>();
    // 文件
    private List<File>     _files = new ArrayList<File>();

    public PathSearch() {

    }

    // public PathSearch(Map<Integer, String> aFix) {
    //
    // this._fix = aFix;
    // }

    /** 添加规则 */
    public int ruleAdd(int r) {

      _rule = _rule | r;
      return _rule;
    }

    /** 去除规则 */
    public int ruleRemove(int r) {

      _rule = _rule & (~r);
      return _rule;
    }

    /** 是否包含规则 */
    public Boolean hasRule(int r) {

      return (_rule & r) != 0;
    }

    /**
     * 判断是否满足规则用户指定的rule (正则表达式 ______ 开始于 __________ 结束于)
     *
     * @param content
     * @return
     */
    public Boolean meetRule(File pathname) {

      Boolean result = true;
      // 查找路径
      if (hasRule(FIND_DIRECTORY)) {
          result = result && pathname.isDirectory();
      }
      // 查找文件
      if (hasRule(FIND_FILE)) {
          result = result && pathname.isFile();
      }
      String fileName = pathname.getName().toUpperCase();
      // 按照开始于查找
      if (hasRule(FIND_START_WITH)) {
          result = result && fileName.startsWith(_fix.get(FIND_START_WITH).toUpperCase());
      }
      // 按照结束于查找
      if (hasRule(FIND_END_WITH)) {
          result = result && fileName.endsWith(_fix.get(FIND_END_WITH).toUpperCase());
      }
      // 文件名包含查找
      if (hasRule(FIND_CONTAIN)) {
          result = result && fileName.contains(_fix.get(FIND_CONTAIN).toUpperCase());
      }
      // 按照正则查找 不区分大小写
      if (_rule == FIND_BY_REGEX) {
          result = result && Pattern.compile(_fix.get(FIND_BY_REGEX), Pattern.CASE_INSENSITIVE).matcher(fileName).find();
      }
      return result;
    }

    /**
     * 添加规则(等价于 ruleAdd)
     *
     * @param rule
     */
    public void addRule(int rule) {

      ruleAdd(rule);
    }

    /**
     * 添加规则 和 规则验证字段
     *
     * @param rule
     * @param value
     */
    public void addRule(int rule, String value) {

      ruleAdd(rule);
      this._fix.put(rule, value);
    }

    /**
     * 根据给定的path 查找其下满足特定条件的文件、文件夹
     */
    public void findUnderPath(String path) {

      File directory = new File(path);
      if (!directory.exists()) {
          // 路径不存在
          return;
      }
      File[] files = directory.listFiles(new FileFilter() {

          @Override
          public boolean accept(File pathname) {

            return meetRule(pathname);
          }
      });
      _files = Arrays.asList(files);
    }

    /**
     * 根据指定的path 查找其下包括子文件夹 所有满足特定条件的文件、文件夹
     *
     * @return
     */
    public void findDeepUnderPath(File pathName) {

      if (!pathName.exists()) {
          return;
      }
      // 获取所有 符合规则的文件 列表
      File[] files = pathName.listFiles(new FileFilter() {

          @Override
          public boolean accept(File pathname) {

            return meetRule(pathname);
          }
      });
      // 添加到结果集列表中
      _files.addAll(Arrays.asList(files));
      // 查找所有目录
      File[] directories = pathName.listFiles(new FileFilter() {

          @Override
          public boolean accept(File pathname) {

            return pathname.isDirectory();
          }
      });
      // 获取子文件夹下的文件
      for (File directory : directories) {
          findDeepUnderPath(directory);
      }
    }

    public List<File> getFiles() {

      return _files;
    }

    @Test
    public void testFind() {

      String path = "F:\\work_tools";
      PathSearch ps = new PathSearch();

      // ps.addRule(FIND_FILE);
      ps.addRule(FIND_BY_REGEX, "[\\d]");
//     ps.addRule(FIND_END_WITH, "rar");

      // ps.findUnderPath(path);
      ps.findDeepUnderPath(new File(path));
      List<File> files = ps.getFiles();
      for (File f : files) {
          System.out.println(f.getPath());
      }
    }

//    @Test
    public void testRule() {

      System.out.println(ruleAdd(1));
      System.out.println(ruleAdd(4));
      System.out.println(ruleAdd(8));
      System.out.println(hasRule(4));
      System.out.println(ruleRemove(4));
      System.out.println(hasRule(4));
    }
}

3.快速找出两个list(或数组)中不同的对象
    一般的想法都是通过对两个list进行 循环嵌套,每找到一个,remove一个,这样的话有两个缺点:一个是速度,在最差的情况下是O(n^2),这对于数量大的是比较慢的。二是由于要remove元素,不能采用iterator尽心循环(据说采用迭代器java会有缓存优化)。
      这个就可以采用二进制来解决,其实这里用二进制只是一种方式,完全可以用 权的概念,一个权设为10,一个权设为1
任意两个不相等的数都可以,如果多个list和数组的话,还是二进制方式比较清楚)。假如数组种的对象通过code来进行标示,新建一个
Map<String,Integer> countMap = new HashMap<String,Integer>()//key -- > code, value -- > 权

分别对两个list进行第一次循环
   循环list1的时候:

countMap.put(code,10);

    循环list2的时候:

if(null == countMap.get(code)){
   countMap.put(code, 0);//初始化为0
}
int count = countMap.get(code);//获取当前权
countMap.put(code, count + 1);//更新权


这样一来,所有list1独有的,countMap表现为Value为1,list2独有的,countMap表现为Value为10,共有的表现为Value为11
然后进行第二次循环,将list1、list2根据code进行分类,组合成两个HashMap,以方便根据code找出code相同的部分(code相同不代表其他属性也相同,实际处理中可能会有用,不管你用没用到,反正我用到了)和code不同的部分。

之后就是 根据找出来的code,各自的map中获取对应的对象了。
复制度O(2n)
我能想到的是这个方法,不知道有没有更好的,望提示!!!
上代码:

/**
 * 通过3次循环,对field 进行快速分类,找出彼此code不同的TableField
 * @author qihuan
 *
 */
public class QuickDiff {
    private List<TableField> oldFieldPop = new ArrayList<TableField>();
    private List<TableField> newFieldAppend = new ArrayList<TableField>();
    private List<String> commonCode = new ArrayList<String>();
    private Map<String, TableField> newFieldMap;
    private Map<String, TableField> oldFieldMap;
    
    public QuickDiff(){
    }
    /**
     * 通过3次循环,对field 进行快速分类
     * @param oldFields
     * @param newFields
     */
    public void doDiff(List<TableField> oldFields,List<TableField> newFields){
	// key:desc -- value:对应出现次数
	Map<String,Integer> countMap = new HashMap<String, Integer>();
	addToMap(countMap,oldFields,1);//old 权为 1
	addToMap(countMap,newFields,10);//new 权为10
	
	newFieldMap = turnToMapByCode(newFields);
	oldFieldMap = turnToMapByCode(oldFields);
	//对 独有的code进行分类
	for(String code : countMap.keySet()){
	    int value = countMap.get(code);
	    if(value == 11){
		commonCode.add(code);
		//do nothing
	    }else if(value == 10){
		newFieldAppend.add(newFieldMap.get(code));
	    }else if(value == 1){
		oldFieldPop.add(oldFieldMap.get(code));
	    }
	}
    }
    
    /**
     * 按照 code 进行分类
     * @param fields
     * @return
     */
    private Map<String, TableField> turnToMapByCode(List<TableField> fields){
	Map<String, TableField> fieldMap = new HashMap<String, TableField>();
	for(TableField tf : fields){
	    String code = tf.getCode();
	    fieldMap.put(code, tf);
	}
	return fieldMap;
    }
    /**
     * 
     * @param countMap 计数map
     * @param fields 
     * @param value 权
     */
    private void addToMap(Map<String, Integer> countMap, List<TableField> fields, int value) {
	for(TableField tf : fields){
	    String code = tf.getCode();
	    if(null == countMap.get(code)){
		countMap.put(code, 0);
	    }
	    int count = countMap.get(code);//获取当前权
	    countMap.put(code, count + value);//更新权
	}
    }
    /**
     * old 独有的
     * @return
     */
    public List<TableField> getOldFieldPop() {
    
        return oldFieldPop;
    }
    /**
     * new 独有的
     * @return
     */
    public List<TableField> getNewFieldAppend() {
    
        return newFieldAppend;
    }
    /**
     * 共有的
     * @return
     */
    public List<String> getCommonCode() {
    
        return commonCode;
    }
    /**
     * newField to Map
     * @return
     */
    public Map<String, TableField> getNewFieldMap() {
    
        return newFieldMap;
    }
    /**
     * oldField to Map
     * @return
     */
    public Map<String, TableField> getOldFieldMap() {
    
        return oldFieldMap;
    }
    
}
分享到:
评论

相关推荐

    大一大学计算机基础课程知识点.doc

    应用软件〔可选〕:用户为解决实际问题开发的专门程序〔Photoshop、AutoCAD〕 11.计算机工作原理〔存储程序即冯·诺依曼原理〔1946〕〕: 计算机系统由五大部分组成; 指令和数据都存放在储存器中,计算机工作时...

    modbus通信协议

    • 8位二进制,十六进制数0...9,A...F • 消息中的每个8位域都是一个两个十六进制字符组成 每个字节的位 • 1个起始位 • 8个数据位,最小的有效位先发送 • 1个奇偶校验位,无校验则无 • 1个停止位(有校验...

    会计理论考试题

    A、模拟信息 B、模拟信息或数字信息 C、数字形式D、二进制形式的数字 6.在Windows98中,要恢复回收站中的文件,只要___B____。 A、双击该文件 B、用鼠标把该文件施出回收站 C、单击该文件 D、A、B、C均可 7.在...

    华为编程开发规范与案例

    维护类问题(C类)-指设计、编码中出现的对软件系统的维护方便程度造成影响的问题,在系统中不起关键作用,但对系统后期维护造成不便或导致维护费用上升; 可测试性问题(D类)-指设计、编码中因考虑不周而导致...

    计算机组成原理考研纲要

    在发送端,将要传送的K位二进制信息码左移R位,再将它与生成多项式G(x)做模2除法,生成一个R位校验码(余数),附在信息码后,构成一个新的CRC码。 b.在接收端利用收到的编码做模2除法,以检测和确定出错的位置;...

    C#微软培训资料

    14.4 继承中关于属性的一些问题.169 14.5 小 结 .172 第四部分 深入了解 C#.174 第十五章 接 口 .174 15.1 组件编程技术 .174 15.2 接 口 定 义 .177 15.3 接口的成员 .178 15.4 接口的实现 .182 ...

    asp.net知识库

    使用.ashx文件处理IHttpHandler实现发送文本及二进制数据的方法 制作一个简单的多页Tab功能 一完美的关于请求的目录不存在而需要url重写的解决方案! 在C#中实现MSN消息框的功能 XmlHttp实现无刷新三联动ListBox 鼠标...

    语言程序设计课后习题答案

    2.二进制数运算简单;3.机器可靠性高;4.通用性强。其缺点是它表示数的容量较小,表示同一个数,二进制较其他进制需要更多的位数。 1-9 请将以下十进制数值转换为二进制和十六进制补码: (1)2 (2)9 (3)93 (4...

    基于AT89S52 单片的频率计

    辑器编译连接生成单片机可执行的二进制文件(.HEX),然后通过单片机的烧 写软件将HEX 文件烧入单片机内。3 2.2.3 单片机仿真软件:PROTEUS Proteus 是目前最好的模拟单片机外围器件的工具。可以仿真51 系列、 AVR,...

    西安理工大学 微机原理课件

    当学习了相关的原理知识及指令系统后,就希望能运用学到的知识解决实际的问题。这就需要通过程序设计来完成。 学习程序设计应从基本知识和基本方法入手,逐步深入。本章中讲述了伪指令,汇编语言源程序格式,汇编...

    《数据结构 1800题》

    6.算法可以用不同的语言描述,如果用C 语言或 PASCAL语言等高级语言来描述,则算法实际上就是程序 了。( )【西安交通大学 1996 二、7(3分)】 7.程序一定是算法。( )【燕山大学 1998 二、2(2分)并改错】 8....

    PHP基础教程 是一个比较有价值的PHP新手教程!

    如果想要强行转换变量类型,可以使用与C语言相同的函数settype()。 2.5 变量与常量 可能你已经注意到,变量都有一个美元符号($)的前缀。所有变量都是局部变量,为了使得定义的函数中可以使用外部变量,使用...

    rar压缩软件.rar

    包含两个掩码,并且所有文件既匹配第一个掩码,也匹配第二个掩码, 较小的子集 或者更精确的匹配拥有更高的优先权。例如,如果你用 *.cpp 和 f*.cpp 掩码, f*.cpp 拥有更高的优先权。 RAR 命令行语法 ~~~~~~...

    C# for CSDN 乱七八糟的看不懂

    逻辑运算符 与:a & b 或:a | b 第8页 C#(WINFORM)学习 非:! A 模数运算符 模数运算符 (%) 计算第二个操作数除第一个操作数后的余数。所有数值类 型都具有预定义的模数运算符。如 Console.WriteLine(5 % 2); ...

Global site tag (gtag.js) - Google Analytics