Optimisation advice (HashMap) - java

I have a big list of coordinates (this form):
if(x == 1055 && y == 63 && z == 1117)
return blackwood;
if(x == 1053 && y == 63 && z == 1117)
return blackwood;
if(x == 1049 && y == 64 && z == 1113)
return blackwood;
if(x == 1054 && y == 63 && z == 1112)
return blackwood;
if(x == 1058 && y == 63 && z == 1112)
return blackwood;
if(x == 1062 && y == 64 && z == 1117)
return blackwood;
if(x == 1050 && y == 64 && z == 1117)
return blackwood;
if(x == 1062 && y == 64 && z == 1118)
return glass;
if(x == 1050 && y == 64 && z == 1118)
return andesite;
(Much longer than that)
But, when I call the method that execute these instructions, I have a lag (Not very long, but enough to have a freeze impression in-game).
So, my question is, how can I optimize this?
I was thinking about stocking these in a HashMap and use HashMap.get(key), but, does HashMap.get(key) iterate the list to find it out?

You could indeed use a Map with as key a custom class that uses as component value these 3 data : x, y and z.
With a fair implementation of the hashCode() method, it should be a constant time [O(1)] or very close to.
If you have to recreate the map as often as you need to request it, using a map could be helpless as from one side you could loose what you gain from another side.
So, create this custom class and override hashCode() and equals() by taking these 3 fields into consideration :
public class Coordinate {
private int x;
private int y;
private int z;
public Coordinate(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
#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 instanceof Coordinate))
return false;
Coordinate other = (Coordinate) obj;
if (x == other.x && y == other.y && z == other.z)
return true;
return false;
}
}
Then you could initialize the map with expected key-values :
Map<Coordinate, MyValue> mapValuesByCoord = new HashMap<>();
mapValuesByCoord.put(new Coordinate(1055,63,1117), blackwood);
mapValuesByCoord.put(new Coordinate(1053,63,1117), blackwood);
mapValuesByCoord.put(new Coordinate(1062, 64, 1118), glass);
...
And use the map in this way :
MyValue value = mapValuesByCoord.get(new Coordinate(1055,63,1117));

There's an issue here with the common use of the word "map", as in a piece of paper showing a miniature representation of a piece of land, versus the programmer or mathematician's use of "map", in which values are associated with other values.
If pretty much every 3D coordinate has a corresponding return value, you would be better off having a direct lookup table. You could do this with a 3D array, i.e. an array-of-arrays-of-arrays:
Rock[][][] rockMap = ... // Google for guidance on initialising a 3D array
...
rockMap[1054][63][1112] = blackwood;
// etc.
Here "rockMap" is closer to the common use of the word "map". If you drew that 3D array, it would be your "world map".
Then your lookup is:
return rockMap[x][y][z];
Alternatively you could use a 1D array and calculate an index from x, y, z:
Rock[] rockMap = new Rock[SIZE_X * SIZE_Y * SIZE_Z];
rockMap[1054 * SIZE_Y * SIZE_Z + 63 * SIZE_Z + 1112] = blackwood;
Lookup is similar to assignment:
return rockMap[x * SIZE_Y * SIZE_Z + y * SIZE_Z + z];
If you don't have a rock for every coordinate, this approach would still work (you'd just have a null, or some other absence marker, in all the empty slots). But it would be a bit wasteful of space.
In this case it could be more efficient to create a Coordinate type, and construct a Map<Coordinate>.
Map<Coordinate> rockMap = ...;
rockMap.put(new Coordinate(x,y,z), blackwood);
...
return rockMap.get(new Coordinate(x,y,z));
You should do your own tests to find out what type of Map works best in your program -- HashMap? TreeMap? Test them.
For these to work, Coordinate needs to implement certain methods -- check the Javadoc and make sure it does.

