I am implementing a minstack algorithm and across something strange, Maybe I am missing either 'Some Stack concept' or 'Some Java concept' here. I am making using of two stacks(st and st2) to perform my minstack operations. Below is my pop method which fails at if condition:
Method 1 - FAILS:
public void pop() {
if(st.pop() == st2.peek())
st2.pop();
}
Below is the Pop method which works fine when I store the st.pop() results in a variable 'a':
Method 2 - PASSES:
public void pop() {
int a = st.pop();
if(a == st2.peek())
st2.pop();
}
Please assume that there are integer elements in both the stacks and the value from st.pop() is equal to st2.peek(). I would like the understand the difference as to why the st.pop() would not work in if state of method 1 and works in method 2 after storing results of st.pop() into a temporary variable a
If I understand the question correct, st.pop() doesn't work in the first method because the type of elements in st are never explicitly stated (ie. st could be initialized like Stack st = new Stack();).
As a result, any object (doesn't have to be an int) could be pushed onto the stack, so when the stack is popped, it's unclear what data type is returned, which causes the if statement to fail.
In the second method, the popped item is explicitly defined as an int in the variable a, so when the comparison is made with a, the if statement works as expected.
Related
I am trying to implement kind of Stack, which has push(), pop(), getMaxSoFar().
It should be executed o(1) time. However, I got an error in push(T value), and I don't know why. The error message said the operator ">=" is not defined in the type of T. I just wanted to check the code so I put int type instead of then it worked.
class FastMaxStack<T>
{
private Stack<T> stack;
private Stack<T> maxStack;
public FastMaxStack()
{
stack = new Stack();
maxStack = new Stack();
}
public void push(T value)
{
if(maxStack.isEmpty())
{
maxStack.push(value);
}
else if(value >= maxStack.peek())
{
maxStack.push(value);
}
stack.push(value);
}
public T pop()
{
maxStack.pop();
return stack.pop();
}
public T getMaxSoFar()
{
return maxStack.peek();
}
}
Your push method is assuming that the >= operator is supported for every conceivable type T. However, that operator is only supported for numeric types.
Perhaps you should define your class to operate for integers only, and not any data type.
On the other hand, perhaps you could implement your class for all Comparables.
class FastMaxStack<Comparable<T>>
{
//etc...
}
(too long for a comment)
There is another problem.
push always pushes on stack, but only pushes on maxStack if the value is at least as large as the top. So far, so good.
But pop always pops from both. Two problems:
Even if you pop as many times as you push, there can be an EmptyStackException if maxStack does not have enough elements (which will happen if you don't push values in increasing order).
Even if there is no exception, the value of getMaxSoFar won't be correct. As I understand what you are trying to do, maxStack is supposed to hold in top the max element of the stack in its current state. But imagine you push a value smaller than top, maxStack is not updated, and if you pop (from both then), the max is lost in maxStack. But it's still here in stack.
I have two stacks.
I want to be able to push any element onto one, but only if it was popped off the other.
Instead of My current function looks like this:
public void pushValue(int poppedValue) {
Stack.push(value)
}
I want the function to look something like this:
public void pushValue(pop() poppedValue) {
Stack.push(value)
}
How could I set the pop() function as a parameter, instead of an int?
In other words, how can I set the parameter to only accept a value that was popped from somewhere?
There is no way in Java to express that constraint. (Or in any other language, AFAIK)
(IMO) the best you can do is to pass the second Stack as an argument to the first one and make the first one responsible for popping a value; e.g.
public class Stack {
...
public int transferValue(Stack source) {
int res = source.pop(); // throws exception if source is empty
this.push(value);
return res;
}
}
This leaves you with problems regarding push:
Do you remove it entirely from the Stack API? If so, how do the elements get onto the source stack?
Do you split the Stack API into Stack and StackWithoutPush? If yes, which is the super-class / super-interface? Neither alternative is perfect. Either way, the subclass violates the contract of the superclass in some sense. (C.f. the problem of List versus UnmodifiableList APIs.)
Your syntax isn't possible, but you could make the second stack a member field and then push iff the value is present when you peek at the second stack (through the field).
private Stack otherStack = null; // <-- set this somehow (constructor?), or pass it.
public void pushValue(int newValue) {
if (otherStack != null && otherStack.peek() == newValue) {
Stack.push(newValue); // <-- please observe naming conventions (stack)
}
}
Then, pop() the value. Basically, peek, push and then pop.
In following code, the variable levelsToGo is getting updated unexpectedly on the recursive invocation of getAllStringNames(). When it comes back to stack to pop I am getting value of levelsToGo that was passed into the recursive call, not the value that existed previously.
public List<String> getAllStringNames(Student p, Integer levelsToGo)
{
List<String> employeeSet = new ArrayList<String>();
for(Student child : p.getAllSubjects())
{
employeeSet.add(child.getRoll());
if(levelsToGo > 0)
studentChilds.addAll(getAllStringNames(child, --levelsToGo))
}
return employeeSet;
}
The first time I passed student1, levelsToGo was 1 and student1 had 1 child. It called recursively and set levelsToGo to 0. When it came back to the first iteration we found that value is still 0. It should be the original value 1.
You decrement levelsToGo when you use it in the getAllStringNames() method invocation. The expression --levelsToGo means subtract one from the value of levelsToGo, store it back into levelsToGo, and then use it in the method call.
Instead, you should write
studentChilds.addAll(getAllStringNames(child, levelsToGo - 1));
Do not decrement integer variable, pass new integer as parameter
studentChilds.addAll(getAllStringNames(child, levelsToGo - 1))
So here it goes. I've been building a piece of software for a bigger project, and right now, I am simply baffled by the way Java treats my code. I have absolutely no idea as to why Java behaves the way it does right here.
It seems to skip part of my code, and assigns values to a different array than I expected when no according method is called.
I have walked over this for a few hours now with the IntelliJ Debugger, inspecting everything ever so closely, but I have not found a single reason as to why things happen the way they do.
package com.whatareyoudoing.java;
import java.util.Arrays;
/**
* WHAT THE ACTUAL DUCK
*/
public class WTF {
private int[] number;
private int[] oldNumber;
public WTF() {
number = new int[1];
oldNumber = new int[1];
}
public void putNumber(int c) {
number[0] = c;
}
public void putOld() {
if(Arrays.equals(oldNumber, number)) {
System.out.println("Nothing to do!");
return; //How on earth can they literally be the same?!
}
oldNumber = number;
}
public void doWTF() {
putNumber(1);
putOld(); // Works.
putNumber(2); // Expected Result: number = 2; oldNumber = 1 [NOPE] number = 2; oldNumber = 2
putOld(); // [NOPE] Simply Skips with "Nothing to do"
putNumber(3); // Same odd behaviour
putOld(); // Aaaand skips again.
}
}
After calling putNumber the first time, using putNumber again simultaneously puts the value in both variables (oldNumber and Number) instead of only in number[0].
I continued to simplify my code as far as possible so this example is more hands-on. Obviously, the real example where I found this had arrays longer than a single element.
I also tested it with multidimensional arrays, as well as object arrays. No change in the behavior.
I am completely puzzled now and have absolutely no idea how to go on. If you can shed any light on this topic, please do so. I am more than confused.
The following assignment statement:
oldNumber = number;
makes oldNumber and number point to the same underlying array. Perhaps what you want is to make a copy:
System.arraycopy(number, 0, oldNumber, 0, number.length);
See the documentation for System.arraycopy for full details.
This line isn't doing what you think it's doing.
oldNumber = number;
It isn't copying the contents of one array to another. It is making the reference variable oldNumber refer to the same array object as number refers to.
oldNumber ----> [1]
number -------^
So, any change through either variable writes through to the same array, and the change is visible through both references, which refer to the same array.
Then later you call Arrays.equals with references to the same array, so they are "equal".
You want to copy the number with this line instead:
oldNumber[0] = number[0];
When you assign
oldNumber = number
you don't make a copy of the values in the array. oldNumber will point to the exact same array (and future changes in either variable reflect in the other).
You can make a copy with
oldNumber = Arrays.copyOf(number, number.length);
In the putOld function you assigned the reference of the first array to the other. After the first call oldNumber is a pointer to number and if you change a value in one, the other one is affected too.
If you want to copy the values System.arraycopy().
The List listofinteger is of type Integer , but accepting String Object and when i do check for instance of Integer , it is giving true , its too strange , can anybody explain what is happening.
All i know is when i send the List listofinteger to method ,it is given reference to List reference variable of no type , when i add it takes the input as String , now when i return the List listofanything to List of Integer type , it should take because its a reference .
Now but i check for instanceof , it is printing true for Integer , but its String.
import java.util.ArrayList;
import java.util.List;
public class TestEx {
List<Integer> listofinteger=new ArrayList<Integer>(); //list of integer type
public static void main(String... args)
{
TestEx f=new TestEx();
f.listofinteger.add(123); //adds integer by wrapping it(auto)
f.listofinteger=f.addelement(f.listofinteger);
if(f.listofinteger.get(1) instanceof Integer);
{
System.out.println("true"); //prints true here
System.out.println(f.listofinteger.get(1));
}
}
List<Integer> addelement(List listofanything)
{
listofanything.add("asdasdasd"); //adding String object
return listofanything;
}
}
I know that the method addelement(List listofanything ) here should be given a type Integer but i am here testing it , to understand the concept of Generics
First of all, as #VJD commented, you have a syntax error - unneeded ; at:
if(f.listofinteger.get(1) instanceof Integer);
About your question, generics are compile time tool to check for type safety. In runtime there's no validation, as of type erasure. That's why you get no error adding String to list of Integers..
Your program prints true because of a syntax error in your code, which happens to be legal with a different meaning to what you intended.
Your if statement is
if(f.listofinteger.get(1) instanceof Integer);
The semicolon at the end ends the whole statement, and makes it equivalent to passing an empty block:
if(f.listofinteger.get(1) instanceof Integer) {
// Do nothing
}
After that you have the block that was supposed to be part of the if-condition, but is now just an anonymous block. (You can add braces in your code more or less wherever you want, to separate statements for scoping purposes. They still execute in the standard order).
Putting both of them together, your code is equivalent to:
if(f.listofinteger.get(1) instanceof Integer) {
// Do nothing
}
System.out.println("true"); //prints true here
System.out.println(f.listofinteger.get(1));
and so it should be clear that the last two lines will always be executed, regardless of what the if condition was.
As others have noted, you can fix this by removing the semicolon after the if statement. (And since this is a confusing and hard-to-spot problem, many static analysis tool such as FindBugs will highlight these semicolons as a likely problem.)
You are passing your List as an Generic List...
You need to identify your List as List <Integer> listofanything for your code give an error if you add a string... I changed your addElement code to:
List<Integer> addelement(List<Integer> listofanything)
{
listofanything.add("asdasdasd"); //Error when adding
return listofanything;
}
and an error appeared compiling...