二分查找

【数据结构】二分查找和二分搜索(排序)树总结

本秂侑毒 提交于 2020-01-15 07:10:46
二分查找法 注意边界的关系 // 二分查找法,在有序数组arr中,查找target // 如果找到target,返回相应的索引index // 如果没有找到target,返回-1 template<typename T> int binarySearch(T arr[], int n, T target){ // 在arr[l...r]之中查找target int l = 0, r = n-1; while( l <= r ){ //直到l大于r的时候这个边界才会消失 //int mid = (l + r)/2; 这个可能会出现越界问题 int mid = l + (r-l)/2; //用最小的值加一个范围再除以2 if( arr[mid] == target ) return mid; if( arr[mid] > target ) r = mid - 1; else l = mid + 1; } return -1; } // 用递归的方式写二分查找法 template<typename T> int __binarySearch2(T arr[], int l, int r, T target){ if( l > r ) return -1; int mid = (l+r)/2; if( arr[mid] == target ) return mid; else if(

数据库索引的使用

浪尽此生 提交于 2020-01-14 18:38:10
数据库索引工作原理 转载至:http://www.ituring.com.cn/article/986 译者按 :今天在翻译时无意中搜索到StackOverflow中的这篇文章(问答),觉得有必要翻译出来。不仅因为文章本身写得精彩,更重要的是它昭示了一个写文章(特别是技术文章)的重要法则——5W1H。 原文在此 How does database indexing work? (作者: Xenph Yan ) 问:随着数据库的增大,既然索引的作用那么重要,有谁能抛开具体的数据库来解释一下索引的工作原理? 答:(我自己来回答这个问题,😎) 为什么需要索引 数据在磁盘上是以块的形式存储的。为确保对磁盘操作的原子性,访问数据的时候会一并访问所有数据块。磁盘上的这些数据块与链表类似,即它们都包含一个数据段和一个指针,指针指向下一个节点(数据块)的内存地址,而且它们都不需要连续存储(即逻辑上相邻的数据块在物理上可以相隔很远)。 鉴于很多记录只能做到按一个字段排序,所以要查询某个未经排序的字段,就需要使用线性查找,即要访问N/2个数据块,其中N指的是一个表所涵盖的所有数据块。如果该字段是非键字段(也就是说,不包含唯一值),那么就要搜索整个表空间,即要访问全部N个数据块。 然而,对于经过排序的字段,可以使用二分查找,因此只要访问log2 N个数据块。同样,对于已经排过序的非键字段

二分查找(上):如何用最省内存的方式实现快速查找功能?

岁酱吖の 提交于 2020-01-12 12:01:57
二分查找(上):如何用最省内存的方式实现快速查找功能? 针对有序数据集合的查找算法:二分查找算法也叫折半查找算法 假设我们有1000W个整数数据,每个数据占8个字节,如何设计数据结构和算法,快速判断某个整数是否出现在这1000W数据中?最后不要占用太多的内存空间,不要超过100M? 假设我们要猜测0-99之间的数据,你来猜写的什么数字,如果是23(如果猜测范围的数字有偶数个,中间数有两个,就选择较小的那个) 次数 猜测范围 中间数 对比大小 第一次 0-99 49 49 > 23 第二次 0-48 24 24 > 23 第三次 0-23 11 11 < 23 第四次 12-23 17 17 <23 第五次 18-23 20 20 < 23 第六次 21-23 22 22 < 23 第七次 23 √ 假设有1000个订单金额,已经按照从小到大排序,现在想知道有没有=19的订单,如何存在,返回订单数据,不存在返回null 订单金额分别为8,11,19,23,27,33,45,55,67,98,low和high表示待查找区间的下标,mid表示待查找区间的中间元素下标,第一次:low = 8 ,mid = 27,high = 98,第二次 : low = 8 ,mid = 11,high = 23,第三次:low =19 , mid = 19 , high = 23 O(logn

B树、B-树、B+树、B*树

无人久伴 提交于 2020-01-12 07:44:16
B树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right); 2.所有结点存储一个关键字; 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树; 如: B树的搜索,从根结点开始,如果查询的关键字与结点的关键字相等,那么就命中; 否则,如果查询关键字比结点关键字小,就进入左儿子;如果比结点关键字大,就进入 右儿子;如果左儿子或右儿子的指针为空,则报告找不到相应的关键字; 如果B树的所有非叶子结点的左右子树的结点数目均保持差不多(平衡),那么B树 的搜索性能逼近二分查找;但它比连续内存空间的二分查找的优点是,改变B树结构 (插入与删除结点)不需要移动大段的内存数据,甚至通常是常数开销; 如: 但B树在经过多次插入与删除后,有可能导致不同的结构 上边也是一个B树,但它的搜索性能已经是线性的了;同样的关键字集合有可能导致不同的 树结构索引;所以,使用B树还要考虑尽可能让B树保持左图的结构,和避免右图的结构,也就 是所谓的“平衡”问题; 实际使用的B树都是在原B树的基础上加上平衡算法,即“平衡二叉树”;如何保持B树 结点分布均匀的平衡算法是平衡二叉树的关键;平衡算法是一种在B树中插入和删除结点的 策略; 2、 B-树 是一种多路搜索树(并不是二叉的): 1.定义任意非叶子结点最多只有M个儿子;且M>2; 2.根结点的儿子数为[2, M]; 3