HashMap rarely iterates to get an element from its structure. Proper implementations iterate so rarely that people usually don't bother mentioning that part exists. Hence the O(1) complexity.
Imagine a table of your elements (every element has a key). Ideally HashMap will put every one of your elements in a unique row (so only 1 element per row). When given a key to get an element, HashMap will calculate a hash (int) of the key and find out in which row is its appropriate value located. Multiple elements in one row can occur because sometimes two different keys can have same hashes and then you iterate that row to find your element.
I think you could use a HashMap on your problem to speed it up a bit (where x, y and z should be unique keys).

I would create blackwood, glass and andesite object that have check(x, y, z) method.
Edit:
Maybe I should have also added that to make it more efficient you can implement blackwood.check(x, y, z) like this:
public boolean check(int x, int y, int z){
if ( y == 63 || y == 64){
if (z == 1117 || z == 1113 || z == 1112){
if (x == 1055 || x == 1053 || x == 1049 || x = 1054 ||
x == 1058 || x == 1062 || x == 1050){
return true;
}
}
}
return false;
}
What you will gain from this:
1) The logic for each type is encapsulated into separate classes and you wont have one huge method with long "ifs". And it will be easy to add a new type.
2) By moving the "y" check to top you will do a quick exit if its not 63 or 64. Same applies to z. Since "or" check in Java will not check the rest you will buy some performance by not checking all "x" values if x is 1055 for example.
3) Using Map or Set approach you have to create X, Y, Z wrapper key object on each call to your method. With the method being called very frequently you might have issues with garbage collector not being able to clean them up fast enough.

Related

More efficient way to check if a value is included in an array?

