折半查找(二分搜索)的应用和技巧全面总结
- 格式:doc
- 大小:66.50 KB
- 文档页数:6
二分法查找:
概念:二分法查找也叫折半查找,它要求被查数据是有序的,否则无法使用二分法查找。
作用:提高查找的效率。
查找的方式:
查找时,设置一个上界和一个下界,然后取上下界的中间元素与指定的关键值比对,若相符,表示找到,查找结束;如果不符在判断关键落在左半部还是右半部;
如果在左半部。
则舍弃右半部,保持下界位置不变,将上界设在中间元素的前一个位置,重新查找;如果在右半部,则与左半部相反。
如此反复进行,若下界大于上界,表明没有元素和关键值相匹配,查找失败。
二分查找概念二分查找概念二分查找,也叫折半查找,是一种高效的查找算法,用于在有序的数据结构中查找指定的元素,其时间复杂度为 O(log n)。
在处理大规模的数据集时,二分查找算法是非常有用的。
二分查找是一种比较简洁的算法,它的核心思想是不断将要查找的区间划分成两段,然后分别进行处理,直到查找到目标元素或者区间不存在为止。
下面我们来介绍一下如何进行二分查找。
二分查找算法的基本过程1. 首先,确定要查找的区间范围,即左边界和右边界。
初始时,左边界 left 为数组的起始位置,右边界 right 为数组的结束位置。
2. 然后,计算中间位置 mid,可以通过以下公式得到:`mid = (left + right) / 2`。
3. 接下来,将查找目标与中间位置的元素进行比较。
- 如果中间位置的元素等于查找目标,就直接返回中间位置。
- 如果中间位置的元素大于查找目标,那么将右边界缩小到 mid-1,即新的 right = mid-1,然后继续查找。
- 如果中间位置的元素小于查找目标,那么将左边界扩大到 mid+1,即新的 left = mid+1,然后继续查找。
4. 重复上述步骤,直到 left 大于 right,即查找区间不存在。
二分查找算法的时间复杂度二分查找算法的时间复杂度为 O(log n),其中 n 为待查找序列的长度。
由于每次查找都会将查找区间缩短一半,因此它的时间复杂度比顺序查找的 O(n) 要小得多。
而且,二分查找算法也适用于非常大的数据集合。
二分查找算法的优缺点二分查找算法的优点是,它能够在大型的有序数据集合中进行高效的查找,而且它的时间复杂度比较低。
而缺点是,它只能用于有序的数据结构中查找元素,如果数据集合并没有经过排序,就需要先进行排序,否则无法使用二分查找算法。
二分查找算法的应用场景二分查找算法通常应用于需要在大规模有序数据集中查找元素的场景,比如搜索引擎中的网页排名、图书馆中的书籍排序等。
二分查找是在我们整个数据结构当中一个比较重要的算法,它的思想在我们的实际开发过程当中应用得非常广泛。
在实际应用中,有些数据序列是已经经过排序的,或者可以将数据进行排序,排序后的数据我们可以通过某种高效的查找方式来进行查找,今天要讲的就是折半查找法(二分查找),它的时间复杂度为O(logn),将以下几个方面进行概述了解二分查找的原理与思想分析二分查找的时间复杂度掌握二分查找的实现方法了解二分查找的使用条件和场景1 二分查找的原理与思想在上一个章节当中,我们学习了各种各样的排序的算法,接下来我们就讲解一下针对有序集合的查找的算法—二分查找(Binary Search、折半查找)算法,二分查找呢,是一种非常容易懂的查找算法,它的思想在我们的生活中随处可见,比如说:同学聚会的时候喜欢玩一个游戏——猜数字游戏,比如在1-100以内的数字,让别人来猜从,猜的过程当中会被提示是猜大了还是猜小了,直到猜中为止。
这个过程其实就是二分查找的思想的体现,这是个生活中的例子,在我们现实开发过程当中也有很多应用到二分查找思想的场景。
比如说仙现在有10个订单,它的金额分别是6、12 、15、19、24、26、29、35、46、67 请从中找出订单金额为15的订单,利用二分查找的思想,那我们每一次都会与中间的数据进行比较来缩小我们查找的范围,下面这幅图代表了查找的过程,其中low,high代表了待查找的区间的下标范围,mid表示待查找区间中间元素的下标(如果范围区间是偶数个导致中间的数有两个就选择较小的那个)第一次二分查找第二次二分查找第三次二分查找通过这个查找过程我们可以对二分查找的思想做一个汇总:二分查找针对的是一个有序的数据集合,查找思想有点类似于分治思想。
每次都通过跟区间的中间元素对比,将待查找的区间范围缩小为原来的一半,直到找到要查找的元素,或者区间被缩小为0。
一:查找的数据有序二:每次查找,数据的范围都在缩小,直到找到或找不到为止。
函数二分法的原理及应用二分法,又称折半查找法,是一种在有序列表中查找其中一特定元素的效率较高的算法。
其核心思想是每次将待查找范围缩小一半,通过不断缩小范围直到找到目标元素或确定目标元素不存在。
二分法的原理非常简单。
设有一个有序列表,首先确定该列表的中间位置,然后将目标元素与中间位置的元素进行比较。
如果目标元素小于中间位置元素,则目标元素在列表的前半部分,否则目标元素在列表的后半部分。
以此类推,每次都将待查找范围缩小一半,直到找到目标元素或确定目标元素不存在。
应用方面,二分法广泛应用于各个领域。
以下是几个常见的应用场景:1. 查找有序列表中的元素:二分法是在有序列表中查找元素的最优解法。
例如,在一个有序数组中查找一些特定的数值,二分法的时间复杂度为 O(log n)。
2.查找旋转有序数组中的元素:旋转有序数组是指一个有序数组经过其中一种旋转操作后得到的数组。
即使被旋转,依然可以使用二分法进行查找。
3.查找一些函数的零点:对于一个单调递增或单调递减的函数,在一些区间内只存在一个零点。
可以利用二分法找到函数的零点,方法是在区间内不断缩小范围,直到找到满足精度要求的近似解。
4. 在图中查找最短路径:在一些图算法中,如最短路径算法(例如Dijkstra算法),需要在图中进行查找操作。
二分法可以用来确定查找的范围,从而提高算法的效率。
5.数据库索引查找操作:数据库索引的结构往往是一个有序列表,通过二分法查找可以大幅提高数据库的查询效率。
总的来说,二分法的优势在于每次查找操作将查找范围缩小一半,因此其时间复杂度较低,效率较高。
然而,在应用二分法时,要求列表是有序的。
如果列表无序,则需要先进行排序操作,这将花费额外的时间。
另外,二分法只适用于静态的数据结构,对于动态更新频繁的数据结构,二分法的效率可能较低。
需要注意的是,二分法虽然适用于很多应用场景,但并非适用于所有情况。
在应用二分法时,需要仔细分析问题的特点,确定是否适合使用二分法。
简单二分法简单二分法简介二分法是一种常用的查找算法,也被称为折半查找。
它是一种高效的算法,时间复杂度为O(logn)。
简单二分法是最基础、最常见的二分法。
原理简单二分法是在一个有序数组中查找某个元素。
它的核心思想是将数组分成两部分,如果目标元素比中间元素大,则在后半部分查找;否则在前半部分查找,直到找到目标元素或者确定目标元素不存在。
步骤1. 确定数组的左右边界left和right。
2. 计算中间位置mid = (left + right) / 2。
3. 如果目标值等于中间位置的值,则返回mid。
4. 如果目标值小于中间位置的值,则在左半部分继续查找,即right = mid - 1。
5. 如果目标值大于中间位置的值,则在右半部分继续查找,即left = mid + 1。
6. 重复步骤2-5,直到left > right或者找到目标元素为止。
代码实现下面是一个简单的二分查找实现:```pythondef binary_search(nums, target):left, right = 0, len(nums) - 1while left <= right:mid = (left + right) // 2if nums[mid] == target:return midelif nums[mid] < target:left = mid + 1else:right = mid - 1return -1```注意事项1. 数组必须是有序的。
2. 如果数组中有重复元素,无法保证返回的是第一个或最后一个出现的位置。
3. 如果目标元素不存在于数组中,需要特殊处理,例如返回-1或抛出异常。
4. 在计算mid时,要注意整数除法会向下取整,因此应该使用(left + right) // 2而不是(left + right) / 2。
5. 在确定边界时,要注意数组下标从0开始还是从1开始。
总结简单二分法是一种高效的查找算法,在处理有序数组时非常实用。
二分法起源
二分法介绍:
1.基本思想:
二分法,又称为折半查找法,是一种常见的搜索算法。
其基本思想是通过比较中间元素和目标元素的大小,排除一半的元素,将搜索范围缩小为原来的一半。
如果目标元素不在当前范围内,就继续对剩余范围进行二分,直到找到目标元素或确定目标元素不存在。
2.步骤:
1.确定搜索范围的起始和结束位置。
2.计算中间位置的索引。
3.比较中间位置元素与目标元素的大小。
4.根据比较结果调整搜索范围。
5.重复以上步骤,直到找到目标元素或搜索范围为空。
3.适用条件:
•数组或列表必须是有序的。
4.时间复杂度:
•O(logn),其中n为元素个数。
5.应用领域:
•在有序数组、有序列表等数据结构中进行高效查找。
二分法起源:
1.古代数学:
•二分法最早可以追溯到古代数学中,古代数学家在解方程、求根、逼近数值等问题时就开始运用二分法的思想。
2.古代哲学:
•在古希腊哲学中,对于复杂问题的分解和逐步解决的思想为二分法提供了哲学基础。
3.牛顿的方法:
•17世纪,数学家和物理学家牛顿提出了用二分法逼近函数零点的方法,这被称为“牛顿法”或“牛顿-拉弗森法”。
4.计算机科学:
•二分法在计算机科学中得到广泛应用,特别是在算法设计中,如二分查找算法、分治算法等。
总体来说,二分法的起源可以追溯到古代数学和哲学时期,随着科学和技术的发展,它在不同领域得到了进一步的发展和应用。
二分法以其简单而有效的特点,成为解决各种问题的重要方法之一,深刻影响了数学、计算机科学等多个学科领域。
二分法检索二分法检索是一种高效的算法,在计算机领域中得到广泛的应用。
它可用于在有序的数据集中,查找指定元素的位置。
本文将分步骤阐述二分法检索的原理和实现。
一、什么是二分法检索二分法检索也被称为折半检索,它是一种从有序数据集中查找某个指定元素的算法。
它的基本原理是不断缩小需要查找的范围,直到找到目标元素或确定目标元素不存在。
二、二分法检索的原理1、将要查找的数据集按照一定的顺序排序。
2、获取数据集中最中间的元素,并将其与目标元素进行比较。
3、如果目标元素等于中间元素,则检索结束并返回其索引。
如果目标元素大于中间元素,则在右半部分查找,否则在左半部分查找。
4、重复以上步骤,直到找到目标元素或整个数据集被查找完毕。
三、二分法检索的实现以下是一段 JavaScript 代码,用于演示二分法检索的实现。
```function binarySearch(arr, target) {let left = 0;let right = arr.length - 1;while (left <= right) {const mid = Math.floor((left + right) / 2);if (arr[mid] === target) {return mid;} else if (arr[mid] < target) {left = mid + 1;} else {right = mid - 1;}}return -1;}const arr = [1, 3, 4, 6, 8, 9, 11];console.log(binarySearch(arr, 8)); // 4console.log(binarySearch(arr, 2)); // -1```四、二分法检索与其他算法的比较相对于线性查找,二分法检索的时间复杂度更小,通常为 O(log n),其中 n 为数据集的大小。
线性查找的时间复杂度为 O(n)。
描述二分查找法找数据的步骤
二分查找法又称折半查找法,是一种常见的查找算法。
它的基本思想是不断将查找区间分成两部分并检查中间元素,直到找到目标元素或查找区间为空。
以下是二分查找法找数据的步骤:
1. 确定查找区间,即左右边界。
一般初始化为整个数据集合。
2. 计算中间位置,即“左右边界之和除以二”。
3. 判断中间位置的值是否等于目标值。
如果相等,则查找结束,返回该位置。
4. 如果中间位置的值大于目标值,则在左半边继续查找,即将右边界移动到中间位置的前一个位置。
5. 如果中间位置的值小于目标值,则在右半边继续查找,即将左边界移动到中间位置的后一个位置。
6. 重复以上步骤,直到查找区间为空或者找到目标元素。
需要注意的是,在使用二分查找法时,数据必须是有序的,否则无法正常运行。
此外,对于重复元素的处理,可以选择返回第一个或最后一个等于目标值的元素位置,或最接近目标值的元素位置。
- 1 -。
二分查找算法的描述二分查找算法,也称为折半查找算法,是一种在有序数组中查找特定元素的常用算法。
它的核心思想是通过每次将查找区间缩小一半的方式来逐步逼近目标值,直到找到目标值或者确定目标值不存在为止。
二分查找算法的时间复杂度为O(logn),效率较高。
二分查找算法的具体步骤如下:1. 确定查找区间的起始点和终止点,初始时起始点为数组的第一个元素,终止点为数组的最后一个元素。
2. 计算查找区间的中间点,即取起始点和终止点的中间位置,如果该位置的元素恰好等于目标值,则查找成功,返回该位置。
3. 如果中间点的元素大于目标值,则目标值可能在左半部分,将终止点更新为中间点的前一个位置,并返回步骤2。
4. 如果中间点的元素小于目标值,则目标值可能在右半部分,将起始点更新为中间点的后一个位置,并返回步骤2。
5. 重复步骤2至步骤4,直到起始点大于终止点,此时查找失败,目标值不存在于数组中。
二分查找算法的关键在于每次将查找区间缩小一半,通过不断地排除一半的元素,可以快速地逼近目标值。
这种分而治之的思想使得二分查找算法的效率比线性查找算法高很多。
为了更好地理解二分查找算法,我们可以通过一个简单的例子来演示。
假设有一个有序数组arr,其中包含了1到100的整数。
我们要在数组中查找目标值为55的元素。
按照二分查找算法的步骤:1. 确定查找区间的起始点和终止点,起始点为数组的第一个元素1,终止点为数组的最后一个元素100。
2. 计算查找区间的中间点,中间点为起始点1和终止点100的中间位置50。
由于50小于目标值55,所以目标值可能在右半部分。
3. 将起始点更新为中间点的后一个位置,即51。
4. 计算新的中间点,中间点为51和100的中间位置75。
由于75大于目标值55,所以目标值可能在左半部分。
5. 将终止点更新为中间点的前一个位置,即74。
6. 计算新的中间点,中间点为51和74的中间位置62。
由于62大于目标值55,所以目标值可能在左半部分。
折半查找(二分搜索)的应用和技巧全面总结折半查找应该算是算法中比较简单常见,但却很实用的方法之一了,又叫做二分搜索,其应用比较广泛,可以用于排序数组中元素的查找,复杂度仅为log(N),也可以用于有序数组中插入元素等等,一般而言针对排序数组的一些算法都会活多或少的用到折半查找活折半查找的思想,折半查找的实现主要分为两种方式,一种是遍历非递归形式,一种是采用递归的形式。
1、非递归形式,这种实现主要是通过每次调整中点的位置来实现。
1. int binsearch1(int arr[], int k, int l, int h){2. if(l > h){3. return -1;4. }5. int mid;6. while(l <= h){7. mid = (l + h) / 2;8. if(k == arr[mid]){9. return mid;10. }else if(k > arr[mid]){11. l = mid + 1;12. }else{13. h = mid - 1;14. }15. }16. r eturn -1;17. }这种方式比较灵活,而已有利于解决很多变形的问题,后面会介绍。
2、递归的形式,这种形式比较简单,调整起点,中点,终点的位置,递归函数就可以实现1. int binsearch2(int arr[], int k, int l, int h){2. if(l > h){3. return -1;4. }5. int mid = (l + h) / 2;6. if(k == arr[mid]){7. return mid;8. }else if(k > arr[mid]){9. binsearch2(arr, k, mid +1, h);10. }else if(k < arr[mid]){11. b insearch2(arr, k, l, mid - 1);12. }13. r eturn -1;14. }二、现在考虑复杂一点的二分搜索的问题,当我们遇到这样的数组a={1, 2, 3, 3, 5, 7, 8},存在重复的元素,需要从中找出3第一次出现的位置,这里3第一次出现的位置是2,《编程珠玑》里给出了很好的分析,二分搜索主要的精髓在于不变式的设计(就是上面的while循环条件式)。
1. int binsearch_first(int arr[], int k, int n){2. int l = -1, h = n;3. while(l + 1 != h){4. int m = (l + h) / 2;5. if(k > arr[m]){6. l = m;7. }else{8. h = m;9. }10. }11. i nt p = h;12. i f(p >= n || arr[p] != k){13. r eturn -1;14. }15. r eturn h;16. }算法分析:设定两个不存在的元素a[-1]和a[n],使得a[-1] < t <= a[n],但是我们并不会去访问者两个元素,因为(l+u)/2 > l=-1, (l+u)/2 < u=n。
循环不变式为l<u && t>a[l] && t<=a[u] 。
循环退出时必然有l+1=u, 而且a[l] < t <= a[u]。
循环退出后u的值为t可能出现的位置,其范围为[0, n],如果t在数组中,则第一个出现的位置p=u,如果不在,则设置p=-1返回。
该算法的效率虽然解决了更为复杂的问题,但是其效率比初始版本的二分查找还要高,因为它在每次循环中只需要比较一次,前一程序则通常需要比较两次。
举个例子:对于数组a={1, 2, 3, 3, 5, 7, 8},我们如果查找t=3,则可以得到p=u=2,如果查找t=4,a[3]<t<=a[4],所以p=u=4,判断a[4] != t,所以设置p=-1.一种例外情况是u>=n, 比如t=9,则u=7,此时也是设置p=-1.特别注意的是,l=-1,u=n这两个值不能写成l=0,u=n-1。
虽然这两个值不会访问到,但是如果改成后面的那样,就会导致二分查找失败,那样就访问不到第一个数字。
如在a={1,2,3,4,5}中查找1,如果初始设置l=0,u=n-1,则会导致查找失败。
同理:查找数组中一个元素最后出现的位置如下:1.int binsearch_last(int arr[], int k, int n){2.int l = -1, h = n;3.while(l + 1 != h){4.int m = (l + h) / 2;5.if(k >= arr[m]){6.l = m;7.}else{8.h = m;9.}10.}11.i nt p = l;12.i f(p <= -1 || arr[p] != k){13.r eturn -1;14.}15.r eturn p;16.}三、旋转数组中元素的查找什么是旋转数组呢,旋转数组就是将个一个有序数组以一个点为中心进行旋转(前后颠倒),例如{4,5 ,1,2 ,3}是{1,2,3,4,5}的一个以3为中心的旋转。
这样数组就变得整体无序了,但是还是部分有序的。
第一个解决方案:可以找到旋转的中点,然后对两个部分有序的数组分别进行二分查找1. int split(int a[], int n)2. {3. for (int i=0; i<n-1; i++) {4. if (a[i+1] < a[i])5. return i;6. }7. return -1;8. }9.10. i nt bsearch_rotate(int a[], int n, int t)11. {12. i nt p = split(a, n); //找到分割位置13. i f (p == -1)14. r eturn bsearch_first(a, n, t); //如果原数组有序,则直接二分查找即可15. e lse {16. i nt left = bsearch_first(a, p+1, t); //查找左半部分17. i f (left == -1) { //左半部分没有找到,则查找右半部分18. i nt right = bsearch_first(a+p+1, n-p-1, t); //查找右半部分19. i f (right != -1) return right+p+1; //返回位置,注意要加上p+120. r eturn -1;21. }22. r eturn left; //左半部分找到,则直接返回23. }24. }还有另外一种方法就是还按照一次二分查找的形式进行,可以这样考虑计算数组中点的时候,会将数组分为两个部分,一部分是有序的,或者两部分有序的,总之必然有一遍是有序的,那么就又可以按照二分的思想进行求解。
二分查找算法有两个关键点:1)数组有序;2)根据当前区间的中间元素与x的大小关系,确定下次二分查找在前半段区间还是后半段区间进行。
仔细分析该问题,可以发现,每次根据low和high求出mid后,mid左边([low, mid])和右边([mid, high])至少一个是有序的。
a[mid]分别与a[left]和a[right]比较,确定哪一段是有序的。
如果左边是有序的,若x<a[mid]且x>a[left], 则right=mid-1;其他情况,left=mid+1;如果右边是有序的,若x> a[mid] 且x<a[right] 则left=mid+1;其他情况,right=mid-1;代码如下:1. int bsearch_rotate(int a[], int n, int t)2. {3. int low = 0, high = n-1;4. while (low <= high) {5. int mid = low + (high-low) / 2;6. if (t == a[mid])7. return mid;8. if (a[mid] >= a[low]) { //数组左半有序9. if (t >= a[low] && t < a[mid])10. h igh = mid - 1;11. e lse12. l ow = mid + 1;13. } else { //数组右半段有序14. i f (t > a[mid] && t <= a[high])15. l ow = mid + 1;16. e lse17. h igh = mid - 1;18. }19. }20. r eturn -1;21. }四、有序数组的插入问题其实有序数组的插入问题也可以通过二分搜索实现,只是返回值不同而已,在没找到元素的时候返回l(最左值)值就是元素应该插入的位置。
1. int binsearch1(int arr[], int k, int l, int h){2. if(l > h){3. return -1;4. }5. int mid;6. while(l <= h){7. mid = (l + h) / 2;8. if(k == arr[mid]){9. return mid;10. }else if(k > arr[mid]){11. l = mid + 1;12. }else{13. h = mid - 1;14. }15. }16. r eturn l;17. }五、二分思想的变形,其实二分是一种思想,不单单是应用于有序序列,可以应用于很多将序列进行划分的问题上。