算法入门---java语言实现的二分查找小结
来源:互联网 发布:js生成uuid时间 编辑:程序博客网 时间:2024/06/07 19:39
package com.zy.serch;
public class BinarySerch {
/**
* 二分查找。
* 前提:数据源是有序的。
* 核心思想:还是先确定要写的算法的区间,此处我们是按照src[left...right],左闭右闭来查找的。
* 首先我们找到中间的索引mid,此时数据源就成了src[left...mid-1] [mid] [mid+1...right]
* 这样src[left...mid-1] < src[mid],src[mid+1...right] > src[mid].此时比较我们要查找
* 的数和mid索引所在的值:
* 等于: 找到直接返回
* 小于: 此时就应该在src[left...mid-1]据需执行相应的操作,
* 注意不需要再比较mid了,那么就是把right的索引做相应的处理。
* 大于: 此时就应该子啊src[mid+1...right]据需执行相应的操作,此次就需要对left索引做处理。
*
* 最终当left索引大于等于right索引的时候就不需要在进行查找了,此时仍没有找到的时候就返回-1,或其它的来标记未找到。
*
* 二分查找,当有相等的时候,那么按照查找规则,找到就会返回,不一定是前面的或者后面的。
* @param src 要进行查找的数据源
* @param value 要查找的值
* @return 如果数据存在返回找到的索引,否则返回-1;
*
*/
public int binarySerch(int[] src,int value){
//老思想,确定自己的区间,定义需要维护的变量。
int len = src.length;
int left = 0;
int right = len-1;//由于我此处设计的是按照前闭后闭来看的。
//注意小于等于都符合我们区间控制,不操作等于的时候,最后只剩一个元素正好使我们
//要查找的就会遗漏
while(left <= right){
//
//int mid = (left+right)/2; 这种写法容易发生溢出,当两个大的int型的数相加时候范围是有可能超过int的
//所以用下面的写法。
int mid = left +(right-left)/2;
if(value == src[mid]){
return mid;
}else if(value > src[mid]){
//此时要查找的应该在右边部分所以
left = mid+1;
}else if(value < src[mid]){
//此时要查找的应该在左边部分所以
right = mid-1;
}
}
return -1;
}
/**
* 用递归的方法实现二分查找,核心思想是一样的。
* 不过递归实现时,考虑问题的角度的变,现在想每次的问题都是在一段区间内
* 从左向右找,然后递归的从左向右找,所以这个参数肯定也得传入左右的索引,
* 只不过这个索引会越来越小,直到不满足递归条件然后退出。
* @param src 数据源
* @param left 查找的区间的左索引
* @param right 查找的区间的右索引
* @param value 要查找的值
* @return 如果数据存在返回找到的索引,否则返回-1;
*/
public int binarySerch(int[] src,int left,int right,int value){
//递归退出条件
if(left > right){
return -1;
}
int mid = left+(right-left)/2;
if(value == src[mid]){
return mid;
}
if(value > src[mid]){
left = left+1;
//下面应该直接进入到另一个函数进行查询,进入以后这个函数就执行完了,然后
//自动销毁了,然后就去那个函数中接着执行,所以就是一层一层的,递归的设计思想
//直到某个函数中找到了,不再调用此处了,或者某个函数不满足递归条件了直接退出。
return binarySerch(src, left, right, value);
}else{
right = mid-1;
return binarySerch(src, left, right, value);
}
//return -1;这就不该有了,现在理解的还不到位。
}
}
递归实现的二分查找可能性能上会略差,不过都是logn的时间复杂度。慕课网上的图
二分查找实现的floor操作(慕课网的)
/**
* 理解的还不够透彻
* 对value向下取数核心思想:
* 从src[left...right],中开始查找.先计算mid
* 当src[mid]大于或者等于value的时候, 让right的索引减一,因为我们要找小于或者等于的。
* 当src[mid]小于value的时候,那么直接把left放在在mid的索引(不放在mid+1怕大于right)
* 就这样在left < right的条件下一只进行次操作,那么最后出来的时候就是我们要找的最大的小于value的值的索引。
*
* @param src 数据源
* @param value 进行floor操作的值。
* @return 返回在数组中找到的value的floor值:
* 1)、找到该value的时候直接返回。
* 2)、没有找到的时候返回比value小的最大值的索引,如果这个索引最大值有多个,那么返回最大索引(从
* 右往左一步步减少)
* 3)、如果整个数组的最小值都比value大,那么不存在value的floor值返回-1.
*/
public int floor(int[] src, int value){
int len = src.length;
//左闭右闭的区间找,
int left = 0;
int right = len-1;
//如果最小的元素都比当前的元素小那么就返回-1;
if(src[0] > value){
return -1;
}
//等于时就证明我们已经走到了我们的条件的索引
while(left < right){
//使用mid = left+(right-left)/2会死循环
//因为假设我们一直查找到了两个数相邻的时候,设为A 、B
//我们要查找的数value等于B, 此时A < B 在数组中有序相邻排列。
//left索引、righ索引分别对应于A和B。那么mid =(如上) 永远是等于left所在的索引
//而此时left索引对应的元素小于value,需要把mid的值再赋值给left,再进行求mid,如此进入了死循环
//因为right索引不会动。
//所以我们使用int mid = left+(right-left)/2,这种求mid的方法。
//这种求mid的方法奇数时候没什么影响,在偶数的是后会向上取一个数如:
// 0 1 2 3 的时候会取 2,而我们以前会取1.但是在奇数的时候如
//0 1 2 3 4 5 依然是取3没什么影响。
//综上:当我们使用mid = left+(right-left)/2时候,再出现如上两个数相邻的状况,我们会取到
//right的数,而right的索引无论是在大于还是等于value的时候都会对mid进行减1.这样while的判断
//条件left < right就不符合了,会退出循环。
//mid = left+(right-left)/2 案例例如:
//int[] src = {5 ,23 ,29 ,30 ,33,33 ,35 ,39 ,53 ,56 ,70 ,74 ,81 ,82 ,87 ,87 };
//第一次:0+(15-0)/2 = 7
//src[7] = 39 < value;left = 7
//第二次:7+(15-7)/2 = 11.
//src[11] = 74 > value;right = 10
//第三次:7+(10-7)/2 = 8;
//src[8] = 53 < value;left = 8
//第四次:8+(10-8)/2 = 9;
//src[9] = 56 < value;left = 9
//第五次:9+(10-9)/2 = 9;
//src[9] = 56 < value;left = 9
//接下来一直无限循环。
int mid = left+(right-left+1)/2;
if(src[mid] >= value){
//大于等于的时候mid减一,往前面走一个
right = mid - 1;
}else{
//当小于的时候此处直接把left设置为mid,大范围减少查找的量
left = mid;
}
}
System.out.println("left = "+left+",right = "+right);
//此处出来的时候left是等于right的
//此时由于等于的时候我们队right进行了减1.那么有可能后一个数是等于的所以执行如下操作
if( left + 1 < len && src[left+1] == value )
return left + 1;
// 否则, 该索引即为返回值
return left;
}
二分查找实现的ceil(慕课网上的)
/**
* 理解的也不够透彻
* 对value向上取数核心思想:
* 从src[left...right],中开始查找.先计算mid.
* 当src[mid]小于或者等于value的时候, 让left的索引加1。
* 当src[mid]大于value的时候,那么直接把right放在mid的索引。
* 就这样在left < right的条件下一直进行次操作,那么最后出来的时候就是我们要找的最大的小于value的值的索引。
* @param src 数据源.
* @param value 进行ceil操作的值.
* @return 返回在数组中找到的value的ceil值:
* 1)、找到该value的时候直接返回。
* 2)、没有找到的时候返回比value大的小大值的索引,如果这个索引最小值有多个,那么返回最小索引(从左
* 往右一步步减少)
* 3)、如果整个数组的最大值都比value小,那么不存在value的floor值返回-1.
*/
public int ceil(int[] src, int value){
int len = src.length;
//左闭右闭的区间找,
int left = 0;
int right = len-1;
//如果最小的元素都比当前的元素小那么就返回-1;
if(src[right] < value){
return -1;
}
while( left < right ){
//此处动的是左边索引,所以正好不会出现死循环。
int mid = left + (right-left)/2;
if( src[mid] <= value )
left = mid + 1;
else
right = mid;
}
if( right - 1 >= 0 && src[right - 1] == value )
return right - 1;
//该索引即为返回值
return right;
}
0 0
- 算法入门---java语言实现的二分查找小结
- 算法入门---java语言实现的二分搜索树小结
- java语言实现二分查找算法
- [查找算法]--二分查找的Java实现
- 二分查找算法的C语言实现
- 算法入门---java语言实现的选择排序小结
- 算法入门---java语言实现的冒泡排序小结
- 算法入门---java语言实现的归并排序小结
- 算法入门---java语言实现的插入排序小结
- 算法入门---java语言实现的希尔排序小结
- 算法入门---java语言实现的快速排序小结
- 算法入门---java语言实现的堆排序小结
- C语言实现折半查找(二分查找)的算法
- java实现的二分查找算法
- 二分查找算法的JAVA实现
- Java实现的二分查找算法
- Java实现的二分查找算法
- Java实现的二分查找算法
- poj 3406 组合数的最后非0数
- Whoops, looks like something went wrong. 1/1 InvalidArgumentException in FileViewFinder.php line 13
- 时间复杂度分析及其案例
- Delphi VCL GIF 动画
- 《存储入门》读书笔记
- 算法入门---java语言实现的二分查找小结
- 【Java邮件开发】2.手工敲指令体验smtp和pop3协议
- WPF分页控件 参照百度分页实现 带源码
- 1017. Queueing at Bank (25)
- 2017华为比赛遗传算法总结
- mui.prompt 改变其input 样式属性
- pycharm使用github
- vue-resource CRUD示例
- JSP相关背景