Writing a game that does lots of comparisons, and it's lagging. I'm trying to speed it up, and this particular chunk of code is run thousands of times every frame, for different values of x y and z. Is there a better way to check if the values of x y and z are valid in the array? (java)
if (x >= 0 && x < blocksArr.length && y >= 0 && y < blocksArr[x].length && z >= 0 && z < blocksArr[x][y].length && blocksArr[x][y][z])
I've tried checking if blocksArr[x][y][z] != null and checking if blocksArr[x][y][z] != undefined but neither give results.
In general, the most efficient way of doing t >= 0 && t < u with u known to be positive is to compare the unsigned value of t and u using Integer.compareUnsigned(t, u) < 0. As a result, your if can be more efficiently expressed as
if (Integer.compareUnsigned(x, blocksArr.length) < 0 &&
Integer.compareUnsigned(y, blocksArr[x].length) < 0 &&
Integer.compareUnsigned(z, blocksArr[x][y].length) < 0 &&
blocksArr[x][y][z])
However, I think your representation of blocksArr as a 3-dimensional array is really inefficient and results in a lot of indirections, which greatly hinders the potential performance. A more logical approach is to represent it as a single array and have length, width, height being stored separately. This would result in your code looks something like this:
if (Integer.compareUnsigned(x, length) < 0 &&
Integer.compareUnsigned(y, width) < 0 &&
Integer.compareUnsigned(z, height) < 0 &&
blocksArr[x * (width * height) + y * height + z])
This however limits your block to around 2 billion elements, to overcome this limitation, you need to resort to the Memory Access API, which is currently in preview. It has an important advantage that it allows the allocation and deallocation of memory blocks to be deterministic, which is much more desirable for too large memory pieces. Using a memory segment to represent the blocksArr, your code would become:
if (Long.compareUnsigned(x, length) < 0 &&
Long.compareUnsigned(y, width) < 0 &&
Long.compareUnsigned(z, height) < 0 &&
blocksArr.get(ValueLayout.JAVA_BOOLEAN, x * (width * height) + y * height + z))
Moreover, since blocksArr is a block of boolean values, packing them so that each element occupies only 1 bit will improve the memory consumption and cache pressure greatly. The check now can be expressed as:
long index = x * (width * height) + y * height + z;
long byteIndex = index >>> 3;
int shift = (int)(index & 7);
if (Long.compareUnsigned(x, length) < 0 &&
Long.compareUnsigned(y, width) < 0 &&
Long.compareUnsigned(z, height) < 0 &&
blocksArr.get(ValueLayout.JAVA_BYTE, byteIndex) & (1 << shift) != 0)
I don't know java but in general, I would expect the following to be at least as fast, possibly faster.
Your compiler may do something like this anyway so it might not be faster. You can split the 'If' statement up so that it will do fewer lookups. Sorry, but I'll have to write it as c code. You can get the idea and translate to java.
if (x >= 0 && y >= 0 && z >= 0 && x < blocksArr.length) {
if (y < blocksArr[x].length && z < blocksArr[x][y].length && blocksArr[x][y][z]) {
.....
}
}
Assuming user16320675 is correct about the evaluation order, you could use one 'if' statement. I don't know how the java compiler works.
if (x >= 0 && y >= 0 && z >= 0 && x < blocksArr.length && y < blocksArr[x].length && z < blocksArr[x][y].length && blocksArr[x][y][z]) .....
What you are doing is a bounds check, to make sure that the indexes x, y, and z are valid indices in the blocksArr[][][] array. In C, this is necessary as C allows you to go outside the array.
Java, however, does a bounds check every time you access the array. So you are doing a manual bounds check, then another check, plus Java is doing a check on two dimensions, and finally Java does another check on three dimensions.
All you really need to do is access the array, let Java do the bounds check, and catch an exception if any of the indices are out of bounds.
boolean value;
try
{
value = blocksArr[x][y][z];
}
catch (ArrayIndexOutOfBoundsException e )
{
value = false;
}
There is some overhead in setting up a try/catch block, but overall it should be faster.
You have a box determined by three dimensions, x, y, and z.
If any of those indices are outside the boundaries of the box, then the entire if() statement is false. So there is no need to walk through things like blocksArr[x].length
Also, think about what is actually going on under the hood. The variable x is in fact a pointer to a location in memory which holds the value. To process a statement like x >= 0, the computer must locate the memory location for x, fetch that value and put it into one of its internal registers, say register A. It then takes that value 0 and puts it into register B. It compares Register A to register B. if A > B, then it goes on to the next operation, otherwise it compares A to B again. If the comparison is zero, then it goes to the next operation, otherwise it move the operation pointer past the if() statement.
For comparing x < blocksArr.length, it again fetches x, then fetches blocksArr calculates the offset to the length value, then fetches that into the register, where it does the comparison.
You can shorten all of this by using some static constants.
Consider that x >= 0 can be re-written as x > -1. This can potentially reduce 2 comparisons to 1, so a few CPU cycles saved.
An array construct is an immutable object, that is it cannot be changed after being created. So an array's length will never be different. So if you created an array with size 5, blocksArr.length will always return 5. in the comparison x < blocksArr.length you could substitute x < 5, which means the CPU does not need to fetch blocksArr.length, which saves CPU cycles.
So you could re-write the array creation, and your if statement to:
public static final int MAX_X = 10;
public static final int MAX_Y = 15;
public static final int MAX_Z = 20;
public boolean blocksArr[][][] = new boolean[MAX_X][MAX_Y][MAX_Z];
.
.
.
if ( ( x > -1 && x < MAX_X ) && // validate for X dimension
( y > -1 && y < MAX_Y ) && // validate for Y dimension
( z > -1 && z < MAX_Z ) && // validate for Z dimension
blocksArr[x][y][z] ) // check value
I think this is the least CPU intensive way of doing this.

How do I calculate this code's time complexity? [duplicate]

