我有一个大型数据集,其中值是非重叠范围,按升序排序。范围和键之间有空洞(类型很长)可以分配给多个范围:
[100,300] K1
[310,400] K1
[401,600] K2
[650,1000] K3
...
我需要找到给定值的键。如果值不属于任何范围,我应该返回0.
我的方法是建立
NavigableMap<Long, Range> map = new TreeMap<>();
然后
map.put(K1, new Range(100,300);
...
这会产生一个按键排序的相当大的地图。这不是我想要的,因为我希望有一个按范围值排序的地图,这样我就可以轻松进行二分搜索。我的问题是,我不知道如何使用此地图查找给定值的关键字。例如,值101应该返回K1,500应该返回K2,301应该返回0.有没有办法实现我想要的NavigableMap或者我使用错误的方法?
答案 0 :(得分:1)
由于您已声明范围不能重叠但可能存在间隙,因此您应使用NavigableMap<Range,Long>
Range
表示,该hashCode
表示仅使用equals
范围的下限NavigableMap
实施。
请注意,我已根据您在代码示例中显示的内容颠倒了Range
中泛型类型的顺序。
要搜索一个值,您希望最大条目(即下限最大的条目)小于搜索键。
相反,如果您使用Map
对象的上限,则您希望最小的条目大于搜索键。
找到相应的<div class="collapse navbar-collapse" id="myNav">
<ul class="nav navbar-nav">
<li><a href="index.php">Home</a></li>
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Resource<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="Finan.php">Financial</a></li>
<li><a href="Real.php">Real Estate</a></li>
</ul>
</li>
</ul>
</div>
条目后,由于可能存在间隙,您必须仔细检查键值是否实际在范围内。
答案 1 :(得分:0)
它可能有点虚拟但可能有用。
创建一个min-max-assign (e.g. [100,300, K1])
个值的类型。然后根据min
值对它们进行排序。
如果您搜索min
值,则二分搜索将返回它的位置(比如x),否则返回-index_to_be_inserted - 1
。然后,您可以检查您的值是否在范围内。
例如,
[100,300] K1
[310,400] K1
[401,600] K2
[650,1000] K3
你的arraylist将是100(300,'K1'),310(400,'K1'),401(600,'K2'),650(1000,'K3')。
如果搜索101到309,二进制搜索结果将为-1(x
)。检查索引-x-1 = -(-1)-1 = 0
中的最大值。
如果您搜索了101
然后101<300
,则会返回K1
,如果您搜索了301
,则会返回0
。
我并不认为这是最好的方式,但它是一种适用于O(log_n)
答案 2 :(得分:0)
我相信,根本不需要Map
。您可以在Comparable
类中实现Range
接口,并在排序列表中进行二进制搜索:
public class Range implements Comparable<Range>{
private int start;
private int end;
public Range(int start, int end){
this.start = start;
this.end = end;
}
public int compareTo(Range range) {
if(this.start<range.start) return -1;
if(this.start>range.start) return 1;
if(this.start==range.start){
if(this.end<range.end) return -1;
if(this.end>range.end) return 1;
}
return 0;
}
//... getters for fields
}
public class RangeBianrySearch{
public static Range findRangeFor(int value, List<Range> rangeList) {
return findRange(value, rangeList, 0, rangeList.size()-1);
}
private static Range findRangeFor(int value, List<Range> rangeList, int start, int end) {
if(end<0 || start==rangeList.size()) return null;
int index;
index = start+(end-start)/2;
Range range = rangeList.get(index);
if(start!=end){
if(range.getStart()>value){
return findRangeFor(value, rangeList, start, index-1);
}else
if(range.getEnd()<value){
return findRangeFor(value, rangeList, index+1, end);
}
}
if(range.getStart()<=value && range.getEnd()>=value){
return range;
}
return null;
}
}
用法:
List<Range> rangeList = new ArrayList<Range>();
rangeList.add(new Range(1,100));
rangeList.add(new Range(101,200));
rangeList.add(new Range(250,301));
//etc...
Collection.sort(rangeList); //important
Range range = RangeBianrySearch.findRangeFor(115);