【C++】bsearch函数的使用及二分法查找介绍

news2024/9/20 12:41:56

写程序的时候,肯定避免不了需要从集合中找到符合条件的元素,一般情况下,最简单也最常用的就是循环遍历元素,这种方法虽然写的简单,但是小数据量还行,但是数据过大的话,这样效率就低了。循环的时候,比如你要的数据正好在集合的最后,那就需要把前面的每一个元素都要对比一次,如果你要查找的数据,正好在前几个,那就很快找到到了。但数据这东西毕竟不是可控的。

所以,要查找,我们就要采用一点技巧和方法,在C/C++中,搜索的时候,可以使用bsearch函数来实现元素的查找,这个函数定义在头文件stdlib.h中,使用方式如下:

本文所有代码在 cygwin,gcc 11.3,gdb 11.2 中编译调试

bsearch的基本使用方法

bsearch函数的使用方法简单,函数定义如下

void* bsearch( const void *key, const void *ptr, size_t count, size_t size,
                int (*comp)(const void*, const void*) );

具体参数如下

key - 指向要查找的元素的指针 
ptr - 指向要检验的数组的指针 
count - 数组的元素数目 
size - 数组每个元素的字节数 
comp - 比较函数。若首个参数小于第二个,则返回负整数值,若首个参数大于第二个,则返回正整数值,若两参数等价,则返回零。 将 key 传给首个参数,数组中的元素传给第二个。 

comp函数的定义如下

int cmp(const void *a, const void *b);

cmp参数说明:a表示要查找的那个元素,b表示查找数组里的元素

举例如下,从数组f中查找x,如果找到就打印“找到11”,没找到就打印"没找到11"

#include <stdio.h>
#include <stdlib.h>  
const int x = 11;
const int f[] = { 1,3,6,9,11 };
int cmp(const void *a, const void *b) {
   int x1 = (int)(*(int*)a);
   int x2 = (int)(*(int*)b);
   printf("x1:%d\n", x1);
   printf("x2:%d\n", x2);
   if (x1 < x2) return -1;
   else if (x1 > x2) return 1;
   else return 0;
}
int main(int, char**) {
   int* c = (int*)bsearch(&x, f, 5, sizeof (int), cmp);
   if( c != NULL ) 
   {
      printf("找到%d\n",x);
   }
   else 
   {
      printf("没找到%d\n",x);
   }
   return 1;
}

输出如下

x1:11
x2:6
x1:11
x2:11
找到 11

可以看到,通过bsearch函数,从f中找到了11

但是,观察cmp函数中的两行printf代码

printf("x1:%d\n", x1);
printf("x2:%d\n", x2);

它表示打印要查找的元素,也就是上例的x,x2表示被查找的f中的某个元素,通过观察输出的结果,可以发现,虽然f数组中有{ 1,3,6,9,11 }5个元素,但实际上,比较函数并没有比较全部元素,只比较的两次就找到了11.

这就是文章开头说到的,循环遍历会降低效率,而使用bsearch会让查找速度加快,应为bsearch的查找并非遍历元素,而是采用了二分法查找,bsearch的第一个字幕b代表的就是Bisection/baɪˈsekʃən/,中文意思为“二等分"

关于二分法查找

在查找上使用二分法,是通过多次切分被查找的数组,然后和要查找的元素组做对比,具体步骤如下

假设数组为arr,要查找的元素为key,数组长度为len,进行如下操作

1.把被查找的数组长度除以2,得到的中间值mid,作为索引,去数组中取值arr[mid]

2.使用比对函数进行对比,第一步取到的arr[mid]和要查找的值key如果,返回的值小于0,也就说明要查找的值key,在数组的索引为0到mid中间。然后,修改要查找的数组起始位置,重复第一步,在0到mid中间查找

如果返回的值大于0,就说明要查找的值key,在数组的索引为mid到数组的最后一个元素之间。然后修改要查找的数组起始位置,重复第一步,在arr[mid]到最后个元素中间查找

3.重复如上2,3步,然后最终找到你要找的值

4.如果返回返回0,说明找到了,可以返回了

例如

从[1,2,3,4,5]中,找到4

  1. 5/2 = 2,先找到索引是2的3
  2. 因为3比4小,说明4在索引2以后
  3. (2+1+5)/2 = 4, 索引4就是5 ,比4大所以,在所以在索引4以前,3以后
  4. (3+4)/2 = 3,索引3就是4,找到了

以上就是使用二分法的流程

自己实现一个bsearch

