Okay so I was working on understanding the bubble sort algorithm this code works but I dont understand the while statement? It doesnt have a condition in the parentheses and I dont know why it keeps on running and why it stops.
public class BubbleSort {
int temp;
boolean flag;
int[] bubbleSort(int[] bs)
{
flag=true;//What?
while(flag)//Whats happening here? Whats the condition
{
flag=false;//Wouldnt that quit the while loop?
for(int i=0;i<bs.length-1;i++)
{
if(bs[i]>bs[(i+1)])
{
temp=bs[i];
bs[i]=bs[i+1];
bs[i+1]=temp;
flag=true;//What does this signify?
}
}
}
return bs;
}
public static void main(String[] args)
{
BubbleSort thisone = new BubbleSort();
int[] bacon = {1,0,3,2,4,5};
int[] potato = thisone.bubbleSort(bacon);
for(int i=0;i<potato.length;i++)
{
System.out.println(potato[i]);
}
}
}
It may be easier to understand in pseudo-code, without all the language-specific stuff:
didSwap = true # force loop entry
while didSwap: # keep going until sorted
didSwap = false # mark sorted
for each element except last:
if element > next element:
swap element, next element
didSwap = true # swapped, mark possibly unsorted
The didSwap (a) variable is initially set to true to ensure the loop is entered.
Upon entering the loop, it is immediately set to false so that, it nothing sets it back to true, the loop will exit after this iteration. That means the default behaviour for a loop iteration is to complete, then exit the loop (all talk of iterations here and below refer to the outer loop, the while one, not the inner for each one).
Now look at what sets it back to true. It's the swapping of any items in this iteration. When that happens, you know that you need at least one more iteration of the loop because you may have disturbed the order of items you've already done earlier in this iteration.
Consider the case of the following numbers and you're part way through the first iteration (no swaps have yet been done):
5 10 15 7 20
^^
Running from left to right, you've arrived at the 15 and you know that the first three numbers are already in order. But then you get to the 7 and you swap it with 15 to fix the order of those two. Now you have:
5 10 7 15 20
^^
and you can see that, because you've made a change to the sequence before where you're processing, you may have disturbed the order (in fact you have in this case), so you'll need at least one more pass to check and/or fix that.
Bottom line, because of the sequential nature of processing the list (left to right), you can only be certain it's sorted if you reach the end of an iteration and no swaps have been performed during that iteration.
That's why the flag method is used. More naive implementations simply do something like n * n iterations for a list of size n. That also guarantees that the items will be sorted at the end but doesn't give you the early exit possibilities of the flag method. You can see the problem immediately if you give it an already-sorted list of a thousand elements.
The naive approach will process the entire list one thousand times, the flag method only once.
(a) I prefer didSwap myself since its use and intent is clearer.
The flag is a typical Bubble sort optimization. If you go through the entire array and make no changes, then the array is sorted, and you can stop. while(flag) means "as long as the array still needs to be sorted."
In other words, the flag short circuits the sort. It lets you stop early if possible.
Before entering the loop flag is set to true (otherwise it would not be able to enter)
As soon as it enters it sets flag to false
If a condition is met, the flag is set to true
Back to the top of the loop - is flag set ? If false, it will break out, otherwise back to step2
flag=true;//What?
flag was declared earlier as a boolean, now it's being initialized to true (so that the loop will execute at least once)
while(flag)//Whats happening here? Whats the condition
A condition is just something that evaluates to a boolean, in this case the boolean variable flag is the condition.
flag=false;//Wouldnt that quit the while loop?
It won't jump out of the loop, that would take a break or return, so execution will continue into the for loop.
flag=true;//What does this signify?
This is set when if(bs[i]>bs[(i+1)]) evaluates to true, signalling that the array is not sorted yet.
Related
I have an ArrayList which is populated by a random number of GameObj instances each time the program is run.
If an object makes contact with another object in the ArrayList, it will set a boolean called visible from true to false.
Is there a way to check if all of the item instances in the ArrayList have been set to false through:
XXXX.visible = false
Once I can check if they are all set to false.
You can use Stream.noneMatch() to do this:
if (bricks.stream().noneMatch(GameObj::isVisible)) {
doStuffIfAllBricksAreInvisible();
}
This returns true, if all bricks are invisible.
Additionally I would recommend to take a look at Stream.allMatch(), which returns true, if all elements of the list match the given predicate.
Using allMatch() this would look like this:
if (bricks.stream().allMatch(b -> !b.isVisible())) {
doStuffIfAllBricksAreInvisible();
}
To complete this, you also can take a look at Stream.anyMatch(), which returns true, if one of the elements matches the given predicate.
If you are using Java <8, one way will be to store the arraylist size on intialisation in a variable( say variable name be count).
On change of flag from true to false, decrease the count by 1. If flag is already false, do nothing. Now you can just check the count is 0 or not.
If count is 0, print "Well done, Game over" or else continue the game.
For Java 8 or up, you can go for streams API as suggested in other answers.
I suggest use anyMatch because allMatch method returns true when the list is empty
if (!bricks.stream().anyMatch(GameObj::isVisible)) {
// TODO when visible balls not found (all are invisible)
}
Check if List of boolean values are all true or one value at least is false
List<Boolean> booleans = new ArrayList<>();
booleans.add(false);
booleans.add(true);
booleans.add(true);
booleans.add(true);
boolean areAllTrue = booleans.stream().allMatch(Boolean::booleanValue);
// equivalent to:
boolean areAllTrue = booleans.stream().allMatch(b -> b);
Important note: If booleans.size() is zero; the result of allMatch() is always true. So you have to check the size first, or depending on your context needs.
If you're new to Java, you probably want to use a for loop like this:
bool allFalse = true;
for(int index = 0; index < arrayList.size(); ++index)
if(arrayList[index].visible) {
allFalse = false;
break;
}
break; terminates the for loop as soon as you find the first true value since you no longer need to check anymore.
That will work if you know arrayList isn't empty, but it might make sense to have allFalse be false for an empty List since something that isn't there is neither true nor false.
For checking something in an ArrayList with not too many elements, a for loop with a break will also be significantly faster than a Stream. While that might not matter in general where readability and maintainability are paramount, it often does matter in games, especially if he does this check frequently. However, it depends on his use case. Speed may not be important.
[edited the post to be more clear]
The code below is supposed to represent a number of trial runs, and within each trial assume a is the number of cases that need to be checked.
while(testCaseAmt > 0) {
for(int i = 0; i < a; i++) {
if(some condition)
//code when i is not the last element
//then I would like to break/return here.
if(i = a - 1)
//code when i is the last element
//then if the above if statement never runs during the a amt of trials
//i will print out something else
}
testCaseAmt--;
}
My question is if there is another way to access specifically the last element within a for loop to give it specific instructions. I want to loop through a set trials and if they meet the first condition, I stop the loop immediately and return. However, if the condition isn't found I still need to print out not found.
Cheers.
To me this seems related to "off-by-one errors" or "fencepost errors", see here.
If the code you're executing when i is not the last element isn't too complex, it could be better to just end the for loop one iteration earlier and write the specific code for the last element outside the for loop.
Adding an if statement inside a for loop where you know it will only be true at the very last iteration could be seen as bad-style.
You can define a boolean conditionMet = false before the for-loop and iterate until i < a-1.
If some condition applies, execute your code, then set conditionMet = true and break out of the for-loop.
After the for-loop, check if !conditionMet and in this case, execute the code for the last element.
So basically, I have a programming assignment, and it involves two lines at an airline, one for frequent flyers and one for regular flyers. I have a for loop set up that, each time it runs, it determines whether some amount of frequent flyers gets in, some amount of regular flyers, or no one. For a frequent flyer, it is supposed to take 3 minutes to service a flyer, with one "minute" being a single iteration of the loop. For the regular flyers, it will take 5 minutes to service one person, again, with one iteration of the loop being a single minute. How can I determine when someone in the line has been serviced? As in, how can I pull someone out of the line whenever 3 or 5 iterations of the loop have occured, respectively. I'm utilizing a linked list.
I'm not sure I entirely understand your question, but I think I got the idea.
You could use break; to exit the loop (if that's what you're trying to do), and to test the amount of times the loop has been executed, you can use an int. It will look something like this:
int i = 0;
for(initialization, condition, iteration){
//Your code
if(i == 3 | i == 5){
break; //If you have your own method to "pull someone out of the line",
//then insert it here instead of using break, and also insert i = 0.
}
i++;
}
public void addClimb(String peakName, int climbTime){
for(int i = 0; i < climbList.size()-1; i++){
if(peakName.substring(0,1).compareTo(climbList.get(i).getName().substring(0,1)) <= 0){
climbList.add(i, new ClimbInfo(peakName, climbTime));
} else {
climbList.add(new ClimbInfo(peakName, climbTime));
}
}
}
The Goal is to have it take in an peakName and climbTime, have it loop through the climbTime objects in climbList, check for when the first letter of the parameter comes before the first letter of the climbTime in the loop, and places it as soon as that happens, but im getting an out of bounds error when i enter in several ClimbInfos and try to print them. This method is not properly inserting the ClimbInfo into climbTime properly.
Could someone explain what I'm doing wrong?
Depending on initial conditions, your function will do one of two things:
if climbList is initially empty, or initially contains only one element, then the test i < climbList.size() - 1 will fail, so the function will return immediately, doing nothing.
if climbList initially contains more than one element, then the test i < climbList.size() - 1 will always succeed, because every pass through the loop will add an element to climbList and will increment i by one. So i < climbList.size() - 1 is true before the iteration, then it will be true after the iteration. So you have an infinite loop.
I don't think that either of these is what you want.
You failed to explain what the problem is.
This method is not properly inserting the ClimbInfo into climbTime properly.
Doesn't tell me what happens. Runtime exception? Compile error? Or are you left with an empty collection at the end?
If you receive an exception, please include it along with a stack trace.
If we assume you have an empty collection, that can only mean one thing: the for loop condition is never reached. I can tell this for certain because the if statement has an else which inserts. Therefore, every iteration of the loop is guaranteed to insert. Thus, the loop must not be iterating.
I suspect it's the size checking.
for(int i = 0; i < climbList.size()-1; i++){
That logic is almost certainly wrong for two reasons:
If you start with an empty collection, then climbList.size() = 0, which means climbList.size() - 1 = -1. 0 is not less than -1, therefore your condition fails and the loop exits.
Assume you start with a non-empty list, then you will in fact insert. However, every iteration of the loop rechecks the size, yet within the loop, you are appending. Essentially, you are saying "for every element in climb list, add an element to climb list". That is going to run out of memory at some point, unless you start with an empty list.
you should not modify the list while iterating it.
I assume that what you are trying to achieve here is custom sorting. For that you must implement Comparable interface in ClimbInfo and use Collections.sort(climbList).
read more here and here.
Basically you are looping through the whole list, adding a record each time through the loop.
You probably want something like:
public void addClimb(String peakName, int climbTime){
for(int i = 0; i < climbList.size(); i++){
if(peakName.substring(0,1).compareTo(climbList.get(i).getName().substring(0,1)) >= 0){
climbList.add(i, new ClimbInfo(peakName, climbTime));
return;
}
}
climbList.add(new ClimbInfo(peakName, climbTime));
}
It must be really basic but I need help. For example, you store monster information in an array, and do for~loop to make each monster attacks/moves in their turn like this
for( i <- 0 to monsters.length-1) monsters(i).act
Then some monsters die during the loop and you have to delete some elements in the array while the loop is still on going. Then the next item in the array could be not really the the next one you want to process.
is there any fast/smart way to make sure each item in an array will be proceed once and only once within the loop, even if you really had to make change to the array during loop?
Scala's collections generally don't assume that you'll be manipulating them while they're using a method like foreach (or executing a for loop). If you want to do things that way, the easiest class to use is Java's java.util.concurrent.ConcurrentSkipListMap.
// This helps you use Java collections like Scala ones
import collection.JavaConversions._
case class Monster(name: String, hp: Int) {}
val horde = new java.util.concurrent.ConcurrentSkipListMap[Int,Monster]
horde put (0, Monster("wolf",7))
horde put (1, Monster("orc",3))
for (h <- horde) println(h) // Prints out both
Iterator.iterate(Option(horde.firstEntry)) {
case None => None
case Some(e) =>
val m = e.getValue
if (m.name=="wolf") horde.remove(1) // Kill the orc
else if (m.name=="orc") horde.remove(0) // Kill the wolf
Option(horde.higherEntry(e.getKey))
}.takeWhile(_.isDefined).foreach(_=>())
for (h <- horde) println(h) // Prints out just the wolf
Now, granted, this is rather a mess, but it does work, and it gives nice random access to your monsters. You have to maintain the keys in a sensible order, but that's not too hard.
Alternatively, as others have indicated, you could add an isAlive or isDead method, and only act on monsters that are alive. Then, after you've passed through the list once, you .filter(_.isAlive) to throw away all the dead monsters (or .filter(! _.isDead)), and run it again.
I would either use a conditional statement to check the monster's isAlive property in the loop before I called act, or do that check inside the act method itself.
I imagine that your monster[i] is not going to die on his turn, but rather off some other hapless monster?
If you're hooked on arrays, or don't mind the processing time (and for what you're doing, i reckon you don't care), just keep a boolean on each monster of isDead.
If a monster dies due to some ... i dunno, reason, just mark the "isDead" as true.
Then, in your monster "act" method, just check if the monster "isDead" or not.
After each loop, you can just prune the list to keep the alive monsters (move all the ones that are alive to a new list and begin again, prune the list in place, whatever is easier for you).
EDIT: This first graph misinterperets your question. However, my solution should still work for you.
What you're asking for is a thread-safe array - one that can be accessed by multiple "threads" of execution at a time. Seeing as you're new to Java, my guess is that your game is not going to be multithreaded, and so if you delete an item in an array, that's going to happen for sure before your next loop runs.
That said, if you really want to, you can add a "monster.dead" boolean function to your array, and set that to true whenever a monster dies. In your loop, then, you'd say:
for( i <- 0 to monsters.length-1)
if (monsters[i].dead == false)
monsters(i).act
Most likely, though, you won't run into this issue.
Edit: just reread your post, and realized that you'll be deleting monsters as your array is running. Remember that each line you execute happens sequentially, so when you remove monsters[i], it will be gone the next time the for loop is evaluated. If you have an array of monsters with 5 monsters in it and you delete the second one, when the loop executes again,
monsters.length - 1
is going to evaluate to 3 now. You'll never run into a moment where you hit a deleted array element.
If you delete an entry in an array, this element would be null.
Therefore you should check every element of your array, e.g.:
for(int i = 0; i <= array.lenght - 1; i++) {
// check null
if(array[i] != null) {
// do stuff
}
}
Hope this helped, have Fun!
make a copy of the original array, and traverse the copy.
if a monster would remove a monster, it would be removed only from the original
Deleting elements from an array while looping over it is generally a horrible idea. What if you delete an element before you reach it in the loop? Should you not actually delete it until the end of the loop, or should you skip over it?
I recommend something more like this:
var monsters = ... initial list of monsters ...
monsters = for (m <- monsters; if m.alive) yield { m.act; m }
Take advantage of yield and if in conjunction with the for loop, which allows you to build a new list.