Java 为二进制搜索的复合对象编写比较器
我有一个类和实例列表,看起来像这样(更改字段名以保护无辜/专有):Java 为二进制搜索的复合对象编写比较器,java,binary-search,comparator,Java,Binary Search,Comparator,我有一个类和实例列表,看起来像这样(更改字段名以保护无辜/专有): 公共类膨胀 { 公共长时间(毫秒); 公共长空格单位; 公共长期成本; } 公共类膨胀生产者 { 最终私有列表bloatList=new ArrayList(); 最终私有随机=新随机(); 公共无效生产商人数() { int n=bloatList.size(); Bloat previousBloat=(n==0)?new Bloat():bloatList.get(n-1); Bloat newBloat=新的Bloat(
公共类膨胀
{
公共长时间(毫秒);
公共长空格单位;
公共长期成本;
}
公共类膨胀生产者
{
最终私有列表bloatList=new ArrayList();
最终私有随机=新随机();
公共无效生产商人数()
{
int n=bloatList.size();
Bloat previousBloat=(n==0)?new Bloat():bloatList.get(n-1);
Bloat newBloat=新的Bloat();
newBloat.timeinmillizes=
previousBloat.timeinmillides+random.nextInt(10)+1;
newBloat.spaceInBytes=
previousBloat.spaceInBytes+random.nextInt(10)+1;
newBloat.costInPennies=
上一个bloat.costInPennies+random.nextInt(10)+1;
bloatList.add(newBloat);
}
/*其他领域/方法*/
公共布尔测试单调性()
{
Bloat-previousBloat=null;
for(Bloat thisBloat:bloatList)
{
如果(上一次膨胀!=null)
{
如果((previousBloat.Timein毫秒)
>=thisblot.timein毫秒)
||(以前的bloat.spaceInBytes
>=thisBloat.spaceInBytes)
||(先前的膨胀
>=此膨胀。成本(单位:便士)
返回false;
}
previousBloat=此Bloat;
}
返回true;
}
膨胀生产者膨胀生产者;
列表bloatList
由BloatProducer
在内部保存,并以这样的方式进行维护:它只附加新的Bloat
记录,不修改任何旧记录,并且每个字段都是单调递增的,例如BloatProducer.testmonotonity()
将始终返回true
我想使用Collections.binarySearch(list,key,comparator)
来搜索Bloat
记录,搜索方式可以是timein毫秒、spaceInBytes或costInPennies字段。(如果数字介于两条记录之间,我想查找上一条记录)
编写一系列3个Comparator类的最简单方法是什么?我是否必须使用一个膨胀对象的键,并为我没有搜索的对象使用虚拟字段?如果你想利用对所有三个属性的二进制搜索,你必须为它们创建Comparator,并对其他列表或树集进行排序y比较器。如果要按3个属性中的每一个进行搜索,则需要有3个独立的
比较器
一个更简洁的选择是使用一个通用的比较器
,它接收一个参数,告诉它通过哪个字段进行比较
基本的通用比较器应该如下所示:
public class BloatComparator implements Comparator<Bloat>
{
CompareByEnum field;
public BloatComparator(CompareByEnum field) {
this.field = field;
}
@Override
public int compare(Bloat arg0, Bloat arg1) {
if (this.field == CompareByEnum.TIME){
// compare by field time
}
else if (this.field == CompareByEnum.SPACE) {
// compare by field space
}
else {
// compare by field cost
}
}
}
公共类BloatComparator实现Comparator
{
CompareByEnum字段;
公共BloatComparator(CompareByEnum字段){
this.field=字段;
}
@凌驾
公共整数比较(膨胀arg0,膨胀arg1){
if(this.field==CompareByEnum.TIME){
//按现场时间比较
}
else if(this.field==CompareByEnum.SPACE){
//按字段空间比较
}
否则{
//按现场成本进行比较
}
}
}
您需要为要比较的每个字段编写一个单独的比较器:
public class BloatTimeComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
if (bloat1.timeInMilliseconds > bloat2.timeInMilliseconds) {
return 1;
} else if (bloat1.timeInMilliseconds < bloat2.timeInMilliseconds) {
return -1;
} else {
return 0;
}
}
}
对于binarySearch方法,返回值为:
搜索键的索引(如果它包含在列表中);否则,((插入点)-1)。插入点定义为将键插入列表的点:大于键的第一个元素的索引,或list.size()如果列表中的所有元素都小于指定的键。请注意,这保证了当且仅当找到键时,返回值将>=0
这是您指定的所需索引。以下是编写第一个比较器的测试驱动方法:
public class BloatTest extends TestCase{
public class Bloat {
public long timeInMilliseconds;
public long spaceInBytes;
public long costInPennies;
public Bloat(long timeInMilliseconds, long spaceInBytes, long costInPennies) {
this.timeInMilliseconds = timeInMilliseconds;
this.spaceInBytes = spaceInBytes;
this.costInPennies = costInPennies;
}
}
public void testMillisecondComparator() throws Exception {
Bloat a = new Bloat(5, 10, 10);
Bloat b = new Bloat(3, 12, 12);
Bloat c = new Bloat(5, 12, 12);
Comparator<Bloat> comparator = new MillisecondComparator();
assertTrue(comparator.compare(a, b) > 0);
assertTrue(comparator.compare(b, a) < 0);
assertEquals(0, comparator.compare(a, c));
}
private static class MillisecondComparator implements Comparator<Bloat> {
public int compare(Bloat a, Bloat b) {
Long aTime = a.timeInMilliseconds;
return aTime.compareTo(b.timeInMilliseconds);
}
}
}
public类bloassert扩展了TestCase{
公共类膨胀{
公共长时间(毫秒);
公共长空格单位;
公共长期成本;
公共膨胀(长时间毫秒、长空间字节、长成本字节){
this.timeinmillizes=timeinmillizes;
this.spaceInBytes=spaceInBytes;
this.costInPennies=costInPennies;
}
}
public void testmillissecondcomparator()引发异常{
膨胀a=新膨胀(5,10,10);
膨胀b=新膨胀(3,12,12);
Bloat c=新的Bloat(5,12,12);
比较器比较器=新的毫秒比较器();
assertTrue(比较器比较(a,b)>0);
assertTrue(比较器比较(b,a)<0);
assertEquals(0,比较器。比较(a,c));
}
私有静态类毫秒比较器实现比较器{
公共整数比较(膨胀a、膨胀b){
长时间=a.timein毫秒;
返回aTime.compareTo(b.timein毫秒);
}
}
}
测试程序(MultiBinarySearch.java
)以查看这些想法是否正常工作(它们似乎:
package com.example.test;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.Comparator;
导入java.util.List;
导入java.util.Random;
阶级膨胀
{
最终公共长时间(毫秒);
最终公共长空格单位;
最终公共长期成本;
静态最终私有整数N=100;
公共膨胀(长l1、长l2、长l3){
timeinms=l1;
spaceInBytes=l2;
成本指数=l3;
}
公共Bloat(){this(0,0,0);}
公共膨胀更多膨胀(随机r)
{
还新
Collections.binarySearch(bloatList, bloatObjectToFind,
new BloatTimeComparator());
public class BloatTest extends TestCase{
public class Bloat {
public long timeInMilliseconds;
public long spaceInBytes;
public long costInPennies;
public Bloat(long timeInMilliseconds, long spaceInBytes, long costInPennies) {
this.timeInMilliseconds = timeInMilliseconds;
this.spaceInBytes = spaceInBytes;
this.costInPennies = costInPennies;
}
}
public void testMillisecondComparator() throws Exception {
Bloat a = new Bloat(5, 10, 10);
Bloat b = new Bloat(3, 12, 12);
Bloat c = new Bloat(5, 12, 12);
Comparator<Bloat> comparator = new MillisecondComparator();
assertTrue(comparator.compare(a, b) > 0);
assertTrue(comparator.compare(b, a) < 0);
assertEquals(0, comparator.compare(a, c));
}
private static class MillisecondComparator implements Comparator<Bloat> {
public int compare(Bloat a, Bloat b) {
Long aTime = a.timeInMilliseconds;
return aTime.compareTo(b.timeInMilliseconds);
}
}
}
package com.example.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
class Bloat
{
final public long timeInMilliseconds;
final public long spaceInBytes;
final public long costInPennies;
static final private int N = 100;
public Bloat(long l1, long l2, long l3) {
timeInMilliseconds = l1;
spaceInBytes = l2;
costInPennies = l3;
}
public Bloat() { this(0,0,0); }
public Bloat moreBloat(Random r)
{
return new Bloat(
timeInMilliseconds + r.nextInt(N) + 1,
spaceInBytes + r.nextInt(N) + 1,
costInPennies + r.nextInt(N) + 1
);
}
public String toString() {
return "[bloat: time="+timeInMilliseconds
+", space="+spaceInBytes
+", cost="+costInPennies
+"]";
}
static int compareLong(long l1, long l2)
{
if (l2 > l1)
return -1;
else if (l1 > l2)
return 1;
else
return 0;
}
public static class TimeComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
return compareLong(bloat1.timeInMilliseconds, bloat2.timeInMilliseconds);
}
}
public static class SpaceComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
return compareLong(bloat1.spaceInBytes, bloat2.spaceInBytes);
}
}
public static class CostComparator implements Comparator<Bloat> {
public int compare(Bloat bloat1, Bloat bloat2) {
return compareLong(bloat1.costInPennies, bloat2.costInPennies);
}
}
enum Type {
TIME(new TimeComparator()),
SPACE(new SpaceComparator()),
COST(new CostComparator());
public Comparator<Bloat> comparator;
Type(Comparator<Bloat> c) { this.comparator = c; }
}
}
class BloatProducer
{
final private List<Bloat> bloatList = new ArrayList<Bloat>();
final private Random random = new Random();
public void produceMoreBloat()
{
int n = bloatList.size();
Bloat newBloat =
(n == 0) ? new Bloat() : bloatList.get(n-1).moreBloat(random);
bloatList.add(newBloat);
}
/* other fields/methods */
public boolean testMonotonicity()
{
Bloat previousBloat = null;
for (Bloat thisBloat : bloatList)
{
if (previousBloat != null)
{
if ((previousBloat.timeInMilliseconds
>= thisBloat.timeInMilliseconds)
|| (previousBloat.spaceInBytes
>= thisBloat.spaceInBytes)
|| (previousBloat.costInPennies
>= thisBloat.costInPennies))
return false;
}
previousBloat = thisBloat;
}
return true;
}
public int searchBy(Bloat.Type t, Bloat key)
{
return Collections.binarySearch(bloatList, key, t.comparator);
}
public void showSearch(Bloat.Type t, Bloat key)
{
System.out.println("Search by "+t+": ");
System.out.println(key);
int i = searchBy(t,key);
if (i >= 0)
{
System.out.println("matches");
System.out.println(bloatList.get(i));
}
else
{
System.out.println("is between");
i = -i-1;
Bloat b1 = (i == 0) ? null : bloatList.get(i-1);
System.out.println(b1);
Bloat b2 = (i >= bloatList.size()) ? null : bloatList.get(i);
System.out.println("and");
System.out.println(b2);
}
}
}
public class MultiBinarySearch {
private static int N = 1000;
public static void main(String[] args)
{
BloatProducer bloatProducer = new BloatProducer();
for (int i = 0; i < N; ++i)
{
bloatProducer.produceMoreBloat();
}
System.out.println("testMonotonicity() returns "+
bloatProducer.testMonotonicity());
Bloat key;
key = new Bloat(10*N, 20*N, 30*N);
bloatProducer.showSearch(Bloat.Type.COST, key);
bloatProducer.showSearch(Bloat.Type.SPACE, key);
bloatProducer.showSearch(Bloat.Type.TIME, key);
key = new Bloat(-10000, 0, 1000*N);
bloatProducer.showSearch(Bloat.Type.COST, key);
bloatProducer.showSearch(Bloat.Type.SPACE, key);
bloatProducer.showSearch(Bloat.Type.TIME, key);
}
}