void * mybsearch(const void* base, int len, int size, const void* key, int (*cmp)(const void* a, const void* b))
{
    size_t low = 0, high = len;
    while (low < high)
    {
          int mid = (low + high) / 2;
          void * p = (void *) (((const char *) base) + (mid * size));
          int comret  = (*cmp) (key,p);
          if (comret < 0)
                high = mid;
          else if (comret > 0)
                low = mid + 1;
          else
          return p;
    }
    return NULL;
}

然后还是刚才的代码

#include <stdio.h>
#include <stdlib.h>  
const int x = 11;
const int f[] = { 1,3,6,9,11 };
int cmp(const void *a, const void *b) {
   int x1 = (int)(*(int*)a);
   int x2 = (int)(*(int*)b);
   printf("x1:%d\n", x1);
   printf("x2:%d\n", x2);
   if (x1 < x2) return -1;
   else if (x1 > x2) return 1;
   else return 0;
}
int main(int, char**) {
   int* c = (int*)mybsearch(f,5, sizeof (int), &x, cmp);
   if( c != NULL ) 
   {
      printf("找到%d\n",x);
   }
   else 
   {
      printf("没找到%d\n",x);
   }
   return 1;
}

执行一下,看结果

x1:11
x2:6
x1:11
x2:11
找到 11

运行结果正确

知道的二分法的原理,就知道bsearch该如何使用,什么情况下,bsearch就找不到你要的元素

例如,如果把要查找的数组和要查找的元素修改为

const int x = 2;
const int f[] = { 1,3,6,9,2 };

的话,bsearch就无法从f中找到2,因为你的数组并不是单调的,按照二分法的查找方式,就找不到
在这里插入图片描述

所以,使用bsearch时候,如果不能确认数组是排序好的,就要先调用qsort把数组排序好,然后在使用查找

在这里插入图片描述
如上例,经过qsort以后,数据会排序好,然后就能正常使用bsearch了
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/391843.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅谈游戏中运用到的人工智能

电子游戏中的人工智能意味着电子游戏中角色的创造性行为就像人类游戏玩家正在控制他们一样。它提供了自适应和响应式的视频游戏体验。1949年初&#xff0c;密码学家克劳德香农发现了游戏中的人工智能&#xff0c;从而联想到了电脑上的单人国际象棋游戏。对于人工智能的发展&…

Android的基础介绍

一、Android介绍 Android是一种基于Linux的自由及开放源代码的操作系统,Android 分为四个层,从高层到低层分别是应用程序层、应用程序框架层、系统运行库层和Linux内核层。 Android 是Google开发的基于Linux平台的开源手机操作系统。它包括操作系统、用户界面和应用程序——…

力扣-可回收且低脂的产品

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道超级超级超级简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1757. 可回收且低脂的产品二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交S…

iview tree树形菜单实践之数据回显与选中

iview tree树形菜单在使用过程中&#xff0c;多多少少有一些小坑&#xff0c;本文简单罗列几个&#xff1a; 避坑指南&#xff1a; 关于iview tree树形菜单在使用过程中存在父级菜单的数据传输和回显问题 简单就是两个方面&#xff1a;勾选后数据传输和回显问题。 一&#xff…

mac 环境下安装MongoDB

目录 一、下载MongoDB数据库并进行安装 二. 解压放在/usr/local目录下 三. 配置环境变量 “无法验证开发者”的解决方法 mongodb可视化工具的安装与使用 一、下载MongoDB数据库并进行安装 下载地址&#xff1a;https://www.mongodb.com/try/download/community 二. 解压…

大数据项目实战之数据仓库:用户行为采集平台——第2章 项目需求及架构设计

第2章 项目需求及架构设计 2.1 项目需求分析 1&#xff09;采集平台 &#xff08;1&#xff09;用户行为数据采集平台搭建 &#xff08;2&#xff09;业务数据采集平台搭建 2&#xff09;离线需求 3&#xff09;实时需求 4&#xff09;思考题 1、项目技术如何选型&…

索引调优的一点基础知识

索引是什么 通过 show profile for query 1&#xff1b; 可以查看该查询语句执行的整个过程&#xff0c;则我们就能分析出那部分是需要优化的索引是帮助Mysql高效获取数据的数据结构 索引存储在文件系统中 索引的文件存储形式与存储引擎有关 索引文件的结构 hash 范围查找不方便…

深度学习-第T2周——彩色图片分类

