一、二分查找算法
1、二分查找
package Search_zhu;
public class MidSearch {
public static int midsearch(int[] a,int value){
int begin = 0;
int end = a.length - 1;
while (begin <= end){
int mid = 2 * begin + (end - begin) / 2;
if (a[mid] > value){
end = mid - 1;
}else if(a[mid] < value){
begin = mid + 1;
}else{
return mid;
}
}
return -1;
}
public static void main(String[] args) {
int[] a = new int[]{3,5,9,12,39,50};
System.out.println(midsearch(a,9));
}
}
2、递归实现二分查找
package Search_zhu;
public class DgMidSearch {
public static int midsearch(int[] a,int n,int value){
return dgmidsearch(a,0,n-1,value);
}
public static int dgmidsearch(int[] a,int begin,int end,int value){
if (begin > end) return -1;
int mid = begin + (end - begin) / 2;
if (a[mid] == value){
return mid;
}else if (a[mid] > value){
return dgmidsearch(a,begin,mid - 1,value);
}else{
return dgmidsearch(a,mid + 1,end,value);
}
}
public static void main(String[] args) {
int[] a = new int[]{2,6,9,12,25,35,98};
System.out.println(midsearch(a,7,12));
}
}
3、查找第一个等于给定值的值的下标
package Search_zhu;
public class MidSearch1 {
public static int midsearch1(int[] a,int value){
int begin = 0;
int end = a.length - 1;
while (begin <= end){
int mid = begin + (end - begin) / 2;
if (a[mid] > value){
end = mid - 1;
}else if (a[mid] < value){
begin = mid + 1;
}else{
if ((mid == 0) || a[mid - 1] != value) return mid;
else end = mid - 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] a = new int[]{2,5,9,23,23,36,58};
System.out.println(midsearch1(a,23));
}
}
4、查找最后一个等于给定值的值的下标
package Search_zhu;
public class MidSearch2 {
public static int midsearch2(int[] a,int value){
int begin = 0;
int end = a.length - 1;
while (begin <= end){
int mid = begin + (end - begin) / 2;
if (a[mid] > value){
end = mid - 1;
}else if(a[mid] < value){
begin = mid + 1;
}else{
if (mid == end || a[mid + 1] != value){
return mid;
}else{
begin = mid + 1;
}
}
}
return -1;
}
public static void main(String[] args) {
int[] a = new int[]{2,5,23,23,23,36,58};
System.out.println(midsearch2(a,23));
}
}
5、查找第一个大于等于给定值的值的下标
package Search_zhu;
public class MidSearch3 {
public static int midsearch3(int[] a,int value){
int begin = 0;
int end = a.length - 1;
while (begin <= end){
int mid = begin + (end - begin) / 2;
if (a[mid] >= value){
if (mid == 0 || a[mid - 1] < value ) return mid;
else end = mid - 1;
}else{
begin = mid + 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] a = new int[]{2,5,23,23,23,36,58};
System.out.println(midsearch3(a,5));
}
}
6、查找最后一个小于等于给定值的值的下标
package Search_zhu;
public class MidSearch4 {
public static int midsearch4(int[] a,int value){
int begin = 0;
int end = a.length - 1;
while (begin <= end){
int mid = begin + (end - begin) / 2;
if (a[mid] > value){
end = mid - 1;
}else{
if (mid == end - 1 || a[mid + 1] > value) return mid;
else begin = mid + 1;
}
}
return -1;
}
public static void main(String[] args) {
int[] a = new int[]{2,5,23,23,23,36,58};
System.out.println(midsearch4(a,25));
}
}
二、二分查找的局限性
- 二分查找依赖的是顺序表结构,就是数组。原因是二分查找需要依赖数组根据下标随机访问的特性,如果是链表的话,找到中间节点是需要遍历链表的一半
- 二分查找依赖的是有序数据,二分查找依赖的是有序数组,如果没有序,需要先排序,堆排、快排、归并排的时间复杂度为O(nlogn),如果针对的是静态数组,可以实现一次排序,多次二分查找;如果是动态数组,不断插入或删除,数据插入和删除都要先进行排序,这时排序的成本就比较高,针对这种动态集合,更适合用二叉树来进行查找
- 数据量太少不适合用二分查找,在这种情况下,二分查找和顺序遍历的时间差不多,但如果比较操作非常耗时,比如数组中存储的是字符串,这时还是推荐用二分查找*
- 数据量太大也不适合用二分查找,因为二分查找依赖的是数组,数组必须要有连续的内存空间,对内存的要求比较严苛,在资源不足的情况下,使用二分查找是不合适的