众所周知,c++的STL中提供了三个二分查找函数,binary_search(),lower_bound(),upper_bound(),功能分别是找某值是否在数组中出现,找到数组中第一个大于等于某值的元素,找到数组中第一个大于某值的元素。

这三个函数使用十分灵活,可以通过自定义结构体,比较函数,重载大于小于号来实现各种用法,但是它们有一个共同的局限性,就是必须在数组上使用,而不能在整数上使用。

比如我要二分找一个数的向下取整的平方根,范围1e9,肯定不行,1e9的数组都开不了。

大佬的解决方法当然是手写二分辣,但是整数二分是以条件众多,难记难写著称的。所以今天开了一下脑洞,利用野指针实现整数二分。

首先我们观察lower_bound()和upper_bound()调用比较函数时的行为。

struct Example{
int index;
int num;
}exm[];
bool cmp(const Example &x,const Example &y){
printf("%d %d\n",x.index,y.index);
return x.num<y.num;
}
int main(){
for(int i=;i<=;i++){
exm[i].index=i;
exm[i].num=i;
}
Example t;
t.index=-;t.num=;
lower_bound(exm+,exm+,t,cmp);
upper_bound(exm+,exm+,t,cmp);
}
//51 -1
//26 -1
//39 -1
//45 -1
//48 -1
//50 -1
//49 -1
//-1 51
//-1 26
//-1 39
//-1 45
//-1 48
//-1 50

看出来了吧,lower_bound()在调用比较函数时,把数组元素传给比较函数的第一个参数,把待查找元素传给第二个参数

upper_bound()则相反。

自定义的比较函数对于这两个二分查找函数而言是个黑箱,只被关心返回值是几。

那么我们可以让比较函数只关心两个参数的地址,用这个地址瞎搞,不去真的访问这两个地址里面的值,比如刚才给出的例子,找平方根,可以这样写:

const int *p=;
bool cmp(const int &x,const int &y){
return (&x-p)<(&y-p)*(&y-p);
}
int main(){
int k;
scanf("%d",&k);
printf("%d",upper_bound(p+,p+k+,p[k],cmp)--p);
}
//91749281
//9578
//注意溢出

此方法的局限性:

1,指针长度有限制且无法自己定义。

#include<iostream>
#include<algorithm>
using namespace std;
int main(){
printf("the size of int* is %d\n",sizeof(int*));
printf("the size of long long is %d\n",sizeof(long long));
}
//the size of int* is 8
//the size of long long is 8

但是这个貌似没太大问题,因为所有指针,不管它指向什么,都是8位的,和long long一样长,足够了。

2,只能用于正数

指针运算没有负数,对于此种情况只能用设虚拟零点的方法解决。

3,存在非法访问的风险

目前笔者未找到任何证据能够证明二分查找函数本身不去访问指针指向的内容,有可能导致未知的非法访问。

奇思妙想:利用野指针和lower_bound()/upper_bound()函数实现整数二分的更多相关文章

  1. 李洪强iOS开发之【Objective-C】09-空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  2. 【Objective-C】4-空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  3. Objective-C 空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  4. 【Objective-C】09-空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储不论什么内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针.在没有被详细初始化之前.其值为0. 以下两个都是空 ...

  5. 【Objective-C】-空指针和野指针

    一.什么是空指针和野指针 1.空指针 1> 没有存储任何内存地址的指针就称为空指针(NULL指针) 2> 空指针就是被赋值为0的指针,在没有被具体初始化之前,其值为0. 下面两个都是空指针 ...

  6. C++中lower_bound函数和upper_bound函数

    STL中关于二分查找的函数有三个lower_bound .upper_bound .binary_search .这三个函数都运用于有序区间(当然这也是运用二分查找的前提),下面记录一下这两个函数. ...

  7. C语言之free函数及野指针

    [FROM MSDN && 百科] 原型:  void free(void *ptr); #include<stdlib.h>或#include <malloc.h& ...

  8. STL之std::set、std::map的lower_bound和upper_bound函数使用说明

    由于在使用std::map时感觉lower_bound和upper_bound函数了解不多,这里整理并记录下相关用法及功能. STL的map.multimap.set.multiset都有三个比较特殊 ...

  9. lower_bound和upper_bound函数

    lower_bound(ForwardIter first,ForwardIter last,const_TP & val) upper_bound(ForwardIter first,For ...

随机推荐

  1. 6374. 【NOIP2019模拟2019.10.04】结界[生与死的境界]

    题目 题目大意 给你一个数列,每次可以选择任意两个相邻的数\(x\)和\(y\),将其删去,并在原来位置插入\(x+2y\). 每次询问一个区间,对这个区间进行上述操作.求最后剩下的数最大是多少. 答 ...

  2. 【时间】Unix时间戳

    UNIX时间戳:Unix时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp) 是从1970年1月1日(UTC/GMT的午夜)开始所经过的 ...

  3. [HNOI2015]菜肴制作 题解(贪心+拓扑)

    Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予 1到N的顺序编号,预估质量最高的菜肴编号 ...

  4. SQLServer如何手动设置id值(主键)的自动增长

    近期做东西,用到了对SQLServer数据库的操作.好吧,确实好久没看了,对这个数据库陌生到了极点,连最简单的如何设置一个id主键,让它随着插入数据的增多,自动增长id值的设置都忘记了,网上查了一下, ...

  5. selenium之 文件上传所有方法整理总结

    本文转载“灰蓝”的原创博客.http://blog.csdn.net/huilan_same/article/details/52439546 文件上传是所有UI自动化测试都要面对的一个头疼问题,今天 ...

  6. Java-Class-@I:org.springframework.web.bind.annotation.PostMapping

    ylbtech-Java-Class-@I:org.springframework.web.bind.annotation.PostMapping 1.返回顶部   2.返回顶部 1. package ...

  7. jmeter 创建接口测试案例

    1 怎么做接口测试? 一般情况下,由于我们项目前后调用主要是基于http协议的接口,所以测试接口时主要是通过工具或代码模拟http请求的发送和接收.所以我们下面整理了一下使用Jmeter工具进行htt ...

  8. 剑指offer——66翻转字符串

    题目描述 牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上.同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思.例如,“student ...

  9. 剑指offer——49礼物的最大价值

    题目描述 在一个m*n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0).你可以从棋盘的左上角开始拿格子里的礼物,并每次向左或者向下移动一格,知道到达棋盘的右下角.给定一个棋盘及其上面 ...

  10. 前端(十五)—— JavaScript事件:绑定事件方式、事件的冒泡和默认事件、鼠标事件、键盘事件、表单 事件、文档事件、图片事件、页面事件

    JS事件:绑定事件方式.事件的冒泡和默认事件.鼠标事件.键盘事件.表单 事件.文档事件.图片事件.页面事件 一.事件的两种绑定方式 1.on事件绑定方式 document.onclick = func ...