深度学习-第T2周——彩色图片分类深度学习-第P1周——实现mnist手写数字识别一、前言二、我的环境三、前期工作1、导入依赖项并设置GPU2、导入数据集3、归一化4、可视化图片四、构建简单的CNN网络五、编译并训练模型1、设置超参数2、编写训练函数六、预测七、模型评估深度学习-…

产品经理如何去做需求分析,建议收藏

目录 一、需求收集 1. 产品需求 2. 功能需求 3. 迭代需求 二、需求分析 1. 系统了解需求&#xff08;5W2H法&#xff09; 2. 判断需求真实性 3. 分析现有解决方案-竞品分析 4. 行业结构分析 5. 总结 三、方案验证 四、商业模式 五、路线规划 六、战略制定 七、总…

基于贝叶斯优化CNN-LSTM混合神经网络预测(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密…

监控视频模糊看不清怎么处理提高监控视频清晰度?

随着监控设备的日益普及&#xff0c;监控视频的画质也成为了人们关注的焦点。然而&#xff0c;很多人反映监控视频画质不佳&#xff0c;有些甚至看不清。那么&#xff0c;对于这样的问题&#xff0c;我们该如何去处理呢&#xff1f;监控画面模糊变清晰处理方法如下&#xff1a;…

网上购物网站的设计

技术&#xff1a;Java、JSP等摘要&#xff1a;本文介绍了JSP和JAVA等相关技术&#xff0c;针对网上购物系统的实际需求&#xff0c;设计开发了一个基于JSP的小型电子商务网站也就是网上购物系统&#xff0c;。在设计开发中&#xff0c;采用的是SSH框架&#xff08;strutsspring…

一篇教你解决如何在不加锁的情况下解决多线程问题!

怎样在不加锁的情况下解决线程安全问题&#xff0c;你需要了解lock free和wait free这两个概念&#xff0c;在此之前我们先从最简单的有锁编程开始。 我们知道&#xff0c;多线程同时修改共享变量时会出现数据不一致的问题&#xff0c;比如多个线程同时对一个变量加1&#xff…

angular自定义实现管道

参考angular官方文档角 - 管 (angular.io)选择描述name要在模板绑定中使用的管道名称。 通常使用较小的驼峰大小写&#xff0c;因为名称不能包含连字符。pure?如果为 true&#xff0c;则管道是纯的&#xff0c;这意味着仅当该方法的输入参数时才调用该方法 改变。默认情况下&a…

JavaScript基础四、集合类型

零、文章目录 文章地址 个人博客-CSDN地址&#xff1a;https://blog.csdn.net/liyou123456789个人博客-GiteePages&#xff1a;https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee&#xff1a;https://gitee.com/bluecusliyou/TechLearnGithub&#xff1a;https:…

C++源程序的构成————学习笔记

以下内容为&#xff0c;在学校上课时的课堂总结&#xff0c;偶尔我也会扩展一些内容内容仅供参考&#xff0c;欢迎大佬的指正简单的C程序#include <iostream> using namespace std;int main() {int x0;int y 0;cout << "请输入x,y的值"<<endl;cin…

计算机网络第八版——第二章课后题答案(超详细)

第二章 该答案为博主在网络上整理&#xff0c;排版不易&#xff0c;希望大家多多点赞支持。后续将会持续更新&#xff08;可以给博主点个关注~ 第一章 答案 【2-01】物理层要解决哪些问题&#xff1f;物理层的主要特点是什么&#xff1f; 解答&#xff1a;物理层考虑的是怎…

《C++代码分析》第二回:函数重载const char* ,char*,const char[],char[]汇编代码上的区别

一、前言 C相比C是支持函数重载的&#xff0c;现在我们详细探讨一下C函数重载与类方法承载。 二、案例代码 我们编译如下代码&#xff0c;同样的我们关闭代码优化&#xff0c;删除符号链接文&#xff08;.pdb&#xff09; #include "windows.h" #include "w…

php宝塔搭建部署实战兰空图床程序网站PHP源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套Lsky Pro兰空图床程序网站PHP的源码。感兴趣的朋友可以自行下载学习。 技术架构 PHP8.0 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&#xff0c;宝塔添加…

开源监控服务uptime-kuma

好久没写文章了&#xff0c;刚好最近用了一个开源的监控服务&#xff0c;感觉蛮有意思的&#xff0c;记录一下 &#xff08;一&#xff09;安装 uptime-kuma安装方式有几种&#xff0c;这里当然是选择大家都爱的docker,一条命令搞定 docker run -d --restartalways -p 3001:…