概念

二分查找又称折半查找,优点是比较次数少,查找速度快,平均性能好;
其缺点是要求待查表为有序表,且插入删除困难。
因此,折半查找方法适用于不经常变动而查找频繁的有序列表。

思路

将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;
否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。
重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。

时间复杂度

假设其数组长度为n,其算法复杂度为o(log(n))

Javascript实现

var Arr=[3,5,6,7,9,12,15];
function binary(find,arr,low,high){
    if(low<=high){
        if(arr[low]==find) return low;
        if(arr[high]==find) return high;

        var mid=Math.ceil((high+low)/2);

        if(arr[mid]==find){
            return mid;
        }else if(arr[mid]>find){
            return binary(find,arr,low,mid-1);
        }else{
            return binary(find,arr,mid+1,high);
        }
    }
    return -1;
}
binary(15,Arr,0,Arr.length-1);

PS: 写了半个小时…

在chrome调试的时候,有些技巧能大大提高自己调试的效率。不断学习总结中。

  • command + p 文件查找
  • shift + command + p 文件内函数查找
  • 在Elements页,上下键遍历页面元素,左右键进行元素展开

Timeline 的使用

Profiles,Audits一直没有机会用,以后找时间研究下这个吧。

在看别人的代码时发现setTimeout(func,0)的写法很不解。为什么要settimeout 0?
在网上查资料都引入了单线程的JS这个话题。

一点点来看。

有这样一段代码

alert(1); 
setTimeout("alert(2)", 0); 
alert(3); 

按照正常的理解,延迟0秒就是不延迟执行嘛,但其实不是。输出的结果是1,3,2。

为什么会这样呢?

settimout函数造成一种多线程异步的假象,让你认为js可以顺序执行主逻辑的代码,并同时开另外一个线程去处理要延迟的代码。

但其实JS引擎是单线程,浏览器的一个页面只有一个线程在处理。

那么JS为什么会给人多线程的假象呢?

因为JS的运行是事件驱动的。

浏览器中很多行为都是异步的,鼠标点击,窗口拖拽等。如果响应这些事件呢?浏览器把这些异步的事件都放在放入一个行为队列中。
JS引擎单线程的,顺序处理队列中任务。

settimeout的延迟做某件事情并没有另开一个线程处理,而是在设定的延时时间到了之后在队列中新建了一个任务。

那么上面的代码就很好理解了。

alert(1)输出1之后,延迟0秒,队列中新建一个任务。

现在队列中有两个任务,一个是执行alert(3),一个是执行alert(2)。

由于js现在正处于alert(3)的任务中,所以会先执行完这个任务,再取任务队列中settimeout插入的alert(2)的任务。

setTimeout的执行时间点只是加入js主执行队列中的时间点,至于什么时候执行,是由js引擎线程按顺序执行的队列来决定。所以很多时候用setTimeout做动画不流畅的原因。

为什么要settimeout 0 呢?

setTimeout(func, 0)神奇在哪儿?那就是告诉js引擎,在0ms以后把func放到主事件队列中,等待当前的代码执行完毕再执行。

这里的关键就是改变了代码流程,把func的执行放到了等待当前的代码执行完毕再执行。

  • 让浏览器渲染当前的变化(很多浏览器UI render和js执行是放在一个线程中,线程阻塞会导致界面无法更新渲染)
  • 重新评估”script is running too long”警告

又引出一个问题

既然js多线程异步是假象,那么Ajax请求到底是不是异步呢?

继续查资料,查到了浏览器的一些工作机制。
浏览器是多线程的,每开一个页面都至少开有下面几个线程:

  • javascript引擎线程
  • UI界面渲染线程
  • 浏览器事件触发线程
  • Http请求线程

其中Http请求线程是执行完了就终止的线程,比如我们的Ajax请求。只要有一个ajax请求,浏览器就会开一个http请求线程去异步地执行。

当请求的状态变更时,如果先前已设置回调,这异步线程就产生状态变更事件放到 JavaScript引擎的事件处理队列中等待处理。
所以JavaScript引擎始终是单线程运行回调函数。

浏览器线程机制

参考资料:

1.Javascript是单线程的深入分析
2.Javascript可否多线程

所谓的唤醒,就是从浏览器端(或者微信等第三方的app)打开指定app的动作。

IOS上有Url scheme的概念,可以配置每个app的启动协议。就相当于用http的协议地址会默认打开Safari这个app一样。

那么在安卓app中如何设置呢?

只要在AndroidMainifest.xml中对你要启动的那个activity加入如下描述。

<activity
    android:name="com.android.demo.MainActivity"
    android:label="@string/app_name" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <intent-filter android:priority="4000">
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:host="homepae"
            android:scheme="myapp" />
    </intent-filter>

</activity>

那么当我在浏览器中访问如 “myapp://homepage”这个协议地址时,它就会唤醒com.android.demo.MainActivity这个客户端的页面。

有一些build文件总是自动生成,为了不想每次提交都更新到仓库里,可以在git的.gitignore文件中设置,忽略这些文件。

