I am trying to get the biggest and second biggest distance in a Hashmap in Java.
Basically, from a hashmap populated with (x,y) values, I plan to pick a point, set it as a fixed point and calculate distance with this point in relation to all the other points. After all possible distances are calculated, I change the fixed point to the next element in the HashMap. With this process, I aim to get the biggest and second biggest value in a hashmap distance-wise.
HashMap<Integer, Integer> corners = getPotentialCorners(image);
HashMap<Integer, Integer> extremeCorners = new HashMap<>();
int Blue = new Color(0, 0, 255).getRGB();
int currentNumberX;
int currentNumberY;
int pivotVarX;
int pivotVarY;
double distance;
double Highest = 0;
double Highest2 = 1;
int xHighest = 0;
int yHighest = 0;
int xHighest2 = 0;
int yHighest2 = 0;
for (int i : corners.keySet()) {
currentNumberX = (i);
currentNumberY = corners.get(currentNumberX);
for (int j : corners.keySet()) {
pivotVarX = j;
pivotVarY = corners.get(pivotVarX);
distance = Math.abs(Math.sqrt(Math.pow((pivotVarX - currentNumberX), 2) + Math.pow((pivotVarY - currentNumberY), 2)));
if (pivotVarX != currentNumberX) {
if ((Highest > Highest2)) {
xHighest = currentNumberX;
yHighest = currentNumberY;
Highest2 = distance;
}
if (distance > Highest2) {
Highest2 = distance;
xHighest2 = currentNumberX;
yHighest2 = currentNumberY;
}
}
}
}
With this code, I debugged it, and I always get one correct point, and another point is ALWAYS (0,0). I know the issue lies with my process of getting the second highest point (Highest2, XHighest2,YHighest2), but I do not know how to fix it.
As others pointed out, instead of a HashMap, it is better to use List<Point> which you can easily iterate as:
for (Point p: myList) {
...
}
or if you need more control on which elements to iterate over you can use an integer counter:
for (int j = i+1; j < corners.size(); j++) {
Point p = corners.get(j);
...
}
instead of having to use keySet() and get() and all the problems with identical x-values mapping on the same bin.
Also, there are some trivial speed improvements possible:
No need to use the slow Math.sqrt() function (or Math.abs() as square root is always positive) since you are only comparing larger/smaller distances. You can just compare the squared distances.
The latest Java compiler knows how to optimize Math.pow(int, 2), but to make sure you don't get the overhead of a function call, you can help the compiler by writing: (p.x-q.x)*(p.x-q.x) + (p.y-q.y)*(p.x-q.y)
Renaming current and pivot to p and q for conciseness, your code would look like:
List<Point> corners = getPotentialCorners(image);
Double highest = null;
Double highest2 = null;
Point highestP = null, highestQ = null;
Point highestP2 = null, highestQ2 = null;
for (int i = 0; i < corners.size()-1; i++) {
Point p = corners.get(i);
for (int j = i+1; j < corners.size(); j++) {
Point q = corners.get(j);
double distanceSq = (p.x-q.x)*(p.x-q.x) + (p.y-q.y)*(p.y-q.y);
if (highest == null || distanceSq >= highest) {
// shift highest to second highest
highest2 = highest;
highestP2 = highestP;
highestQ2 = highestQ;
highest = distanceSq;
highestP = p;
highestQ = q;
} else if (highest2 == null || distanceSq > highest2) {
highest2 = distanceSq;
highestP2 = p;
highestQ2 = q;
}
}
}
Related
I have an array with point-objects as an input. I want to sort these points, that I get an Array with the shortest route covering all the points. this is my code so far, but i havent figuered out, how to delete points, once they have been used.
public Point[] poiSort(Point[] poi){
poi = new Point[lenght+1];
poi[0] = points[0];
distances = new Double[lenght];
double Distance = verybignumber;
double Distancecompare;
for (int i = 1; i < leght+1; i++){
for (int j = 1; j < (lenght); j++){
Distancecompare = points[i-1].getDistance(points[j]);
if (Distance > Distancecompare){
Distance = Distancecompare;
poi[i] = points[j];
distances[i-1] = Disstance;
}
}
}
return poi;
}
The problem you are apparently trying to solve doesn't make sense.
Or at least ... the subproblem doesn't.
If you have N points, then the number of pair-wise distances between them is (N-1)^2. For each given point P, there are N - 1 distances to other points. You can't define a relevant / easily computable ordering for the points based on that. So sorting doesn't make sense.
What you could do is to take one point and order (and sort) the others based on the distance to that point. But that means for a total of N points you have N separate orderings.
Note that what you are trying to solve here is a form of the "Traveling Salesman1 Problem" (TSP). TSP has been mathematically proven to be an NP-complete problem. That should tell you that attempting to solve it by sorting (which is O(NlogN)) is not to work.
My advice would be:
Do some reading on the TSP and why it is hard
Try to avoid having to find an exact solution to the problem
Look at the techniques / algorithms for finding approximate solutions ... rather than trying to invent your own algorithm.
Look for an existing library.
1 - Or the "Traveling Salesperson Problem". No, I'm not kidding.
You can build a new array during sorting and return it as result. This way you do not need to delete elements. Alternatively, you could use an ArrayList or a TreeSet for more flexibility.
Here a maybe not so elegant, but working example with arrays:
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
public class Main {
public static void main(String... args) {
Point[] points = {new Point(1,1), new Point(3,3), new Point(2,2)};
Point[] result = sort(points);
for (Point p : result) {
System.out.println("point(" + p.x + ", " + p.y + ")");
}
}
public static Point[] sort(Point[] in) {
if (in == null || in.length == 0) {
return in;
}
Point[] out = new Point[in.length];
Point current = in[0];
for (int i = 0; i < in.length; i++) {
if (i == in.length -1) {
out[in.length -1] = Arrays.stream(in).filter(p -> !p.visited).findAny().orElseGet(null);
break;
}
final Point finalCurrent = current; // variable must be final or effectively final as used in stream
out[i] = finalCurrent;
finalCurrent.visit();
Point next = Arrays.stream(in).filter(p -> !p.visited).min(Comparator.comparingDouble(p -> p.getDistance(finalCurrent))).get();
current = next;
}
return out;
}
}
class Point {
final double x;
final double y;
boolean visited;
Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getDistance(Point point) {
return Math.abs(this.x-point.x) + Math.abs(this.y - point.y);
}
public void visit() {
visited = true;
}
}
I'm having trouble implementing a method to create an array of distances using BFS from a chosen starting vertex, it currently seems to work in some cases, but fails in larger graphs. The idea is each index in the array represents the corresponding vertex in a graph.
here is the relevant code
public int[] getDistances(Graph g, int startVertex) {
boolean[] visited = new boolean[g.getNumberOfVertices()];
int[] distance = new int[g.getNumberOfVertices()];
for (int i = 0; i < distance.length; i++)
{
distance[i] = -1;
}
ArrayList<Integer> q = new ArrayList<Integer>();
q.add(startVertex);
int dist_int = 0;
while (!q.isEmpty())
{
int current = q.get(0);
q.remove(0);
dist_int++;
visited[startVertex] = true;
for (int j = 0; j < g.getEdgeMatrix()[current].length; j++)
{
if (startVertex == j)
distance[j] = 0;
if (g.getEdgeMatrix()[current][j] == 1 && !visited[j])
{
q.add(j);
distance[j] = dist_int;
visited[j] = true;
}
}
}
return distance;
}
the idea is it iterates through an adjacency matrix, determining each unvisited child, each time a child is found the current dist_int is assigned to the corresponding index in the distance array. With the distance increasing each time all of the children of the current node have been assigned, then the current moves to the first child and repeats.
Instead of using dist_int to hold the distance values just call
distance[j] = distance[current] + 1;
I am writing an AI to play Mancala and this is my method in which the AI's calculations are done by examining the outcomes of all 6 possible moves. I use the array staticBoardState to restore boardState (which stores the information about all of the holes on the board) back to its original values after each examination of move outcomes, but staticBoardState seems to be changing in odd ways even though I believe that I do not change it. I am a beginner amateur coder, so please ask questions if my code does not make sense. This is my code:
public int getBotCalc(int boardState[]) {
int[] staticBoardState = boardState;
double[] movePoints = new double[6];
int initialScore = boardState[6];
int scorePoints;
int freeTurnPoints;
double bestMovePoints;
int bestMove;
for(int f = 0; f <= 5; f++) {
boardState = staticBoardState;
int botChoice = f;
int botHole = boardState[botChoice];
boardState[botChoice] = 0;
for(int g = 0; g < botHole; g++) {
botChoice++;
if(botChoice>12) {
botChoice = 0;
}
boardState[botChoice]++;
}
if(botChoice<=5&&boardState[botChoice]==1&&boardState[12-botChoice]>=1) {
boardState[6] += boardState[12 - botChoice] + 1;
boardState[botChoice] = 0;
boardState[12 - botChoice] = 0;
}
scorePoints = boardState[6] - initialScore;
if(botChoice==6) {
freeTurnPoints = 1;
} else {
freeTurnPoints = 0;
}
movePoints[f] = scorePoints + (1.5 * freeTurnPoints);
}
bestMovePoints = movePoints[0];
bestMove = 0;
for(int f = 1; f <= 5; f++) {
if(movePoints[f]>bestMovePoints) {
bestMovePoints = movePoints[f];
bestMove = f;
}
}
boardState = staticBoardState;
return bestMove;
}
Any help is greatly appreciated.
It looks like you're confusing value-type assignment with reference assignment. When you write
staticBoardState = boardState
what happens is that staticBoardState simply holds a reference to the array in memory that boardState is also already referring to. Not they both refer to the same array in memory, which is why staticBoardState is apparently being modified through the use of boardState. What you need to do to fix this is allocate staticBoardState as a new array and explicitly copy its contents, for example using a boardState.clone(), and perform similar copying each time you want to restore your boardState.
I wrote this algorithm. It works (at least with my short test cases), but takes too long on larger inputs. How can I make it faster?
// Returns an array of length 2 with the two closest points to each other from the
// original array of points "arr"
private static Point2D[] getClosestPair(Point2D[] arr)
{
int n = arr.length;
float min = 1.0f;
float dist = 0.0f;
Point2D[] ret = new Point2D[2];
// If array only has 2 points, return array
if (n == 2) return arr;
// Algorithm says to brute force at 3 or lower array items
if (n <= 3)
{
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr.length; j++)
{
// If points are identical but the point is not looking
// at itself, return because shortest distance is 0 then
if (i != j && arr[i].equals(arr[j]))
{
ret[0] = arr[i];
ret[1] = arr[j];
return ret;
}
// If points are not the same and current min is larger than
// current stored distance
else if (i != j && dist < min)
{
dist = distanceSq(arr[i], arr[j]);
ret[0] = arr[i];
ret[1] = arr[j];
min = dist;
}
}
}
return ret;
}
int halfN = n/2;
// Left hand side
Point2D[] LHS = Arrays.copyOfRange(arr, 0, halfN);
// Right hand side
Point2D[] RHS = Arrays.copyOfRange(arr, halfN, n);
// Result of left recursion
Point2D[] LRes = getClosestPair(LHS);
// Result of right recursion
Point2D[] RRes = getClosestPair(RHS);
float LDist = distanceSq(LRes[0], LRes[1]);
float RDist = distanceSq(RRes[0], RRes[1]);
// Calculate minimum of both recursive results
if (LDist > RDist)
{
min = RDist;
ret[0] = RRes[0];
ret[1] = RRes[1];
}
else
{
min = LDist;
ret[0] = LRes[0];
ret[1] = LRes[1];
}
for (Point2D q : LHS)
{
// If q is close to the median line
if ((halfN - q.getX()) < min)
{
for (Point2D p : RHS)
{
// If p is close to q
if ((p.getX() - q.getX()) < min)
{
dist = distanceSq(q, p);
if (!q.equals(p) && dist < min)
{
min = dist;
ret[0] = q;
ret[1] = p;
}
}
}
}
}
return ret;
}
private static float distanceSq(Point2D p1, Point2D p2)
{
return (float)Math.pow((p1.getX() - p2.getX()) + (p1.getY() - p2.getY()), 2);
}
I am loosely following the algorithm explained here: http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairDQ.html
and a different resource with pseudocode here:
http://i.imgur.com/XYDTfBl.png
I cannot change the return type of the function, or add any new arguments.
Thanks for any help!
There are several things you can do.
First, you can very simply cut the time the program takes to run by changing the second iteration to run only on the "reminder" points. This helps you to avoid calculating both (i,j) and (j,i) for each values. To do so, simply change:
for (int j = 0; j < arr.length; j++)
to
for (int j = i+1; j < arr.length; j++)
This will still be O(n^2) though.
You can achieve O(nlogn) time by iterating the points, and storing each in a smart data structure (kd-tree most likely). Before each insertion, find the closest point already stored in the DS (the kd-tree supports this in O(logn) time), and it is your candidate for minimal distance.
I believe the linked algorithm mentions sorting the array by one coordinate so that given LHS q in point 1 to 2000, if RHS p at point 200 is more than 'min' distance away with only its x distance, you can avoid checking the remaining 201 to 2000 points.
I figured it out - cut the time by a vast amount. The distanceSq function is wrong. Best to use Java's Point2D somepoint.distanceSq(otherpoint); method instead.
As for the original brute force when n is 3 (it will only ever be 3 or 2 in that scenario), a linear search is better and more effective.
The checks against the min variable are also wrong in the inner for loops after the brute force condition. Using squared distance is fine, but min is not squared. It has preserved, original distance, which means that min must be square rooted in both checks (once in the outer loop, once in the inner for each check).
So,
if ((p.getX() - q.getX()) < min)
Should be
if ((p.getX() - q.getX()) < Math.sqrt(min))
Same goes for the other check.
Thanks for your answers everyone!
I'm adding in a loop, but the return value is always 0, I can't figure it out.
If I uncomment one of the final 2 lines, it returns the manual value correctly, and the rest of the class works. ARRAYLIST_SIZE = 10.
public float averageBearing() {
float sumBng = 0;
for (int i = 0; i==ARRAYLIST_SIZE; i++) {
Location l = locList.get(i);
float tempBearing = l.getBearing();
sumBng += tempBearing;
}
float finalBng = sumBng/ARRAYLIST_SIZE;
//remove following lines for real use
//finalBng = (float) (Math.random()*360);
//finalBng = (float) 105.0;
return finalBng;
}
I am reasonably sure the locations in the list have bearings, here is the add method. I have to spoof the bearing for now because the location only has it if we're moving, but I'm at my stationary desk.
public void add(Location location) {
if (locList == null) {
locList = new ArrayList<Location>();
}
//test code to spoof bearing
location.setBearing((float) 105.0);
//use only locations with extra data
if (location.hasBearing() && location.hasSpeed()) {
locList.add(location);
mostRecent = location;
//ensure we have at most 10 recent locations
//no reason to use stale data
while (locList.size()>10) {
locList.remove(0);
}
}
ARRAYLIST_SIZE = locList.size();
}
The conditional expression in your loop is testing equality. It fails on the first test, since i is zero, and ARRAYLIST_SIZE is 10. Change it to this:
for (int i = 0; i<ARRAYLIST_SIZE; i++) {
Change this:
for (int i = 0; i==ARRAYLIST_SIZE; i++)
to this:
for (int i = 0; i<ARRAYLIST_SIZE; i++)
you never enter the for loop because of
i==ARRAYLIST_SIZE
it should be
i<ARRAYLIST_SIZE