I was reading about implementing B-Tree from Rober Sedgewik's and found this snippet in the else part of search method from this link: http://algs4.cs.princeton.edu/62btrees/BTree.java.html
// internal node
else {
for (int j = 0; j < x.m; j++) {
if (j+1 == x.m || less(key, children[j+1].key))
return search(children[j].next, key, ht-1);
}
}
I banged my head but couldn't understand why he directly starts comparing key with j+1th element of children and not jth.
Could someone please through some light upon this specific point?
If you look at his declaration of the less() method, you'll notice that it uses compareTo.
Essentially, what he wanted to do was key.compareTo(children[j+1].key)
But why would he use j+1 instead of j? To understand this, look at the first part of his conditional statement; he uses j+1 == x.m, meaning that he wants to test to see if j+1 is the limit. If j+1 = x.m, he doesn't want to continue incrementing j, so he returns. However, if it is not the limit yet, check compare the current key with the next key in the list (because the next key exists). IF the next key in the list is "less" than the current key, search for the current key.
In short:
If j+1 doesn't exist, the first half of the if statement will catch it and it will break out of the for loop. Otherwise, check j+1's key.
Related
I have an ArrayList, which contains game objects sorted by their 'Z' (float) position from lower to higher. I'm not sure if ArrayList is the best choice for it but I have come up with such a solution to find an index of insertion in a complexity faster than linear (worst case):
GameObject go = new GameObject();
int index = 0;
int start = 0, end = displayList.size(); // displayList is the ArrayList
while(end - start > 0)
{
index = (start + end) / 2;
if(go.depthZ >= displayList.get(index).depthZ)
start = index + 1;
else if(go.depthZ < displayList.get(index).depthZ)
end = index - 1;
}
while(index > 0 && go.depthZ < displayList.get(index).depthZ)
index--;
while(index < displayList.size() && go.depthZ >= displayList.get(index).depthZ)
index++;
The catch is that the element has to be inserted in a specific place in the chain of elements with equal value of depthZ - at the end of this chain. That's why I need 2 additional while loops after the binary search which I assume aren't too expensive becouse binary search gives me some approximation of this place.
Still I'm wondering if there's some better solution or some known algorithms for such problem which I haven't heard of? Maybe using different data structure than ArrayList? At the moment I ignore the worst case insertion O(n) (inserting at the begining or middle) becouse using a normal List I wouldn't be able to find an index to insert using method above.
You should try to use balanced search tree (red-black tree for example) instead of array. First you can try to use TreeMap witch uses a red-black tree inside to see if it's satisfy your requirements. Possible implementation:
Map<Float, List<Object>> map = new TreeMap<Float, List<Object>>(){
#Override
public List<Object> get(Object key) {
List<Object> list = super.get(key);
if (list == null) {
list = new ArrayList<Object>();
put((Float) key, list);
}
return list;
}
};
Example of usage:
map.get(0.5f).add("hello");
map.get(0.5f).add("world");
map.get(0.6f).add("!");
System.out.println(map);
One way to do it would to do a halving search, where the first search is half way thru your list (list.size()/2), then for the next one you can do half of that, and so on. With this exponential method, instead of having to do 4096 searches when you have 4096 objects, you only need 12 searches
sorry for the complete disregard for technical terms, I am not the best at terms :P
Unless I overlook something, your approach is essentially correct (but there's an error, see below), in the sense that your first while tries to compute the insert-index such that it will be placed after all lower OR EQUAL Z: there's correctly an equal sign in your first test (updating "start" if it yields TRUE).
Then, of course, there's no need to worry anymore about its position among equals. However, your follow-up while destroys this nice situation: the test in the first follow-up while yields always TRUE (one time) and so you move back; and then you need the second follow-up while to undo that. So, you should remove BOTH follow-up whiles and you're done...
However, there's a little problem with your first while, such that it doesn't always exactly do what the purpose is. I guess that the faulty outcomes triggered you to implement the follow-up whiles to "repair" that.
Here's the issue in your while. Suppose you have a try-index (start+end)/2 that points to a larger Z, but the one just before it has value Z. You then get into your second test (elseif) and set "end" to the position where that Z-value resides. Finally you wind up with precisely that position.
The remedy is simple: in your elseif assignment, put "end = index" (without the -1). Final remark: the test in the elseif is unnecessary, just else is sufficient.
So, all in all you get
GameObject go = new GameObject();
int index = 0;
int start = 0, end = displayList.size(); // displayList is the ArrayList
while(end - start > 0)
{
index = (start + end) / 2;
if(go.depthZ >= displayList.get(index).depthZ)
start = index + 1;
else
end = index;
}
(I hope I haven't overlooked something trivial...)
Add 1 to the least significant byte of the key (with carry); binary search for that insert position; and insert it there.
Your binary search has to be so constructed as to end at the leftmost of a sequence of duplicates, but this is trivial given an understanding of the various Binary search algorithms.
Im currently going over MIT courseware for java and am unsure why there is a piece of code involved. I tried removing the code to determine if it is necessary and it kept the program from running.
I have two arrays, one is names of runners, the other is their times. the goal is to find the index of the lowest (fastest) time and then also give the person with the second fastest time. i.e the command prompt will output john is the fastest and kate is the second fastest
the part i am confused about is "secondIndex == -1 ||" --- why is this here? if i remove it i get the error
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
public static int getSecondIndex(int[] values) {
int minIndex = getMinIndex(values);
int secondIndex = -1;
for(int i = 0; i < values.length; i++) {
if(i == minIndex){
continue;
}
if(secondIndex == -1 ||
values[i] < values[secondIndex]) {
secondIndex = i;
}
}
return secondIndex;
}
It will then evaluate values[secondIndex] which does not have an entry at index -1. The || short circuits from left to right so in the case of secondIndex = -1, values[secondIndex] will never be evaluated.
It's because the loop checks if the current runner's time is less than any time found so far, but when it checks the first runner there is no "fastest runner so far" to compare to. So the check first makes sure that secondIndex has been set at least once before. If it hasn't, the second part of the or statement will never get evaluated (called short-circuit evaluation).
The reason it's there is because of how indexOf works: it can only find things that live on index 0 or higher, so if it cannot find anything, it returns -1.
As such, we compare to -1 to see whether or not something was found at all. If it wasn't, we don't need to waste any more time on it:
if(thing.indexOf(otherthing) == -1) {
// the search failed
}
if it was, we can use the result to immediately look it by using the result of indexOf as an array index.
This condition (secondIndex == -1) is true in the case that secondIndex has not yet been found. Remember that since || is a short circuit operator, if the first condition is true, the second one will not be evaluated. Therefore, if secondIndex is -1, values[secondIndex] will never be evaluated (which is good, because doing so would cause the ArrayIndexOutOfBoundsException).
I am trying to sort a LinkedList in Java. I need to go through mylist from back to front. The elements in the list are objects from my class CustomElement. If they match a certain pattern I want to put them up front.
My problem is that if I detect that the element in my list with index 5 for example matches my pattern and I move it to index 0, the previous element with index 4 has index 5 now, right? That is why I want the for loop to check the element with index 5 again: i++. But that's causing an infinite loop, whreas the method's working fine without i++, but not the way that I want it, because it's skipping the element with index 4 (now 5).
Is it gernerally possible to raise the variable i inside the for loop? And if yes, what am I doing wrong.
for (int i = mylist.size() - 1; i >= 0; i--) {
if (mylist.get(i) matches a certain pattern) {
CustomElement helper = mylist.get(i);
mylist.remove(i);
mylist.add(0, helper);
i++;
}
}
Yes, it is possible to modify i inside your for loop, if it weren't possible, you wouldn't be getting this infinite loop.
What must be happening, is that if (mylist.get(i) matches a certain pattern) continues to be true after a certain point, and you never get to a point where i >= 0 is not true.
So, if myList.get(0) matches your pattern, you'll just put it back at index 0, and keep checking it forever.
It is, but in your case using get(i) for a linked list will give quadratic performance.
If you don't mind your "matching" items being reversed in order then you'd be better creating a new list:
final LinkedList<CustomElement> newList = new LinkedList<> ();
for (final CustomElement e: myList)
{
if (e matches your pattern) { newList.addFirst (e); }
else { newList.addLast (e); }
}
myList = newList;
Then all problems with index variables disappear...
(You could also achieve linear performance whilst modifying the existing list, but it's a little more complicated.)
I have an array with 5 size , and I want to assign value from random function if any index doesn't have it.
while(positionXtoStart==array1[0] || positionXtoStart==array1[1] ||
positionXtoStart==array1[2] || positionXtoStart==array1[3] ||
positionXtoStart==array1[4])
{
positionXtoStart = (rand1.nextInt(400) + 1)+30;
}
this solution is ok for small size of array but if i have array with size of 1000, I cant enter 1000 conditions in the while loop.
I tried For-loop with if-else condition in it but the
problem is, I want to check all array indexes at the same time.
Please try to understand what i am asking. I want to check all array index values at the same time (in one shot).
in For-loop, we can check only one value at a time.
If I understand correctly, you just need to loop through the array, checking each value.
for (int i = 0; i < array1.length; i++)
{
if (array1[i] == positionXtoStart)
{
positionXtoStart = (rand1.nextInt(400) + 1)+30;
break; // exit the loop
}
}
are you looking for something like this?
for(int i=0; i<array1.length; i++)
if(array[i] == whatever)
{
// do stuff
}
unfortunately, what you're asking is not possible. Even in your code:
while(positionXtoStart==array1[0] || positionXtoStart==array1[1] ||
positionXtoStart==array1[2] || positionXtoStart==array1[3] ||
positionXtoStart==array1[4])
the computer is checking one condition at a time. It's not doing all the conditions at once, like you may think it is. The code you posted is equivalent to the code #Supericy and #Samiam posted.
Unless there's a reason the forloops doesn't work for your case, I would say go with the answers that are posted here.
If you have to check each entry you have to go trough the whole array. An unordered array in not really suitable for searching trough it. Maybe you should think of changing your data structure into something like a BST so you have a guarantied O(logn) search.
To compare all elements in an unordered array you need linear time.
In the book 'Data structures and algorithms in java' the following Array search method code is provided:
{
int j;
for(j=0; j< nElems; j++) // for each element,
if( a[j].getLast().equals(searchName)) // found item?
break; // exit loop before end
if(j == nElems) // gone to end?
return null; // yes, can't find it
else
return a[j]; // no, found it
}
I am trying to understand why there needs to be a if(j == nElems) check? Wouldn't the method work the same if it were written as:
{
int j;
for(j=0; j <nElems; j++)
if( a[j].getLast().equals(searchName))
return a[j];
return null;
}
it would :P You could declare the j inside the for to limit its scope as well.
In the first implementation what it do is check if it iterated over all elements and didn't find anything, because j was incremented until it is equal the the condition of stop of the for-loop. I.e., it didn't stop because of break, indicating that it found an element.
I prefer your solution because it's easier to read :)
Yes, both of these ways are give the same result.
Well , j never equals to nElems so this condition (j==nElems) is not wrong BUT it's not Working .
You can make it like this (j==nElems-1) but it's steal waste of code , So your algorithm is better than the first one .