二分查找概念

二分查找算法是在有序数组中用到的较为频繁的一种算法,二分查找其实是分治算法的一个实例;

针对有序表的查找方法,比较次数少,查找快,平均性能好。插入删除比较困难。一般用于有序的不常插入删除而查找频繁的表;
步骤:
1、获取表的中间键,将中间键与查找的键相比;
2、如果查找键小于中间键,则去中间键左半部分查,否则去中间键右半部分查找;
3、重复1,2步骤;
时间复杂度分析:
假设该数组的长度是N那么二分后是N/2,再二分后是N/4……直到二分到1结束,那么二分的次数就是比较的次数,于是我们可以设次数为x,N*(1/2)^x=1,按时间复杂度取最重要的增长量级即为lgN;
c#代码实现:
 public int search()
        {
            int key = 2;
            int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
            int low = 0;
            int high = a.Length - 1;Stack st = new Stack();
            while (low <= high)
            {
                int mid = low + (high - low) / 2;
                if (a[mid] > key)
                {
                    high = mid - 1;
                }
                else if (a[mid] < key)
                {
                    low = mid + 1;
                }
                else
                {
                    return mid;
                }
            }
            return -1;
        }

erlang代码实现(列表实现):

%% erlang实现的列表二分查找,erlang:length,erlang:nth等函数都可以用遍历实现,这里为了方便直接采用
binary_search(Key, List) ->
    High = erlang:length(List),
    Low = 1,
    do_binary_search(Low, High, Key, List).

do_binary_search(Low, High, _Key, _List) when Low > High -> %% 查找不到,返回-1
    -1;
do_binary_search(Low, High, Key, List) ->
    Mid = Low + (High - Low) div 2, %% 求出中间键
    Value = lists:nth(Mid, List), %% 获取中间键的值,尾递归遍历获取,性能消耗
    if Key > Value -> %% 大于中间键的值,去后半部分查找
        do_binary_search(Mid + 1, High, Key, List);
       Key < Value -> %% 小于中间键的值,去前半部分查找
        do_binary_search(Low, Mid - 1, Key, List);
       true -> %% 直接返回查找的键
           Mid
    end.
%%注意:传入的List是列表 ,因为lists:nth的遍历有较大的性能消耗;

erlang代码实现(tuple实现):

binary_search_tuple(Key, List) ->
    Tuple = erlang:list_to_tuple(List),
    High = erlang:tuple_size(Tuple),
    Low = 1,
    do_binary_search_tuple(Low, High, Key, Tuple).

do_binary_search_tuple(Low, High, _Key, _Tuple) when Low > High ->
    -1;
do_binary_search_tuple(Low, High, Key, Tuple) ->
    Mid = Low + (High - Low) div 2,
    Value = erlang:element(Mid, Tuple),
    if Key > Value ->
        do_binary_search_tuple(Mid + 1, High, Key, Tuple);
        Key < Value ->
            do_binary_search_tuple(Low, Mid - 1, Key, Tuple);
        true ->
            Mid
    end.

erlang(尾递归顺序查找、列表实现二分查找、元组实现二分查找)timer:tc测试:

1、10w条有序整数列表,查找key = 10w的多次测试平均时间:

(1)尾递归顺序查找:3177

(2)list实现的erlang二分查找:74770

(3)tuple实现的erlang二分查找:1090

2、100w条有序整数列表,查找key = 100w的多次测试平均时间:

(1)尾递归顺序查找:23929

(2)list实现的erlang二分查找:696093

(3)tuple实现的erlang二分查找:11835

3、上面测试结果可以看出当达到一定数量级时,tuple实现的方式效率会比较高。list方式实现因为list:nth是采用遍历的方式获取元素,会消耗性能。