但是。

有的时候ignore失效,即使添加了忽略然并卵,为什么呢?

因为在git库中已存在了这些build文件,只要之前push过,这些文件都会加入git的跟踪中。

而.gitignore文件只对还没有加入跟踪的文件起作用。

那么解决办法就很明显了,两个字,删掉!

把原来在仓库里的文件删掉,重新和更新过的.gitignore文件一起提交。

之后ignore文件就生效了。

昨天有人问我知道盒子模型么?那必须的呀。width,height,margin,padding,border这些的嘛。

然后又问什么是box-sizing?好熟悉,但没概念了。

在说盒子模型的时候,肯定会说IE对盒子模型的支持和其他浏览器不一样。它的width是包含了padding和border的。

CSS3中新增box-sizing属性刚好可以解决这个问题,不用费心去算是否盒子模型不一致了。

box-sizing: content-box|border-box|inherit;

box-sizing的属性值有两种,(inherit继承就不说了)

  • content-box:border 和 padding 不计入width和height (默认的)
  • border-box :border 和 padding 计入width和height (IE那种的)

android 中有五种类型的 Log .

VERBOSE 类型调试信息,verbose啰嗦的意思 
DEBUG 类型调试信息, debug调试信息 
INFO  类型调试信息, 一般提示性的消息information 
WARN  类型调试信息,warning警告类型信息 
ERROR 类型调试信息,错误信息

那么怎么在logcat中打印出这几种类型的日志呢。

Android.util.Log类提供如下对应的方法。

Log.v(String tag, String msg); //VERBOSE 
Log.d(String tag, String msg); //DEBUG 
Log.i(String tag, String msg); //INFO 
Log.w(String tag, String msg); //WARN 
Log.e(String tag, String msg); //ERROR 

Tag为调试信息标签名称,msg为添加的调试信息 。

这样你可以根据tag,在DDMS中对不同类型的日志进行过滤查看。

但真正的项目中,我们会在 debug 的版本中输出 log,而在 release 版本的产品中关闭 log 的输出。

要控制日志的输出与否,我们仍需要自己根据当前环境去封装自己的Log类。

比如,在Release 版本的软件上将 DEBUG 置为 false :

public class Log {
 private static final boolean DEBUG = true;

 public static void v(String tag, String msg) {
     if(DEBUG) {
      android.util.Log.v(tag, msg);
     }
    }
    public static void v(String tag, String msg, Throwable tr) {
        if(DEBUG) {
         android.util.Log.v(tag, msg, tr);
        }
    }
    public static void d(String tag, String msg) {
        if(DEBUG) {
         android.util.Log.d(tag, msg);
        }
    }
    public static void d(String tag, String msg, Throwable tr) {
        if(DEBUG) {
         android.util.Log.d(tag, msg, tr);
        }
    }
    public static void i(String tag, String msg) {
        if(DEBUG) {
         android.util.Log.i(tag, msg);
        }
    }
    public static void i(String tag, String msg, Throwable tr) {
        if(DEBUG) {
         android.util.Log.i(tag, msg, tr);
        }
    }
    public static void w(String tag, String msg) {
        if(DEBUG) {
         android.util.Log.w(tag, msg);
        }
    }
    public static void w(String tag, String msg, Throwable tr) {
        if(DEBUG) {
         android.util.Log.w(tag, msg, tr);
        }
    }
    public static void w(String tag, Throwable tr) {
        if(DEBUG) {
         android.util.Log.w(tag, tr);
        }
    }
    public static void e(String tag, String msg) {
        if(DEBUG) {
         android.util.Log.e(tag, msg);
        }
    }
    public static void e(String tag, String msg, Throwable tr) {
        if(DEBUG) {
         android.util.Log.e(tag, msg, tr);
        }
    }
}

工作也好boring啊,虽然也是很有挑战性的项目,但又回到一个人工作的状态。

flighting都说得越来越没底气。

男朋友重新当了码农,也越来越忙了。一起加班一起写代码什么的真是够了。

找一个自己不会迷路的目标,然后每天迁入吧。

已安装了android studio, 但在mac的命令行输入adb,提示-bash: adb: command not found

解决办法:

  1. 首先找到你的android sdk目录。比如我的目录是在 /Users/Alice/Library/Android/sdk
  2. 终端切换至sdk目录下的platform-tools中,adb就在这个目录中。输入pwd命令,拷贝这个目录路径XXXX。
  3. 然后输入下面两个命令

    touch .bash_profile
    open -e .bash_profile
    
  4. 如果打开的文档里面已经有内容,我们只要之后添加;XXXX(注意前面一定要用分号隔开),
    如果是一个空白文档的话,我们就输入以下内容,然后保存。

    export PATH=${PATH}:/Users/Alice/Library/Android/sdk/platform-tools    
    
  5. 更新一下这个文件:

    source .bash_profile
    
  6. 之后再输入adb,应该就不会提示adb: command not found了。