之前一直很迷茫想要提升android技术到底该学什么?到底是系统源码,高级自定义view呢还是java入门基础,包括很多刚开始学习android的新人也是,后来慢慢的深入下去才发现基础真的很重要,想要造高楼,必须打地基给打结实。于是打算开始算法的简单初级学习,为了能够更好地学习高层的知识,把自己的基础稳固下来。
这里我选择的是《算法图解》和《大话数据结构》这两本入门基础级别的书(建议优先看算法图解,因为前者属于启蒙,后面的已经初具规模),可以帮你了解到大概的算法和数据结构的内容。
后期的进阶可以选择《编程之美》、《数据结构和算法java语言描述》、《剑指offer》、《编程珠玑》等书。
网上看到的算法与数据结构从入门到进阶的学习书籍推荐,可以参考一下
接下来就是今天的主角了,简单二分法查找。
二分法查找
相信我们平时项目中会遇到很多查找的情况,比如查找某项在列表中的位置。又或者在联系人中快速找到对应的某个人。如果我们按照顺序查找,万一结果在最后一项且数据量很大的时候,查找的效率就很低,损耗性能。这个时候就体现了二分法的作用了。
注意二分法的前提是列表为有序的才管用。
二分法的逻辑其实很简单,可以参考我们小时候猜数字,1-100猜数字,如果数字大了,我们就取剩下部分的中间数继续猜,小了一样。
- 查找的范围,指定低位和高位,即第一位和最后一位
- 先取中间值,即(low + high)/ 2 ,得到中间值和预期值进行比较,如果小了,范围就从中间值到最高位缩进再次进行取中间值比较,重复如此
3. 最后如果得到的值和预期值一样就可以返回结果了。
编码实践
public static void main(String args[]) {
int[] datas = {1,2,3,4,5,6,7,8,9,10,40,50,60,70};
int result = binarySearch(datas, 10);
System.out.print("result position = " + result);
}
//查找数组中值的所在位置(采用二分法)
private static int binarySearch(int[] data, int item) {
if(data == null || data.length == 0) {
return -1;
}
//低位
int low = 0;
//高位
int high = data.length - 1;
//一直循环查找,直到找到合数的值,目前不考虑去重
while (low <= high) {
int mid = (high + low) / 2;
//取中间值来比较
int guess = data[mid];
if(guess == item) {
return mid;
} else if (guess > item) {
high = mid -1;
} else {
low = mid + 1;
}
}
//未找到
return -1;
}
结果
result position = 9
元素重复的二分查找法
这样最简单的二分查找的算法掌握了,为啥要说最简单,因为往往现实情况更复杂,会遇到元素重复或者元素乱序的情况。。。一般如果乱序可以先将列表按照一定规则排好序再去进行二分查找,这边我再讲一个元素重复的二分查找
原理其实也很简单,如果我们取到中间值和预期值相等的时候出现了重复元素,我们就可以循环遍历下之前的元素或者之后的元素进行判断取值,如果也是等于预期值,那就把它取出来。当然有可能会遇到全是相同的元素的时候,这个时候这个办法效率又低了。。。(WTF,无底洞的需求和限量的头发)
思路就是上面写的,中间值前后循环遍历取值,不相等就丢掉
编码实践
代码:
public static void main(String args[]) {
int[] datas = {1,2,3,4,5,6,7,10,10,10,40,50,60,70};
List<Integer> results = binarySearchList(datas, 10);
System.out.print("result position = " + results);
}
//查找重复元素的二分法
private static List<Integer> binarySearchList(int[] data, int item) {
if(data == null || data.length == 0) {
return null;
}
List<Integer> results = new ArrayList<>();
int low = 0;
int high = data.length - 1;
while(low <= high) {
int mid = (low + high) / 2;
int guess = data[mid];
if(guess == item) {
if(mid > 0) {
//遍历中间值前面的元素,判断是否有重复元素在
for(int i = mid - 1; i >= 0; i--) {
if(data[i] == item) {
results.add(i);
} else {
//如果不重复直接跳出循环
break;
}
}
}
//正常情况取中间值
results.add(mid);
if(mid < high) {
//同上,遍历中间值后面的元素,判断是否重复
for(int i = mid + 1; i <= high; i++) {
if(data[i] == item) {
results.add(i);
} else {
break;
}
}
}
return results;
} else if (guess > item) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return results;
}
结果:
result position = [7, 8, 9]
这样,基本的二分查找就结束了,其实原理都不是很难,只要肯静下心来稍微分析一下就会了。各位如果看到有问题的可以及时反馈。