zoukankan      html  css  js  c++  java
  • 二分查找(c & c++)

    typedef int ElemType;


    C版本号

    【递归版本号】

    int binSearch2(ElemType List[] ,int x,int head,int tail){ //递归版本号
    	while(head<=tail){
    		int mid=(head+tail)/2;
    		if(List[mid]==x){
    			return mid;
    		}
    			
    		else if(List[mid]>x){
    			return binSearch2(List,x,head,mid-1);
    		}
    		else{
    			return binSearch2(List,x,mid+1,tail);
    		}
    	}
    	return -1;
    }

    【迭代版本号】

    int binSearch(ElemType List[] ,int x,int head,int tail){ //循环版本号
    	while(head<=tail){
    		int mid=(head+tail)/2;
    		if(List[mid]==x)
    			return mid;
    		else if(List[mid]>x){ //注意别写反
    			tail=mid-1;
    		}
    		else{
    			head=mid+1;
    		}
    	}
    	return -1;
    }


    C++版本号

    上面是之前C语言的版本号。这里用C++再来实现。有三个版本号,顺便进行效率的分析。

    【版本号A】

    template <typename T> static int Binsearcha(T *arr ,int lo,int hi,T x){
    	while(lo < hi){
    		int mid = (lo + hi) >>1;
    		if(x <arr[mid]) hi = mid;
    		else if (arr[mid] < x) lo = mid + 1;
    		else return mid;
    	}
    	return -1; //查找失败
    }
    先看是否在左边,再看是否在右边,都不是就找到了。能够看出每次循环,假设x小于mid位置的元素 仅仅须要一次比較 。 而当mid位置的元素小于x则须要两次比較。这样就造成了效率的分差。即:当所找的元素在左边效率高。在右边效率低。经过课上的分析得出,版本号A的算法平均效率为&Theta;(1.50 log(n))。


    怎么优化呢? 左边查找效率高,右边效率低,那么我们取mid的时候不在中间取,而是多往hi靠近。

    也就是说增长左边的区间,缩短右边的区间。这样就能尽量的“平均”分配。 经过证明这个比例的最优版本号就是黄金切割 0.618: 0.382; 也就是斐波那契相邻两个数的比例。

    所以这个优化也能够称作是斐波那契查找。平均效率&Theta;(1.44 log(n)); 是这样的方法的最优效率。



    由于版本号B,C的二分查找效率更高 所以这里也不给出斐波那契查找的算法实现了。


    版本号A之所以效率低,无非是左右两边查找效率不同所致。事实上我们能够让他们变得同样。


    【版本号 B】

    template <typename T> static int Binsearchb(T *arr ,int lo,int hi,T x){
    	while(1 < hi - lo){
    		int mid = (lo + hi) >>1;
    		if(x <arr[mid]) hi = mid;
    		else lo = mid;
    	}
    	return (x == arr[lo]) ?

    lo : -1; }


    仅仅用if else 每次将区间分成两部分,取其一就可以。这样不管是大还是小都仅仅需比較1次。然后不断压缩区间。


    由于STL中区间都是左闭又开的[ a , b ) ,所以终于hi - lo == 1 终止循环就可以, lo 所在位置就是所找的元素。


    【版本号C】

    template <typename T> static int Binsearchc(T *arr ,int lo,int hi,T x){
    	while(lo < hi){
    		int mid = (lo + hi) >>1;
    		if(x <arr[mid]) hi = mid;
    		else lo = mid+1;
    	}
    	return --lo;
    }

    为了实现其它接口(比如 insert)的调用,我们希望这个函数返回的是 在arr中不大于x最后一个位置,因此在切割区间的时候我们我们尽量用lo去逼近所要查找的值

    终于结果无非是两个,①lo刚好等于要找的元素,②找到比要查找元素大的那个数(即序列中没有所找的元素x)。然后返回 -- lo , 也就是(在arr中不大于x的最后一个位置);


    能够看出在最好的情况版本号A的效率是O(1) , 平均效率 &Theta;(1.50 log(n))。

    版本号B和C的效率一直是 &Theta;(log(n)); 显然后者要更好。



  • 相关阅读:
    金步国作品列表
    GCC编译优化指南【作者:金步国】
    g++优化选项
    C++中实现对map按照value值进行排序
    C++ STL中Map的相关排序操作:按Key排序和按Value排序
    How-To: add EPEL repository to Centos 6.x is Easy!
    如何为linux释放内存和缓存
    用Python对体积较大的CSV文件进行比较的经验
    The mmap module
    Python逐块读取大文件行数的代码
  • 原文地址:https://www.cnblogs.com/wzzkaifa/p/7098421.html
Copyright © 2011-2022 走看看