This question already has answers here:
Big O, how do you calculate/approximate it?
(24 answers)
Closed 3 years ago.
I'm struggling with calculating time complexity in this code.
Only capable of simple code at the moment...
just want to try with complex one!
public static int PATHWAY = 0;
public static int WALL = 1;
public static int MARKED = 2;
public static boolean find(int x, int y) {
if(x == 7 && y == 7) return true;
maze[x][y] = MARKED;
if(x != 0 && maze[x-1][y] == PATHWAY && find(x-1, y)) return true;
if(y != 0 && maze[x][y-1] == PATHWAY && find(x, y-1)) return true;
if(x != 7 && maze[x+1][y] == PATHWAY && find(x+1, y)) return true;
if(y != 7 && maze[x][y+1] == PATHWAY && find(x, y+1)) return true;
return false;
}
Well, in each recursive call you visit a single cell in your 2D array.
Since you mark the visited cells, you can't visit the same cell twice.
Hence the total recursive calls is bound by the length of the 2D array.
Apart from the recursive call, you perform a constant amount of work in each execution of the find() method.
Therefore the time complexity is O(N*M) if N is the number of rows and M the number of columns of the 2D array.
Of course, based on your stopping condition of if(x == 7 && y == 7) return true;, it looks like the dimensions of your 2D array are 8x8, which can be seen as a constant. That would make the running time O(1).
O(N*M) is the complexity for a general input array.
Basically you can calculate assignments and operations.
Have a
int assignments = 0;
int operations = 0;
which you will increment every time you do one.
Other way in doing this is to monitor the time, but it's not the most reliable one.
You can also calculate/approximate Big-O, check Big O, how do you calculate/approximate it?
Well it's not that hard, it actually uses DFS in order to find a path. the order of DFS is O(V+E), where V is the number of vertices and E is the number of edges.
In this case you are using a adjacency matrix to represent your graph. so in worst case the time complexity would be O(M*N), where M is the number of rows and N is the number of columns.

How to write a LessThan method without using the operator

