二分查找排序
2013-10-30 22:08
288 查看
二分查找算法,是在大学阶段学习的基础性算法。算法思想简单,但要写出一个正确的二分查找算法并不简单,从1946年提出,到1962年才完成一个正确的二分查找排序算法。二分查找排序算法的变种,也常常出现在各个IT公司的面试题中。本文总结资料尝试给出一个“正确”的二分查找算法,最后给出一个二分查找排序的变种问题。
1. 经典二分查找排序的算法:
可能需要关注细节问题:
1)循环条件
在第8行,循环的条件设置成 low <=high。如果设置成low<high,是存在问题的:当只有数组只有一个元素,并且该元素就是需要查找的元素时,算法返回错误的值-1,查找失败。
2)求中间元素
在第10行,求中间元素使用的代码:mid = low + ((high - low) >> 1)。一些书籍中给出的是:mid = (high + low) >> 1,如果high+low很大时,会造成溢出。这种情况出现的概率较小,但是为了程序适应比较恶劣条件,使用第10行代码求中间元素就显得有必要了。
(ps:上面的代码可能还存在带完善的地方,欢迎拍砖。。。)
2. 二分查找排序算法的变种
问题描述:已知一个有序的数组a
,循环左移k位(k<N)后得到新的数组b
,在这个新的数组中查找元素x。例如:数组 a
= {1, 3, 5, 7, 9, 10},循环左移2位后变成数组b
= {5, 7, 9, 10, 1, 3},在这个新的数组上查找某个元素x。
上题是我在面试中问道的问题,比较庆幸的是我在《剑指offer》一书中碰到了类似的一题,书中需要找出数组b
最小的最小元素,因此能比较迅速的解决了这个问题。解决问题的思路和《剑指offer》提供的思路一致。
解题思路:数组b
中存在着两个部分有序的子数组,b1:{5, 7, 9, 10}和b2:{1, 3},其中b1中的元素均大于b2中的元素。在使用二分查找算法时,中间元素mid必定落入b1或者b2某个递增序列中,具体解决步骤如下:
Init: low = 0, high = N-1, mid = b[low + (high - low) >> 1]
step1: 求出数组b的中间元素mid, 如果mid == x,则返回成功,否则进入步骤step2。
step2: if(a[low]<mid),mid落入b1数组,此时:
1) if (a[low]<x<mid), x在有序区间[low, mid),则将high = mid -1
2) 否则,x落入区间(mid, high],则将low = mid +1
else mid落入b2数组,此时:
1)if (mid< x< b[high]),x在有序区间(mid, high],则将low = mid + 1
2)否则, x落入区间[low, mid),则将hign = mid -1
step3: if(low <= hign) 继续步骤step1,否则返回查找失败
具体的代码如下:
1. 经典二分查找排序的算法:
int BinarySearch(int* array, int n, int x) { assert((array != NULL) && (0 <= n)); int low = 0; int high = n -1; while (low <= high) { int mid = low + ((high - low) >> 1); if (array[mid] == x) { return mid; } if (x > array[mid]) { low = mid + 1; } else { high = mid -1; } } return -1; }
可能需要关注细节问题:
1)循环条件
在第8行,循环的条件设置成 low <=high。如果设置成low<high,是存在问题的:当只有数组只有一个元素,并且该元素就是需要查找的元素时,算法返回错误的值-1,查找失败。
2)求中间元素
在第10行,求中间元素使用的代码:mid = low + ((high - low) >> 1)。一些书籍中给出的是:mid = (high + low) >> 1,如果high+low很大时,会造成溢出。这种情况出现的概率较小,但是为了程序适应比较恶劣条件,使用第10行代码求中间元素就显得有必要了。
(ps:上面的代码可能还存在带完善的地方,欢迎拍砖。。。)
2. 二分查找排序算法的变种
问题描述:已知一个有序的数组a
,循环左移k位(k<N)后得到新的数组b
,在这个新的数组中查找元素x。例如:数组 a
= {1, 3, 5, 7, 9, 10},循环左移2位后变成数组b
= {5, 7, 9, 10, 1, 3},在这个新的数组上查找某个元素x。
上题是我在面试中问道的问题,比较庆幸的是我在《剑指offer》一书中碰到了类似的一题,书中需要找出数组b
最小的最小元素,因此能比较迅速的解决了这个问题。解决问题的思路和《剑指offer》提供的思路一致。
解题思路:数组b
中存在着两个部分有序的子数组,b1:{5, 7, 9, 10}和b2:{1, 3},其中b1中的元素均大于b2中的元素。在使用二分查找算法时,中间元素mid必定落入b1或者b2某个递增序列中,具体解决步骤如下:
Init: low = 0, high = N-1, mid = b[low + (high - low) >> 1]
step1: 求出数组b的中间元素mid, 如果mid == x,则返回成功,否则进入步骤step2。
step2: if(a[low]<mid),mid落入b1数组,此时:
1) if (a[low]<x<mid), x在有序区间[low, mid),则将high = mid -1
2) 否则,x落入区间(mid, high],则将low = mid +1
else mid落入b2数组,此时:
1)if (mid< x< b[high]),x在有序区间(mid, high],则将low = mid + 1
2)否则, x落入区间[low, mid),则将hign = mid -1
step3: if(low <= hign) 继续步骤step1,否则返回查找失败
具体的代码如下:
int rotate_array_search(int a[], int n, int x) { int low = 0; int high = n-1; while(low <= high) { int mid = low + ((high - low) >> 1); if(a[mid] == x) return mid; if(a[mid] >= a[low]) { if(x < a[mid] && x >= a[low]) { high = mid -1; } else { low = mid + 1; } } else { if(x > a[mid] && x <= a[high]) { low = mid + 1; } else { high = mid -1; } } } return -1; // 查找失败,则返回-1 }
相关文章推荐
- C 语言 排序算法,冒泡排序,选择排序,插入排序,二分查找
- 算法--Two sum之排序数字二分查找实现
- 2013 0314 二分查找 快速排序 空间复杂度
- 排序和二分查找题
- 【递归、二分查找】数字在排序数组中出现的次数
- java两种排序及二分查找
- C语言快速排序与二分查找算法示例
- PHP 数组排序(冒泡排序、选择排序);数组查找(顺序查找、二分查找)
- 59.排序好的大数据创建索引文件,并实现大文件的二分查找,根据索引百万数据秒读数据
- sort(排序) qsort(快排) bsearch(二分查找)
- (一)排序简介:直接插入排序、冒泡排序、二分查找排序
- 快速排序与二分查找
- 经典算法:二分查找、插入排序、选择排序、冒泡排序
- Kotlin练习 之使用Kotlin实现:二分查找,选择排序,冒泡排序,快速排序
- 栋哥带你学Java数组排序和二分查找
- LeetCode-Find Minimum in Rotated Sorted Array II-旋转排序数组找最小-二分查找
- 二分查找-针对已排序数组
- 排序列表转换为二分查找树
- 归并排序、插入排序、快速排序、二分查找的c++实现
- C语言排序(二)——二分查找