Looking at the code below, doesnt the first iteration mean that i = 0 and j = 0 - 1? Why isnt there an error? I thought insertion sort was suppose to start from the end of the array/right side. How is this code accomplishing that?
class stevee {
public static void main(String[] args) {
int A[] = {2,1,9,8,12};
new stevee().sort(A);
System.out.println(Arrays.toString(A));
}
public void sort(int[] data) {
for (int i=0; i<data.length; i++) { //access each element one by one
int current = data[i]; //
int j = i-1;
while (j >= 0 && data[j] > current) {
data[j+1] = data[j];
j--;
}
data[j+1] = current;
}
}
}
Insertion sort works from the end in most examples. But why couldn't it work from the other side? 'Right' and 'Left' are only helping terms. Insertion sort is often explained with set of cards in your hand. Does it matter from which side you start putting them?
And there is no error cause while works also as if, j < 0 -> condition not met -> block not executed. In while condition you have && so both expressions must bu true, if first isn't, there is no sense to execute evaluation of second
There's a condition for that case: while (j >= 0
Related
I am coding a small program where I add an an ArrayList of Strings and I have a method that removes every String ending with S, it is working fine for 4 of elements but it seems to skip one.
Minimum reproducible example:
import java.util.ArrayList;
public class sList {
public static void main(String [] args) {
ArrayList<String> sList=new ArrayList<String>();
sList.add("leaf");
sList.add("leaves");
sList.add("box");
sList.add("boxes");
sList.add("phones");
sList.add("phone");
method m=new methods();
System.out.println(m.removePlurals(sList));
}
}
\\ that is my main method
import java.util.ArrayList;
public class method {
ArrayList<String> removePlurals(ArrayList<String> s) {
for (int i = 0; i < s.size(); i++) {
char c = s.get(i).charAt(s.get(i).length() - 1);
if (c == 's') {
s.remove(i);
}
}
return s;
}
}
I am getting as an output: [leaf, box, phones, phone] so it is skipping "phones"
Any help?
Think about what happens when after you removed "boxes" from the list. The index of "phones" decreases by 1. If it is originally the nth item in the list, it is now the (n-1)th item in the list, isn't it? So now "phones" is at the same position in the list as where "boxes" originally was. On the other hand, i increases by 1.
Now you should see the problem, to check for "phones", i should remain the same because after removing "boxes", the index of "phones" decreased by 1.
Solution, just loop from the end of the list to the start, and you won't have this problem:
for (int i = s.size() - 1; i >= 0; i--) {
char c = s.get(i).charAt(s.get(i).length() - 1);
if (c == 's') {
s.remove(i);
}
}
It is because at the moment you remove an item of a list, the list size is less than at the begining and when your counter is incremented, points to the next one element (skips one).
Yous can solve that just looping the list on the other way, as follow:
ArrayList<String> removePlurals(ArrayList<String> s) {
for (int i = s.size()-1; i >= 0; i--) {
char c = s.get(i).charAt(s.get(i).length() - 1);
if (c == 's') {
s.remove(i);
}
}
return s;
}
}
This is happening because the list you are iterating is being updated in the same loop. So when you remove one element is previous iteration it's index is being updated and element is not picked up at all by loop. So the solution should be like:
1) Create new list and return that:
ArrayList<String> removePlurals(final ArrayList<String> s) {
final ArrayList<String> updatedList = new ArrayList<String>();
for (int i = 0; i < s.size(); i++) {
final char c = s.get(i).charAt(s.get(i).length() - 1);
if (c != 's') {
updatedList.add(s.get(i));
}
}
return updatedList;
}
2) Using Iterator:
ArrayList<String> removePlurals(final ArrayList<String> s) {
final Iterator<String> itr = s.iterator();
while (itr.hasNext()) {
final String x = itr.next();
if (x.charAt(x.length() - 1) == 's') {
itr.remove();
}
}
return s;
}
Aside from the issue reported in the question: you have the issue that removing from the middle of an ArrayList one element at a time is really inefficient, because you keep on shifting all of the elements between (i+1) and the end of the list along by one position - and then you do it again for most of them.
Performance should not be your first concern - slow, correct code is always better than fast, incorrect code - but you should keep in the back of your mind issues that some things are worth avoiding: in this case, it is repeated removal from the middle of an ArrayList.
A better solution is not to keep shifting the elements, but rather just to move them once.
Unlike the solutions which iterate the list backwards, this can be done iterating forwards, which feels more natural (to me, at least).
int target = 0;
for (int i = 0; i < s.size(); ++i) {
if (!s.get(i).endsWith("s")) {
s.set(target, s.get(i));
target++;
}
}
This shifts each element that you are going to keep to its new position. All that then remains is to chop off the end of the list:
while (s.size() > target) s.remove(s.size()-1);
Or, in a single operation:
s.subList(target, s.size()).clear();
All together:
int target = 0;
for (int i = 0; i < s.size(); ++i) {
if (!s.get(i).endsWith("s")) {
s.set(target, s.get(i));
target++;
}
}
s.subList(target, s.size()).clear();
Note that this is effectively what is done by ArrayList.removeIf:
s.removeIf(e -> e.endsWith("s"));
(removeIf does a little bit more, in that it does the removal in a failure-atomic way, that is, if the e.endsWith fails for some reason, such as a null element, the list is left untouched rather than partly updated).
I have an atomic integer array of size 10. I am using this array to organize numbers 1-10 sent in by threads. This 1-10 will eventually be able to change to be a range of numbers larger than 10 and the list is to contain the 10 greatest numbers in that range. I can see the numbers going into the loops and recognizing that they are greater than a number currently there. However, there is never more than 2 numbers in the array when it is printed out. I have tried to trace my code in debug mode, however, it looks as if it is working as intended to me. I feel like there may be a simple error to my logic? I am completely sure all values are entering in the function as I have triple checked this. I start at the end of the array which should contain the highest value and then swap downwards once the slot has been determined. I would appreciate the assistance. This is just a simple experiment I am doing in order to grasp the basics before I try to tackle a homework assignment.
Here an example of my code:
public class testing{
static AtomicIntegerArray maxList = new AtomicIntegerArray(10);
final static int n = 10;
static void setMax(int value)
{
for(int i = 9; i >= 0; i--)
{
if(value > maxList.get(i))
{
int temp = maxList.get(i);
maxList.set(i,value);
if(i == 0)
{
maxList.set(i, value);
}
else
{ for(int j = i-1; j > 0; j--)
{
maxList.set(j, temp);
temp = maxList.get(j-1);
}
}
break;
}
}
public static void main(String[] args)
{
for (int i = 0; i < n; i++)
{
setMax(i);
}
}
}
Here is an example of how it is being called:
Brooke, there is a small bug in your 'j' loop. You had saved the state of a variable (temp), however your logic in the j loop lost the state. This new logic preserves the state of the previous element in the list.
Try this:
for (int j = i - 1; j >= 0; j--) {
int t2 = maxList.get(j);
maxList.set(j, temp);
temp = t2;
}
I'm trying to create a list of 20 integers between 0 and 26 (so in the 1-25 range) that does not repeat as a part of an assignment. I thought I had it figured out, but the program keeps looping over and over without ever ending. Can anyone help me out?
import java.util.Random;
public class prog433a
{
public static void main(String args[])
{
Random r = new Random();
int[] list = new int[20];
for (int k = 0; k < list.length; k++)
{
boolean notADupe = false;
while (notADupe == false)
{
list[k] = r.nextInt(25) + 1;
for (int j = 0; j < list.length; j++)
{
if (list[j] == list [k] && j != k)
{
notADupe = true;
}
else
{
notADupe = false;
break;
}
}
System.out.println(list[k]);
}
}
}
}
EDIT: This is different from the other question because I am trying to figure out how to check for uniqueness using the methods that I am allowed to use in my assignment (essentially, the ones I'm already using in the code).
I think you've reversed the condition out there. Inside if, you should set notADup to false, rather than true. However, I would make the variable isDup instead, and change the while loop accordingly.
One more suggestion: instead of while (notADupe == false), you should just use while (!notADupe). Never compare boolean variables like that. It might surprise you at times.
So to solve your issue, just change your if-else block to:
if (list[j] == list [k] && j != k) {
notADupe = false;
break;
} else {
notADupe = true;
}
BTW, your solution is a bit complex. For every element, you are iterating over whole array to find duplicate. Rather I would suggest you to maintain a Set<Integer> storing the already seen numbers, and check in that every randomly generated number. If present, skip it and re-generate.
Pseudo code would look something like this:
arr = [] // Your list array, initialize to size 20
seen = [] // A Set
for i from 1 -> arr.length
num = rand.nextInt(25) + 1
while seen contains num
num = rand.nextInt(25) + 1
seen.add(num)
arr[i] = num
if it's in ascending order I need to print "Ascending".
And if otherwise, print "Otherwise".
int [] a = new int[args.length];
for (int i = 0; i < args.length; i++)
{
a[i] = Integer.parseInt(args[i]);
}
if (a[0] <= args.length || a[0] == a[0])
{
System.out.println("Ascending");
}
else
{
System.out.println("Otherwise");
}
You seem to be having a lot more trouble with this exercise than you should. So I'll only give a hint, since this looks like homework: You should make n-1 comparisons in order to determine the order. Do that using a for loop.
To clarify: the code you presented does not contain a for loop that compares numbers, and does some comparisons that have nothing to do with verifying order of the numbers.
Hints:
The following two comparisons don't do anything useful: a[0] <= args.length and a[0] == a[0].
You need to use a loop.
For one, the expression a[0] == a[0] will always evaluate to true, meaning that your current code will always enter the first condition and print "Ascending".
For another, you can't establish that a list of n elements is in ascending order without some kind of iteration. You need to use a loop or recursion to check your array's elements against each other.
Try this code
public class Ascending
{
public static void main(String[] args)
{
int [] a = new int[args.length];
boolean otherwise = false;
for (int i = 0; i < args.length; i++)
{
a[i] = Integer.parseInt(args[i]);
}
for(int i=1;i<a.length;i++){
if(a[i-1]>a[i]){
otherwise = true;
}
}
if (!otherwise)
{
System.out.println("Ascending");
}
else
{
System.out.println("Otherwise");
}
}
}
I'm in dire need of help with this project. I'm trying to implement a Bag class for a programming assignment, and I'm getting hung up on the addAll(), Union(), and equals(), methods.
Edit: According to the assignment, addAll() is supposed to add all of the the objects from the second array into the first. I'm no longer getting an error when I run it, but for some reason it will not add all of the elements from the second array, it will only add the first 2. Thanks guys, this one is working perfectly now!
Edit: For Union(), I'm supposed to create a third bag that will contain all the contents of the first 2 bags. I was getting an ArrayIndexOutOfBoundsException when running this method. I've updated the code following biddulph.r and it's also working great. Thanks again!
Edit: "First attempt" And for equals(), it's supposed to check the size of the bags to make sure they are equal in size, then check to see if they contain the same numbers. So as it's written now, my equals() method will compare sizes and return the boolean value for that, but I'm unsure of how to make it compare the actual values.
import java.util.Arrays;
import javax.swing.*;
public class bag {
int maxSize = 10; //Size of the arrays
int count = 0; //Number of items stored in the array
int[] a;
int[] b;
bag c;
bag d;
public bag() {
//for(int i = 0; i < maxSize; i++){
//a[i] = (int)(1+Math.random()*100);
//}
a = new int[maxSize];
}
public String bagString() {
return Arrays.toString(a);
}
public void add(int b) {
try {
a[count] = b;
count++;
} catch (ArrayIndexOutOfBoundsException n) {
JOptionPane.showMessageDialog(null, "Array is full, element will not be added");
}
}
public void removeRandom() {
int i = (int)(1 + Math.random() * (count - 1));
a[i] = a[count - 1];
a[count - 1] = 0;
count--;
}
public void remove(int b) {
for (int i = 0; i < maxSize; i++) {
if (contains(b)) {
a[i] = a[count - 1];
}
}
}
public boolean isEmpty() {
if (count == 0) return true;
else return false;
}
public boolean contains(int b) {
int tf = 0;
for (int i = 0; i < maxSize; i++) {
if (a[i] == b) tf = 1;
}
if (tf == 1) return true;
else return false;
}
public int size() {
return count;
}
public void addAll(bag c, bag d) {
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
}
public void union(bag c, bag d) {
bag bigger = new bag();
for (int i = 0; i < c.size(); i++) {
bigger.add(c.a[i]);
}
for (int i = 0; count < d.size() - 1; i++) {
bigger.add(d.a[i]);
}
System.out.println(bigger.bagString());
}
public boolean equals(bag c, bag d){
if(c.size() != d.size()){
return false;
}else{
for(int i = 0; i < c.union(c, d).size(); i++){
if(c.union(c, d).contains(c.a[i]) && c.union(c, d).contains(d.a[i])){
return true;
}
}
return false;
}
}
}
I really appreciate any help you guys can give me, thanks.
EDIT: Thanks to everyone for your help, you guys are life savers.
Your problem for addAll() is here
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
You shouldn't be adding elements until your c bag becomes bigger than d, you should be adding all of d's elements to c.
for (int i = 0; i < d.size(); i++) {
c.add(d.a[i]);
}
So the part of the assignment you are having issue with is:
public void addAll(bag c, bag d){
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
}
which you say is supposed to add all of the the objects from the second array into the first.
If you break that down and apply it to your addAll() method, it sounds like you are supposed to be adding all of the items in bag "d" into bag "c".
Your for loop is saying start i at 0, and add 1 to it until the size of c is less than or equal to d.
What it should be saying is start i at 0, and add 1 to it until you have gone through every item in d.
That would look like this:
for (int i = 0; i < d.size(); i++){
c.add(d.a[i]);
}
i is increased every time you go through the for loop, and i will stop increasing when you have got to the size of d (the second condition). At this point you will exit the for loop. You don't have to worry about the size of c.
In fact you can probably get rid of the if (a.length >= c.size() + d.size()) line as well.
I hope my explanation helps you understand why the changes have been made to the method.
I think you have a lot of problems with the design of the class that you should address first. If you are representing the bag as a static or dynamic array then you only need one array, not 2. You also don't need two bags inside each bag as attributes, that doesn't make any sense; all you should have left is the size of the bag or count and the array to hold all the elements (which are integers in your case). Also, avoid naming parameters for functions and attributes for the class the same way. Not doing so might confuse the compiler and will require code like self.attributeName to use attributes; otherwise, the compiler assumes you're talking about the parameter.
If you make these changes, the rest should be straight-forward from here. Since it's an assignment, you should make these changes and try again because you won't learn if we provide the answers for you; you'll see it will be much easier once you structure it correctly.
P.S. it's a convention to start a class name with a capital letter. Bag and not bag
addAll
There's a couple of problems with this function as written. First is that it's confusing to the caller. The code using this method would be something like this:
Bag bag1 = ...
Bag bag2 = ...
Bag bag3 = ...
bag1.addAll(bag2, bag3)
...or perhaps bag2.addAll(bag2, bag3). The function is intended to add elements from one bag in to another bag, so why does the caller have to specify three different bags? There's only two involved. You should either make the function static, so it can be called like Bag.addAll(bag1, bag2) or (better) make it totally clear who's getting elements added by making it take a single argument bag1.addAll(bag2).
Second problem is that the function isn't implemented correctly, but I think that's because you're getting confused because you've got three bags involved instead of two. To sketch out how it should be fixed:
Bag target = ...
Bag source = ...
if (target.a.length >= target.size() + source.size()) {
for (int i = 0; i < source.a.length; i++) {
target.add(source.a[i]);
}
}
Good variable naming is your friend.
union
You haven't specified what problem you're having with your implementation, so I'm not going to simply rewrite it for you. Edit your question with the problem, and I'll help.
However, this is an excellent example of a method that should be static (a Factory method, in fact). It should be able ot be called like: Bag biggerBag = Bag.union(bag1, bag2).
EDIT after his comment regarding the .union problem
The problem with .union is that you're looping through each bag using some else's size. It boils down to, if you want add each element from source in to target, you should be only counting elements from source, as so:
bag bigger = new bag();
for (int i = 0; i <= c.size(); i++) {
bigger.add(c.a[i]);
}
note that your method does not protect against the bigger bag not being big enough. You should have a check to make sure that it is BEFORE the loops, or even better just create a big enough bag.
equals
Again, you need to show that you've tried to write it, and then ask a question specifying what you need help with. Update your question and I'll help.
Your method:
public void addAll(bag c, bag d) {
if (a.length >= c.size() + d.size()) {
for (int i = 0; c.size() <= d.size(); i++) {
c.add(d.a[i]);
}
}
}
betrays your lack of understanding of Object Oriented programming.
Remember that the method addAll() is already acting on a bag, and so you should not need to specify 2 bags in the arguments.
Calling example:
mybag.addAll(yourBag);
would demonstrate a possible usage - it would add all contents of yourBag into myBag.
I'll give you this method for free (assuming that the array 'a' contains the contents of the bag - something I'm not sure about because your variable names aren't clear):
public void addAll(Bag otherBag) {
for (int i : otherBag.a) {
add(i);
}
}
The above method will copy all contents of otherBag into this bag.
Another thing I noticed - you also have a b[] instance variable - what's that for?
You also have 2 other bag instance variables. Not sure why.