How would you recursively write a method that checks if a number is less than the other without using the '<' operator?
You can only use the plus, minus, times, and equals operators.
It must be recursive
x and y will always be 0 or greater
Should return boolean
If needed, you can make other methods but they must follow rules above.
Cove I've got so far:
public static boolean isLessThan(int x, int y) {
if(x == y - 1) return true;
if(x == y + 1) return false;
if(x == y) return false;
return isLessThan((x), (y-1)) || isLessThan((x-1), y);
}
Because you have made a good-faith attempt by writing your own code, and because I see this is a kind of puzzle, I'm offering you below code which has only a single recursive call rather than having two recursive calls like in your code.
I think this is as simple as it gets while satisfying the constraints.
What it does: it counts down both numbers to zero, and checks which one reaches zero first. If both reach zero at the same time, the result should be false, but simply checking whether y is zero already includes that check.
public static boolean isLessThan(int x, int y) {
if (y == 0) {
return false;
}
if (x == 0) {
return true;
}
return isLessThan(x - 1, y - 1);
}
#Andreas' answer is more efficient than the above. My aim initially was for a short, clean answer.
I've tried to create a shorter bitshift approach.
Although harder to grasp than the counting example, it has a better complexity and it has an equal amount of lines as the above code (I'm not counting that constant as I could include it inside the code at the expense of readability).
Note that this code shifts left rather than right and - it checks the most significant bit first.
public static final int HIGH_BIT = 1 << 31;
public static boolean isLessThan(int x, int y) {
if (x == y) {
return false;
}
if ((x & HIGH_BIT) != (y & HIGH_BIT)) {
return (y & HIGH_BIT) == HIGH_BIT;
}
return isLessThan(x << 1, y << 1);
}
Note: if != is disallowed, you can change the second if statement to:
if (((x ^ y) & HIGH_BIT) == HIGH_BIT)
Also note that the complexity is really O(1) as, although the algorithm is theoretically O(log n), Java ints are 32 bits so the upper bounds is O(32) which is the same as O(1).
You could do it like the answer to this question:
Bitwise operations equivalent of greater than operator
However that doesn't honor rule 2: It must be recursive.
According to comment, rule 1 should be:
You can only use plus, minus, multiply, equals, and bitwise operators.
With the use of the right-shift operator, we can get a solution in O(log n) time, unlike answer by Erwin Bolwidt, which is O(n) time, and likely to cause StackOverflowError.
public static boolean isLessThan(int x, int y) {
return compare(x, y) == -1;
}
private static int compare(int x, int y) {
if (x == y)
return 0; // x == y
if (x == 0)
return -1; // x < y
if (y == 0)
return 1; // x > y
// Compare higher bits. If different, then that is result
int cmp = compare(x >> 1, y >> 1);
if (cmp != 0)
return cmp;
// Only bit 0 differs, so two choices:
// x0 == 1 && y0 == 0 -> return 1
// x0 == 0 && y0 == 1 -> return -1
return (x & 1) - (y & 1);
}
If != is not allowed, code can be changed to:
// same code up to and including recursive call
if (cmp == 0)
return (x & 1) - (y & 1);
return cmp;

Mathematical induction of this Code?

I don't really understand how I use proof by induction on this Code.
I just wanna know how to prove the correctness of this code and algorithm.
Prove that we will never count items which already counted .
Algorithm for countCells(x,y)
if the cell at(x,y) is outside
the grid the result is 0;
else if
the color of the cell at (x, y) is not the abnormal color the result is 0;
else
set the color of the cell at (x, y) to a temporary
color; the result is 1 plus the number of cells in each piece of the
blob that includes a nearest neighbor;
public int countCells(int x, int y)
{
int result;
if(x<0 || x>=N || y<0 || y>=N) // N is the maximum value of the matrix
return 0;
else if(!getColor(x,y).equals(ABNORMAL)) //
return 0;
else
{
recolor(x, y, TEMPORARY);
return 1 + countCells(x-1, y+1) + countCells(x, y+1)
+ countCells(x+1, y+1) + countCells(x-1, y)
+ countCells(x+1, y) + countCells(x-1, y-1)
+ countCells(x, y-1) + countCells(x+1, y-1)
}
}
the following link show how this works
http://kin.naver.com/qna/detail.nhn?d1id=1&dirId=104&docId=186514818
Proof by induction
Prove for base case condition (n = 1)
Prove for all assumption step ( n = k )
Prove for inductive step + 1 (n = k + 1)
So call your function with a base for step 1, let k equal some other generic input, then do the input + 1.
Basically you want to test the edge cases of your functions to ensure that they work properly. Your teacher probably wants you to just write test conditions for the function above.

Java - Recursive function of the Euclidean Algorithm

I can't seem to convert the following algorithm into Java successfully, please forgive the horrible picture quality but a question I'm working on asks:
I have tried to use the following code to represent the Euclidean Algorithm, but it doesn't seem to work. I don't really know how I would go about representing it in Java code. Any help?
public static int gcd(int x, int y) {
if (y == 0) {
return x;
} else if (x >= y && y > 0) {
return gcd(y, (x % y));
}
}
Thank you.
There is no arbitrary order between x and y.
Your code is not complete!
What if x < y? Your code does not return a value then!
What the book fails to mention is that the two parameters to the function do not necessarily need to be in descending order (ie x >= y). What you need to do is compute the gcd considering this fact.
Simply you can do the following:
public static int gcd ( int x , int y )
{
if ( y == 0 )
return x;
else if ( x >= y && y > 0)
return gcd ( y , x % y );
else return gcd ( y , x ); // if x < y then go ahead and switch them around.
}
You are almost there. You need to consider what happens when y > x, and return the result from the final else branch (hint: x and y can freely switch places).
You are almost there.
Your code does not compile, because there is no catch all clause that return from the function.
It really depends on whether you are going to pass negative values of y into this function. If you expect only positive values, just throw an exception.
public static int gcd(int x, int y) {
if (y == 0) {
return x;
} else if (x >= y && y > 0) {
return gcd(y, (x % y));
}
throw
new IllegalArgumentException(
String.format(
"Unexpected values for x(%d) and y(%d)",
Integer.valueOf( x ),
Integer.valueOf( y )
)
);
}
Here's what I have that accounts for negative numbers:
public static int gcd(int x, int y)
{
if (y == 0)
return x;
if (x < 0)
return gcd(x * -1, y); //turns the first parameter to a positive if it's initally negative
if (y < 0)
return gcd(x, y * -1); //turns the second parameter to a positive if it's initally negative
if (y <= x && x % y == 0)
return y;
return gcd(y, x%y);
}
Note with negative numbers, if you try to find the greatest common divisor, and either of the numbers is negative, you can just change it to a positive and the result would be the same.
If both of the numbers are negative, then I'm not sure what the gcd should be. 1? -1? idk so I left that out. The code I have just treats it as if they were both positive.

Categories