您的代码中存在一些小问题:
-
map.put(loc2.getLoc(), hs); 应该改为 map.put(loc.getLoc(), hs);
- 您需要将
hashCode 方法添加到您的类中,否则您使用的HashSets 将无法识别代表相同位置的对象
- 您只搜索点组,而不是它们的中心
解决方案可能如下所示(在 LocationCopy 类中实现了您的方法,因为您的问题中没有显示任何类):
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class LocationCopy {
private int x, y, z;
//private String world;
public LocationCopy(int x/*, int y*/, int z/*, String world*/) {
this.x = x;
//this.y = y;
this.z = z;
//this.world = world;
}
public LocationCopy(Location spawner) {
this.x = spawner.getBlockX();
this.y = spawner.getBlockY();
this.z = spawner.getBlockZ();
//this.world = spawner.getWorld().getName();
}
//EDIT added toString method (just for better printing and debugging)
@Override
public String toString() {
return "LocationCopy [x=" + x + ", y=" + y + ", z=" + z + "]";
}
//EDIT: added hashCode method that is needed for the HashSets to identify objects that represent the same location
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
result = prime * result + z;
return result;
}
//EDIT: added equals method (not really needed, but better to have one...)
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LocationCopy other = (LocationCopy) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
if (z != other.z)
return false;
return true;
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
public Location getLoc() {
return new Location(x, y, z);
}
public static void main(String[] args) {
List<LocationCopy> locs = createLocs();
HashMap<Location, HashSet<Location>> map = new HashMap<Location, HashSet<Location>>();
for (LocationCopy loc : locs) {
HashSet<LocationCopy> locsCopy = new HashSet<LocationCopy>(locs);
locsCopy.remove(loc);
for (LocationCopy loc2 : locsCopy) {
if (distance(loc2.getX(), loc.getX(), loc2.getZ(), loc.getZ()) <= 16) {
if (!map.containsKey(loc.getLoc())) {
HashSet<Location> hs = new HashSet<Location>();
hs.add(loc2.getLoc());
map.put(loc.getLoc(), hs);//EDIT: changed loc2 to loc
}
else {
HashSet<Location> hs = map.get(loc.getLoc());
hs.add(loc2.getLoc());
map.put(loc.getLoc(), hs);//EDIT: changed loc2 to loc
}
}
}
}
//EDIT: selecting groups for finding the center
Set<Set<Location>> groups = new HashSet<Set<Location>>();
for (Location loc : map.keySet()) {
if (map.get(loc).size() > 5) {
//EDIT: don't know what write does -> using System.out.println instead
//write("More than " + map.get(loc).size() + locToString(loc) + ": " + getLocs(map.get(loc)) + "<br>", fileName, beta);
System.out.println("More than " + map.get(loc).size() + " " + locToString(loc) + ": " + /*getLocs(map.get(loc)) + */"<br>");
//EDIT: create groups to find the center points
Set<Location> group = new HashSet<Location>();
group.addAll(map.get(loc));
group.add(loc);
groups.add(group);
}
}
//EDIT: find the center of the group
for (Set<Location> group : groups) {
Location center = findCenter(group);
System.out.println("center found: " + center);
}
}
/**
* Find the center of each group by calculating the summed distance from each point to every other point.
*
* The point that has the minimum summed distance to every other point is the center.
*/
private static Location findCenter(Set<Location> group) {
if (group.isEmpty()) {
throw new IllegalArgumentException("The group mussn't be empty");
}
List<LocationDistance> summedDistances = new ArrayList<LocationDistance>(group.size());
for (Location loc : group) {
LocationDistance dist = new LocationDistance(loc, 0);
//sum up the distance to each location in the group
for (Location loc2 : group) {
double distance = distance(loc.getBlockX(), loc2.getBlockX(), loc.getBlockZ(), loc2.getBlockZ());
dist.setDistance(dist.getDistance() + distance);
}
summedDistances.add(dist);
}
//sort the list (LocationDistance implements Comparable to do this)
Collections.sort(summedDistances);
//the first item in the list is the center
return summedDistances.get(0).getLocation();
}
private static List<LocationCopy> createLocs() {
List<LocationCopy> locs = new ArrayList<LocationCopy>();
//trying to create the example from the image in your question
locs.add(new LocationCopy(0, 0));
locs.add(new LocationCopy(2, 0));
locs.add(new LocationCopy(5, 0));
locs.add(new LocationCopy(1, 2));
locs.add(new LocationCopy(2, 1));//center
locs.add(new LocationCopy(4, 1));
locs.add(new LocationCopy(3, 2));//adding a new point because otherwhise it will never be enough for a group greater than 5
locs.add(new LocationCopy(10, 30));
locs.add(new LocationCopy(12, 31));
locs.add(new LocationCopy(15, 31));
locs.add(new LocationCopy(8, 36));
locs.add(new LocationCopy(13, 33));//center
locs.add(new LocationCopy(18, 34));
locs.add(new LocationCopy(15, 36));//adding a new point because otherwhise it will never be enough for a group greater than 5
return locs;
}
private static String locToString(Location loc) {
return loc.getBlockX() + " " + loc.getBlockY() + " " + loc.getBlockZ();
}
private static double distance(double x1, double x2, double z1, double z2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(z2 - z1, 2));
}
}
类Location(重要的部分是hashCode方法):
public class Location {
public int x, y, z;
public Location(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public int getBlockX() {
return x;
}
public int getBlockY() {
return y;
}
public int getBlockZ() {
return z;
}
@Override
public String toString() {
return "Location [x=" + x + ", y=" + y + ", z=" + z + "]";
}
//EDIT here the hashCode is also important for the HashSets you use in your code
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
result = prime * result + z;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Location other = (Location) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
if (z != other.z)
return false;
return true;
}
}
还有一个用于比较距离的新类 LocationDistance:
/**
* A class for comparing the distances for locations
*/
public class LocationDistance implements Comparable<LocationDistance> {
private Location location;
private double distance;
public LocationDistance(Location location, double distance) {
this.location = location;
this.distance = distance;
}
@Override
public String toString() {
return "LocationDistance [location=" + location + ", distance=" + distance + "]";
}
@Override
public int compareTo(LocationDistance other) {
return Double.compare(distance, other.getDistance());
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
}
输出是:
More than 6 2 0 0: <br>
More than 6 1 0 2: <br>
More than 6 2 0 1: <br>
More than 6 5 0 0: <br>
More than 6 4 0 1: <br>
More than 6 3 0 2: <br>
More than 6 10 0 30: <br>
More than 6 12 0 31: <br>
More than 6 8 0 36: <br>
More than 6 15 0 31: <br>
More than 6 13 0 33: <br>
More than 6 15 0 36: <br>
More than 6 18 0 34: <br>
More than 6 0 0 0: <br>
center found: Location [x=2, y=0, z=1]
center found: Location [x=13, y=0, z=33]
最后两行是您要搜索的中心。