当值在范围内时返回键

时间:2016-02-27 05:50:13

标签: java hashmap

我有一个大型数据集,其中值是非重叠范围,按升序排序。范围和键之间有空洞(类型很长)可以分配给多个范围:

[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或者我使用错误的方法?

3 个答案:

答案 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);