二分查找算法变体在实际项目中的应用

一、应用场景

项目场景描述:数据库中共有45万条记录,保存了起始IP和终止IP,以及在此IP段对应的地理位置信息,如 114.104.085.000—114.104.085.255 中国 安徽省 六安市。
项目需求:

  • 输入一条IP地址,可以获得该IP所对应的地理位置信息;
  • 空间复杂度暂时不考虑,要求查找时间小于2ms。

二、算法设计

在海量数据检索处理中,哈希算法是常用的检索算法,由于数据库中存储的是一个IP的范围,因此不能将整个数据集存储到一个HashMap中,所以取IP的前三位作为key值。将IP由字符串转化为Long型,如114.104.085.000转换为114104085000。整个数据集做Hash以后,再将其保存到一个按照起始IP排好序的TreeMap中,其Key值为起始IP,value则保存了地理位置信息。同时将TreeMap中的KeySet转化为List,该List是排好序的,保存该List是因为要利用二分查找来寻找TreeMap中对应的起始IP。二分查找算法,在此处是一个变体,用来寻找小于等于起始IP的最大值。

三、二分查找算法——查找小于key值的最大值与大于key值得最小值

先将二分查找和二分查找算法变体的代码贴出:

public class BinarySearch {
	//基本二分查找
	public static int binarySearch(int[] array, int key){
		int low = 0;
		int high = array.length - 1;
		while(low <= high){
			int mid = (low + high) >> 1;
			if(array[mid] == key)
				return mid;
			else if(array[mid] > key){
				high = mid - 1;
			}
			else{
				low = mid + 1;
			}
		}
		return -1;	
	}
	//查找小于key的最大值
	public static int binaryUpBound(int[] array, int key){
		int low = 0;
		int high = array.length - 1;
		while(low < high){
			int mid = (low + high + 1) >> 1;
			if(array[mid] > key){
				high = mid - 1;
			}
			else{
				low = mid;
			}
		}
		if(array[low] <= key)
			return low;
		else
			return -1;
	}
	//查找大于key的最小值
	public static int binaryLowBound(int[] array, int key){
		int low = 0;
		int high = array.length - 1;
		while(low < high){
			int mid = (low + high) >> 1;
			if(array[mid] < key){
				low = mid + 1;
			}
			else{
				high = mid;
			}
		}
		if(array[high] >= key)
			return high;
		else
			return -1;
	}
}

其中需要注意的地方有一下几个方面:

  1. 二分查找算法的变体中,循环退出条件为low<high,如果依旧写为low<=high,则会导致循环无法退出;
  2. 查找小于key的最大值,取mid值时采用(low+high+1)/2,因为如果low和high值相差1时,如果仍写为(low+high)/2则会导致死循环,循环退出后,下限可能是最终结果;
  3. 查找大于key的最小值,取mid值使用(low+high)/2,这与low=mid+1相对应,不会导致死循环,循环退出后,上限可能是结果。

四、结论

项目中使用了Hash和二分查找的思想,并且做了缓存,经测试,最终查找一条IP的耗时为0.35ms,满足了需求。

    原文作者:查找算法
    原文地址: https://blog.csdn.net/chenxiao_ji/article/details/50981950
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