11-接下来如何做

旧城冷巷雨未停 提交于 2020-01-12 05:18:34
1.树 在前面的二分查找示例中,每当用户登陆Facebook,Facebook都必须在一个庞大的数组中查找,核实其中是否包含指定的用户名。在这种数组中查找,最快的方式是二分查找,但问题是每当有新用户注册时,都必须将其用户名插入该数组并重新排序,因为二分查找仅在数组有序时才管用。如果能将用户名插入到数组的正确位置就好了,这样就无需在插入后再排序。为此,有人设计了一种名为二叉查找树的数据结构。 对于其中的每个节点,左子节点的值都比它小,而右子节点的值都比它大。 假设要查找Maggie,首先检查根节点。Maggie排在David的后面,因此你往右找。Maggie排在Manning前面,因此你往前找。 二叉查找树用时为O(log 2 n)几乎与二分查找一样,但在最糟的情况下所需时间为O(n);而在有序数组中查找时,即便是在最糟情况下所需的时间也只有O(log 2 n),但是二叉查找树的插入和删除操作的速度要快得多。 操作 有序数组 二叉查找树 查找 O(log 2 n) O(log 2 n) 插入 O(n) O(log 2 n) 删除 O(n) O(log 2 n) 二叉查找树的缺点:不能随机访问,例如给我第5个元素。在二叉查找树处于平衡状态时平均访问时间也为O(log 2 n)。 假设二叉查找树像下面这样处于不平衡状态。 注意,这棵树是向右倾斜的,因此性能不佳

离散化+线段树/二分查找/尺取法 HDOJ 4325 Flowers

放肆的年华 提交于 2020-01-11 10:02:15
题目传送门 题意:给出一些花开花落的时间,问某个时间花开的有几朵 分析:这题有好几种做法,正解应该是离散化坐标后用线段树成端更新和单点询问。还有排序后二分查找询问点之前总花开数和总花凋谢数,作差是当前花开的数量,放张图易理解: 还有一种做法用尺取法的思想,对暴力方法优化,对询问点排序后再扫描一遍,花开+1,花谢-1。详细看代码。 收获:一题收获很多:1. 降低复杂度可以用二分 2. 线段计数问题可以在端点标记1和-1 3. 离散化+线段树 终于会了:) ( 听说数据很水? ) 代码1:离散化+线段树 /************************************************ * Author :Running_Time * Created Time :2015-8-25 8:55:54 * File Name :F.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue>

算法学习:二分查找法法

坚强是说给别人听的谎言 提交于 2020-01-11 00:40:09
通常在查找数组的时候,会发现一个一个查找很浪费资源,因此通过二分查找法,实现 (上面是思维导图) #include<stdio.h> #include <windows.h> //while、do while 、goto、for、递归 void digui(int shang,int xia,int zhong,int num) { zhong = (shang + xia) / 2; if (shang <= xia) { if (num == zhong) { printf("递归:find.%d\n", zhong); return; } else if (num < zhong) { xia = zhong - 1; printf("shang.%d,zhong.%d,xia.%d \n", shang, zhong, xia); } else { shang = zhong + 1; printf("shang.%d,zhong.%d,xia.%d \n", shang, zhong, xia); } } return; } int main() { int a[1024]; for (int i = 0; i<1024; i++) { a[i] = i; //printf("%d\n",a[i]); } int shang = 0; int xia = 1023;

数据结构——查找:折半查找、二叉查找(排序)树、平衡二叉树

谁说我不能喝 提交于 2020-01-11 00:08:50
七大查找算法: https://www.cnblogs.com/zhang-qc/p/8745153.html 学习的地址 https://www.bilibili.com/video/av27831455?p=20 关于查找表: 上面,静态查找表,找的过程中不改变表。动态查找表,过程中表会变。 静态查找表,对确定的数据元素关系的表查找,不一定是线性表。 关于查找: 上面,概率相同。 我们可以改变元素的排列顺序,可能比较次数会少一点。 平均查找长度,表征效率的问题。 下面为 顺序查找 : 顺序查找适合于存储结构为顺序存储或链接存储的线性表,时间复杂度为O(n) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 折半查找(二分查找): (数据要先有序才行 ,如果是无序的则要先进行排序操作。 ) 最大比较次数就是 log2n 下面2种查找方法(斐波那契查找和插值查找),思想和上面类似,都是按照某个函数给元素分段。 斐波那契查找 : 二分查找的一种提升算法,通过运用黄金比例的概念在数列中选择查找点进行查找,要求开始表中记录的个数为某个斐波那契数小1,及n=F(k)-1;开始将k值与第F(k-1)位置的记录进行比较(及mid=low+F(k-1)-1)。如果>,low=mid+1,k-=2;如果<,high=mid-1,k-=1。 差值查找

Linux内核中的bsearch二分查找函数

最后都变了- 提交于 2020-01-10 14:30:02
void *bsearch(const void *key, const void *base, size_t num, size_t size, int(*cmp)(const void *key, const void *elt)) { size_t start = 0, end = num; int result; while (start < end) { size_t mid = start + (end - start) / 2; result = cmp(key, base + mid * size); if (result < 0) end = mid; else if (result > 0) start = mid + 1; else return (void *)base + mid * size; } return NULL; }    来源: https://www.cnblogs.com/hshy/p/12175718.html