zoukankan      html  css  js  c++  java
  • [underscore源码学习]——`>>` 运算符和二分查找

    这是一篇记录学习 underscore v0.0.5 的fragment,觉得有点意思,和大家分享一下。

    先看_.sortedIndex的源码,它用来确定 obj 在 array中的位置(array升序):

      _.sortedIndex = function(array, obj, iterator) {
        iterator = iterator || _.identity;
        var low = 0, high = array.length;
        while (low < high) {
          var mid = (low + high) >> 1;
          iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
        }
        return low;
      };
    
      _.identity = function(value) {return value};
    

    代码虽短却两个我不常用的姿势:>> 运算符和二分查找。


    右移运算符 >>

    右移运算符的计算规则如下

    int a = 8; int b = a >> 1; // b ?
    先将 8 转化为二进制数,(在 C 中,32位操作系统下int 类型占2个字节,即16bit)
    0000 0000 0000 1000
    整体右移 1 位,高位不足添 0
    0000 0000 0000 0100
    再将新的二进制数转化为十进制得到 b = 4;

    那么,代码 var mid = (low + high) >> 1 mid 变量取值是多少呢?因为好(dou)奇(bi),我作了一点尝试:

    0 >> 1  // 0
    1 >> 1  // 0
    2 >> 1  // 1
    3 >> 1  // 1
    4 >> 1  // 2
    5 >> 1  // 2
    ...
    10 >> 1 // 5
    11 >> 1 // 5
    12 >> 1 // 6
    ...
    

    由归纳法可得 a >> 1 === parseInt(a / 2)。这点相信眼尖的同学早就看出来了。

    二分查找

    既然我们已经知晓mid >> 1 === parseInt((low + high) / 2),我们再来回顾下代码片段:

    while (low < high) {
      var mid = (low + high) >> 1;                                        // (1)
      iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; // (2)
    }
    

    (1)我们已经知晓,mid 取得了一个中间数值,在(2)中是一个三元运算符,解释起来,就是用一个有序数组 array 的中间数和目标数进行比较,则如果中间数比目标数小,就只需要比较中间数右侧的值,反之亦然。然后继续循环...

    等价于下面的代码,由此差距立显:

    while (low < high) {
      var mid = (low + high) >> 1;                                        
      var a = iterator(array[mid]);
      var b = iterator(obj)
      if(a == b) {
        return mid;
      } else if(a < b) {
        low = mid + 1;
      } else {
        high = mid
      } 
    }
    

    题外话

    内容照理说已经讲完了,但对于 >>运算符我还是有些疑虑。既然有a >> 1 === parseInt(a / 2) 那么可否假设 a >> 2 === parseInt(a / (2*2))呢?

    0 >> 2  // 0
    3 >> 2  // 0
    
    4 >> 2  // 1
    7 >> 2  // 1
    
    8 >> 2  // 2
    11 >> 2 // 2
    
    12 >> 2 // 3
    

    继而a >> 3 === parseInt(a / (2*2*2)),可得a >> n === parseInt(a / (X)) X 为 2 的 n 次方。

    左移运算符 <<

    与右移运算符相对的叫左移运算符,记为 <<,相信它也不是吃干饭的。

    有了前面的铺垫,我这里一步到位,假设有a << n === parseInt(a * (X)) X 为 2 的 n 次方。简单验证下:

    1 << 1 // 1*2 = 2
    2 << 1 // 2*2 = 4
    3 << 2 // 3 * (2*2) = 12
    5 << 4 // 5 * (2*2*2*2) = 80
    ...
    

    最后的最后,由于水平有限(大家看出来了,忍住不要笑:-D),文章内容连蒙带猜,没有经过特别严谨的证明,欢迎拍砖!!!

  • 相关阅读:
    [PHP]AES加密----PHP服务端和Android客户端
    [PHP]memcache安装
    [Android]apk反编译方法
    [PHP]生成随机数(建立字典)
    [PHP]Mysql的运用
    [PHP]对象数组和普通数组总结
    ThinkPHP5+Redis单例型购物车
    移动硬盘新建选项消失、不能新建文件夹和文件的解决方案
    PHP substr() 函数截取中文字符串乱码
    php开发中遇到问题的找错误的方法
  • 原文地址:https://www.cnblogs.com/fayin/p/7490469.html
Copyright © 2011-2022 走看看