这是一篇记录学习 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),文章内容连蒙带猜,没有经过特别严谨的证明,欢迎拍砖!!!

[underscore源码学习]——`>>` 运算符和二分查找的更多相关文章

  1. Underscore.js 源码学习笔记(上)

    版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}());  这样的东西,我们应该知道这是一个 IIFE(立即执行 ...

  2. [算法2-数组与字符串的查找与匹配] (.NET源码学习)

    [算法2-数组与字符串的查找与匹配] (.NET源码学习) 关键词:1. 数组查找(算法)   2. 字符串查找(算法)   3. C#中的String(源码)   4. 特性Attribute 与内 ...

  3. Underscore.js 源码学习笔记(下)

    上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...

  4. 【 js 基础 】【 源码学习 】源码设计 (持续更新)

    学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...

  5. 【 js 基础 】【 源码学习 】源码设计 (更新了backbone分析)

    学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析 第二部分:unders ...

  6. [算法1-排序](.NET源码学习)& LINQ & Lambda

    [算法1-排序](.NET源码学习)& LINQ & Lambda 说起排序算法,在日常实际开发中我们基本不在意这些事情,有API不用不是没事找事嘛.但必要的基础还是需要了解掌握. 排 ...

  7. [数据结构1.2-线性表] 动态数组ArrayList(.NET源码学习)

    [数据结构1.2-线性表] 动态数组ArrayList(.NET源码学习) 在C#中,存在常见的九种集合类型:动态数组ArrayList.列表List.排序列表SortedList.哈希表HashTa ...

  8. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  9. [数据结构-线性表1.2] 链表与 LinkedList<T>(.NET 源码学习)

    [数据结构-线性表1.2] 链表与 LinkedList<T> [注:本篇文章源码内容较少,分析度较浅,请酌情选择阅读] 关键词:链表(数据结构)    C#中的链表(源码)    可空类 ...

随机推荐

  1. dateframe取数据

    import numpy as npimport pandas as pd## x1=[1,2,3,4]# x2=[4,5,6,7]# x3=[7,8,9,10]# df=pd.DataFrame(# ...

  2. 上海第八中学 shader

    http://shiba.hpe.cn/jiaoyanzu/wuli/soft/xna.aspx?classId=4

  3. 为什么const对象只能调用const成员函数,而不能调用非const成员函数?

    在c++中,我们可以用const来定义一个const对象,const对象是不可以调用类中的非const成员函数,这是为什么呢?下面是我总结的一些原理. 假设有一个类,名字为test代码如下: clas ...

  4. String [] args是干什么的

         我相信应该有不少人都疑惑,main后面的这个String [] args是干什么的呢?今天,巩固就为你们解密.      这是干什么的呢?先给大家一个简单定义(本人比较讨厌上来就举例子,因为 ...

  5. 原生js:click和onclick本质的区别

    原生javascript的click在w3c里边的阐述是DOM button对象,也是html DOM click() 方法,可模拟在按钮上的一次鼠标单击. button 对象代表 HTML 文档中的 ...

  6. 第七章 介词(La préposition )

    法语中的介词是将两个同类或非同类的词连接在一起,把一个句中成分同另一个句子成分联系起来,并表明两者之间关系的词类.介词是一种无词性变化的词类. ★介词的形式 ()简单形式的介词,如: ()复合形式的介 ...

  7. 对call() apply() 方法的简单理解

    真的是非常简单的理解,我知道的并不多,在网上查找了很多的资料,还是只能了解一点皮毛,下面来整理出来,方便以后深入的去学习,也是对目前知道的知识点的巩固. 整理一些网上的经典解答: 1.一句话区分cal ...

  8. SPSS-非参数检验—两独立样本检验 案例解析

    今天跟大家研究和分享一下:spss非参数检验——两独立样本检验, 我还是引用教程里面的案例,以:一种产品有两种不同的工艺生产方法,那他们的使用寿命分别是否相同 下面进行假设:1:一种产品两种不同的工艺 ...

  9. 网络中路由器相关的名词理解LAN,WAN,WLAN

    1. LAN,全称Local Area Network,中文名叫做局域网. LAN是指在某一区域内由多台计算机互联成的计算机组.一般是方圆几千米以内. 局域网可以实现文件管理.应用软件共享.打印机共享 ...

  10. Bellman_ford货币兑换——正权回路判断

    POJ1860 题目大意:你在某一点有一些钱,给定你两点之间钱得兑换规则,问你有没有办法使你手里的钱增多.就是想看看转一圈我的钱能不能增多,出现这一点得条件就是有兑换钱得正权回路,所以选择用bellm ...