与排序算法不同,搜索算法是比较统一的,常用的搜索除hash外仅有两种,包括不需要排序的线性搜索和需要排序的binary search。

首先介绍一下binary search,其原理很直接,不断地选取有序数组的组中值,比较组中值与目标的大小,继续搜索目标所在的一半,直到找到目标,递归算法可以很直观的表现这个描述:

int binarySearchRecursive(int A[], int low, int high, int key)
{
if (low > high) return -;
int mid = (low + high) >> ;
if (key < A[mid]) return binarySearchRecursive(A, low, mid - , key);
else if (key > A[mid]) return binarySearchRecursive(A, mid + , high, key);
else return mid;
}

但实际上,递归方法的时间效率和空间效率都不如迭代方法,迭代方法才是常用的binary search,代码如下:

int binarySearch(int A[], int low, int high, int key)
{
int mid;
while (low <= high)
{
mid = (low + high) >> ;
if (key < A[mid]) high = mid - ;
else if (key > A[mid]) low = mid + ;
else return mid;
}
return -;
}

简单计算一下Binary Search的效率:

算法流程:

1.检查上下边界--2.获取中值--3.比较--左半边进入子问题/右半边进入自问题/获得结果

1,2所需时间为常数时间,设为C。3阶段以一半的数据量重新运行函数,所以:

T(n)=T(n/2)+C

设n=2^k,则有T(2^k)=T(2^(k-1))+C=(T(2^(k-2))+C)+C=T(1)+k*C

即T(n)=log(n)*C+T(1),所以binary search是一个O(log(n))的算法。

测试函数:

void searchTest()
{
int a[] = { ,,,,,,,,,,, };
cout << binarySearch(a, , , ) << endl;
cout << binarySearch(a, , , ) << endl;
cout << binarySearch(a, , , ) << endl;
cout << endl;
cout << binarySearchRecursive(a, , , ) << endl;
cout << binarySearchRecursive(a, , , ) << endl;
cout << binarySearchRecursive(a, , , ) << endl;
}

测试结果如下:

11
-1
-1

11
-1
-1
请按任意键继续. . .

传统C函数中有bsearch这一函数,因为在现代C++中使用C库运行效率很低,加上接口并不好用,不再提及。而STL中,有以下几个关于搜索的函数。他们均作用于各个STL容器。

int count(起始迭代器,终止迭代器,key value)

return key value的数量

iterator find(起始迭代器,终止迭代器,key value)

成功:return 找到的第一个key value的迭代器

失败:return 终止迭代器

bool binary_search(起始迭代器,终止迭代器,key value)

return 是否找到

iterator lower_bound(起始迭代器,终止迭代器,key value)

return 大于或等于key value的第一个迭代器,若所有值都小于key value,返回终止迭代器

iterator upper_bound(起始迭代器,终止迭代器,key value)

return 大于key value的第一个迭代器,若所有值都小于key value,返回终止迭代器

这些函数中,count和find是作用于任意排序对象的,其效率为O(n),而binary_search, lower_bound, upper_bound是作用于有序对象的,其效率是O(logN)。

下面代码给出这些STL函数的测试:

void searchTest()
{
vector<int> b{ ,,,,,,,,,,, };
cout << "vector<int> b{ 1,2,3,4,4,7,9,11,17,20,23,39 };" << endl;
cout << "count(b.begin(), b.end(), 4):"
<< count(b.begin(), b.end(), ) << endl;
cout << endl;
cout << "find(b.begin(), b.end(), 39) - b.begin():"
<< find(b.begin(), b.end(), ) - b.begin() << endl;
cout << "find(b.begin(), b.end(), 4) - b.begin():"
<< find(b.begin(), b.end(), ) - b.begin() << endl;
cout << "find(b.begin(), b.end(), 37) - b.begin():"
<< find(b.begin(), b.end(), ) - b.begin() << endl;
cout << "find(b.begin() + 5, b.begin() + 10, 39) - b.begin():"
<< find(b.begin() + , b.begin() + , ) - b.begin() << endl;
cout << endl;
cout << "binary_search(b.begin(), b.end(), 39):"
<< binary_search(b.begin(), b.end(), ) << endl;
cout << "binary_search(b.begin(), b.end(), 37):"
<< binary_search(b.begin(), b.end(), ) << endl;
cout << endl;
cout << "lower_bound(b.begin(), b.end(), 39) - b.begin():"
<< lower_bound(b.begin(), b.end(), ) - b.begin() << endl;
cout << "lower_bound(b.begin(), b.end(), 4) - b.begin():"
<< lower_bound(b.begin(), b.end(), ) - b.begin() << endl;
cout << "lower_bound(b.begin(), b.end(), 37) - b.begin():"
<< lower_bound(b.begin(), b.end(), ) - b.begin() << endl;
cout << "lower_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():"
<< lower_bound(b.begin() + , b.begin() + , ) - b.begin() << endl;
cout << endl;
cout << "upper_bound(b.begin(), b.end(), 39) - b.begin():"
<< upper_bound(b.begin(), b.end(), ) - b.begin() << endl;
cout << "upper_bound(b.begin(), b.end(), 4) - b.begin():"
<< upper_bound(b.begin(), b.end(), ) - b.begin() << endl;
cout << "upper_bound(b.begin(), b.end(), 37) - b.begin():"
<< upper_bound(b.begin(), b.end(), ) - b.begin() << endl;
cout << "upper_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():"
<< upper_bound(b.begin() + , b.begin() + , ) - b.begin() << endl;
}

测试结果:

vector<int> b{ 1,2,3,4,4,7,9,11,17,20,23,39 };
count(b.begin(), b.end(), 4):2

find(b.begin(), b.end(), 39) - b.begin():11
find(b.begin(), b.end(), 4) - b.begin():3
find(b.begin(), b.end(), 37) - b.begin():12
find(b.begin() + 5, b.begin() + 10, 39) - b.begin():10

binary_search(b.begin(), b.end(), 39):1
binary_search(b.begin(), b.end(), 37):0

lower_bound(b.begin(), b.end(), 39) - b.begin():11
lower_bound(b.begin(), b.end(), 4) - b.begin():3
lower_bound(b.begin(), b.end(), 37) - b.begin():11
lower_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():10

upper_bound(b.begin(), b.end(), 39) - b.begin():12
upper_bound(b.begin(), b.end(), 4) - b.begin():5
upper_bound(b.begin(), b.end(), 37) - b.begin():11
upper_bound(b.begin() + 5, b.begin() + 10, 39) - b.begin():10
请按任意键继续. . .

Binary Search 的递归与迭代实现及STL中的搜索相关内容的更多相关文章

  1. Binary Search(Java)(递归)

    public static int rank(int[] array, int k, int front, int rear) { if(front > rear) return -1; int ...

  2. 【Leetcode】【Medium】Validate Binary Search Tree

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  3. Trie(前缀树)和ternary trie和binary search tree

    1 什么是trie trie是一棵多叉树,假如存放的是由26个字母(不区分大小写)构成的字符串的话,那么就是一棵26叉树. trie树是一棵前缀树,因为每个结点只保存字符串中的一个字符,整个字符串保存 ...

  4. BINARY SEARCH 的一点说明

    在sap 之abap语言中,有‍BINARY SEARCH这个查找条件.使用read table 来读取内表时,使用‍BINARY SEARCH可以大大的提高查找的效率,为什么呢?学过数据库的人会知道 ...

  5. (BST 递归) leetcode98. Validate Binary Search Tree

    Given a binary tree, determine if it is a valid binary search tree (BST). Assume a BST is defined as ...

  6. 二叉树前序、中序、后序非递归遍历 144. Binary Tree Preorder Traversal 、 94. Binary Tree Inorder Traversal 、145. Binary Tree Postorder Traversal 、173. Binary Search Tree Iterator

    144. Binary Tree Preorder Traversal 前序的非递归遍历:用堆来实现 如果把这个代码改成先向堆存储左节点再存储右节点,就变成了每一行从右向左打印 如果用队列替代堆,并且 ...

  7. 二分查找(Binary Search)的递归和非递归

    Binary Search 有时候我们也把它叫做二进制查找 是一种较为高效的再数组中查找目标元素的方法 我们可以通过递归和非递归两种方式来实现它 //非递归 public static int bin ...

  8. Lowest Common Ancestor of a Binary Search Tree(Java 递归与非递归)

    题目描述: Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in ...

  9. [LeetCode] Closest Binary Search Tree Value 最近的二分搜索树的值

    Given a non-empty binary search tree and a target value, find the value in the BST that is closest t ...

随机推荐

  1. 02_Android写xml文件和读xml文件

     新建Android项目 编写AndroidManifest.xml,使本Android项目具有单元测试功能和写外设的权限. <?xml .控制台输出结果

  2. SwiftyiRate中文说明

    SwiftyiRate Github SwiftyiRate Swift语言实现的app内评分,简单易用. Requirements Integration Usage Initialization ...

  3. Css的学习之旅-css的选择器(2)

    1.最常用的是派生选择器:eg:ul li{ color:red} 2.id选择器:eg:#id{color:red} 3.类选择器:设置标签的class = "",类似id.用点 ...

  4. 使用Visual Studio创建图片精灵(Image Sprite)——Web Essential

    原文:Creating Image Sprite in Visual Studio - Web Essential 译者注:有关图片精灵的信息请参阅http://baike.baidu.com/vie ...

  5. java5后的并发池

    本文可作为传智播客<张孝祥-Java多线程与并发库高级应用>视频的学习记录. 为什么需要并发池 之前写并发的时候 new Thread(new Runnable(){ public voi ...

  6. How tomcat works 读书笔记十七 启动tomcat 上

    一路跋山涉水,这是最后一章了. 关于tomcat的启动,有两个类,一个是Catalina类,一个是Bootstrap类. 理论上,两个类可以和到一起,但是为了支持多种运行模式,又把他们分开了. 为了让 ...

  7. Unity Web自适应浏览器

    unity web的自适应浏览器比我想象中要更简单,但是这里也只有更改最简单的东西实现了自适应.发布web时,在playersetting里面设置分辨率为你在Game窗口自定义的分辨率大小,以保证内容 ...

  8. HBase 二级索引与Join

    二级索引与索引Join是Online业务系统要求存储引擎提供的基本特性.RDBMS支持得比较好,NOSQL阵营也在摸索着符合自身特点的最佳解决方案. 这篇文章会以HBase做为对象来探讨如何基于Hba ...

  9. obj-c中如何定义类的私有实例方法

    obj-c原生没有提供此项机制,不像java有private/protected/public方法的概念.obj-c中的@private以及类似的@protected和@public是用于修饰类的实例 ...

  10. ubuntu安装最新的rails-4.2.0

    完全按照教程来,可是错误不断,还是边装边baidu吧! sudo gem install rails 安装了一大坨关联gem之后,终于好了.于是想小试一下身手,新建文件夹rails_test,cd进入 ...