The following code should be returning 16 as far as I can tell but for some reason, it returns 10. Does anyone know what my bug might be? Basically it's the Knapsack problem in Java and I've ran through the whole code on paper and it seems to return the right answer to me but I cannot figure out why when it's properly run, it returns back 10.
Any help would be much appreciated. Thanks!
import java.util.Stack;
public class knapsackProblem
{
public static int optimalValue(Stack<item> items, int totalWeight)
{
if (items.isEmpty())
return 0;
int value = items.peek().value;
int weight = items.peek().weight;
items.pop();
if (totalWeight<weight)
return optimalValue(items, totalWeight);
return Math.max(optimalValue(items,totalWeight), value + optimalValue(items, totalWeight-weight));
}
public static void main(String args[])
{
int knapsackWeight = 15;
Stack<item> items = new Stack<item>();
items.push(new item(7,10));
items.push(new item(3,6));
System.out.println(optimalValue(items, knapsackWeight));
}
}
class item
{
public int weight;
public int value;
public item(int aWeight, int aValue)
{
weight = aWeight;
value = aValue;
}
}
Your Stack is being modified across the calls. So a line like
return Math.max(optimalValue(items,totalWeight), value + optimalValue(items, totalWeight-weight));
will have two different copies of items for each call. Not what you want.
Instead of using Stack, try changing things around to use an ArrayList. Then pass your index of which item you're evaluating into the optimalValue method instead. This should help you work through the items correctly.
I haven't gone through the whole algorithm, but an obvious problem is that every time you call optimalValue on a Stack, it will pop one or more items from the stack. But a Stack, and the items in the stack, are objects, which means they're passed around by reference. So in this line:
return Math.max(optimalValue(items,totalWeight), value + optimalValue(items, totalWeight-weight));
This calls optimalValue twice. The first time you call it with items as a parameter, optimalValue will pop one or more elements from items. Then the statement calls optimalValue again with items as a parameter--and this will NOT use the same items stack that you passed to the first optimalValue call, but it will use the items with the already-popped-off items still popped off (from the first call). I really doubt this is what you want. If you do things this way, then at some point I think you'll have to make a copy of your Stack. Or you'll need to rethink things and do it a different way (maybe you can use an array or ArrayList, so that the items aren't actually popped off but you could pass a "starting index" from one optimalValue call to the recursive call).
I don't know whether there are other problems with your solution in addition to this one.
Related
(EDIT: Please note that TwoStacksAsQueue's and ArrayList's add() methods are different, so there are no recursive calls happening. I am still stuck after using the debugger, which is why I am asking for help here.)
I am in the middle of designing a class of two stacks that functions as a queue. When I run it, the last number it prints is 6 as expected. When I uncomment the last three lines of code, however, it prints 3 instead.
The way I see it, it should make no difference if the while loop at the end of the transfer() method is commented out or not. It comes after the print statement, so how could it possibly affect the output? What am I missing here? I have reduced my code to the minimal reproducible example.
public class TwoStacksAsQueue<T> {
final int stackCapacity;
final Stack<T> stack1;
final Stack<T> stack2;
public TwoStacksAsQueue(int stackCapacity) {
this.stackCapacity = stackCapacity;
stack1 = new Stack<>();
stack2 = new Stack<>();
}
public void add(T something) {
if (stack1.size() + stack2.size() >= stackCapacity * 2)
throw new RuntimeException("Not enough room in either stack; cannot add");
else if (stack1.isEmpty()) {
stack1.push(something);
} else {
int size = stack1.size();
List<T> popped = new ArrayList<>();
while (!stack1.isEmpty()) popped.add(stack1.pop());
stack1.push(something);
for (int i = size - 1; i >= 0; i--) stack1.push(popped.get(i));
if (stack1.size() > stackCapacity) transfer(stack1, stack2);
}
}
private void transfer(Stack<T> from, Stack<T> to) {
List<T> popped = new ArrayList<>();
System.out.println(from.size());
// while (from.size() > stackCapacity) {
// popped.add(from.pop());
// }
}
}
main method:
TwoStacksAsQueue<Integer> twoStacksAsQueue = new TwoStacksAsQueue<>(3);
twoStacksAsQueue.add(0);
twoStacksAsQueue.add(1);
twoStacksAsQueue.add(2);
twoStacksAsQueue.add(3);
twoStacksAsQueue.add(4);
twoStacksAsQueue.add(5);
The commented out lines of code change the behavior when the stackCapacity is exceeded. In your example, that happens when you push the fourth item. You should focus your debugging efforts there instead of waiting until the sixth item is pushed. If you think that code shouldn't be triggered until you hit twice the stackCapacity, you need to rethink that part.
Your code is hard to follow. In particular, I can't tell why you are creating temporary popped lists instead of using stack2. It seems like you think you are transferring values onto stack2, but you are actually putting them in a temporary popped list that then goes out of scope. You'll have an easier time debugging by printing out all the elements of stack1 and stack2 than trying to discern something based on the size.
I am having trouble figuring out how to remove and print every item in an IntStack object until it is empty. Would I need to use an if statement? I know the basics of stacks, for example:
Suppose s refers to an IntStack object.
If I wanted to add the value 100 to the top of s, I would simply use s.push(100)
If I wanted to remove and print the top value of s, I would use s.pop()
If I wanted to print the top value without removing it, I would use s.peek()
I run into trouble once I try to remove and print every item in s until it is empty.
Even If InStack is some third party stack, as per the description in question it implements all the standard stack methods, so following should work.
public void print(Stack s)
{
while(!s.isEmpty())
{
System.out.println(s.pop());
}
}
Assumming when there is nothing in the stack, s.peek() will return null,
while(s.peek() != null){
System.out.println(s.pop());
}
I have a class Section with several methods including methods get_key() and get_angle(). Items of type Section are added to a hashtable implemented in class Hashtable.
According to my task I should delete such elements from the hashtable which have bigger value of function get_angle() than given_value.
class Hashtable{
private Section[] hash_array; //array of cells of the hashtable
public int size;
public void remove_given(double given_value)
{
for(int i = 0; i < size; i++)
{
if (hash_array[i] != null)
{
double value = hash_array[i].get_angle(); //value of needed function to compare
if (value > given_value)
{
int key_ = hash_array[i].get_key(); //get key for the item in order to delete it
Delete(key_); //delete item
}
}
}
}
}
But the method doesn`t delete any elements. I checked the method Delete() separately and it works just fine as well as other methods called on this method . I really need to figure it out. So I will be grateful for your help.
Debug your code, does it enter the for-loop. How do you initialize the value of size variable? If you forget to initialize it by default it will be zero. It is better to get the size from the hash_array.length.
For one thing you're using the uninitialized global var, size, the size used in the for loop needs to be the size of the Hash collection. Also how is the Hash initialized? Does it contain what you think? I'd follow the aforementioned suggestion to step through the code with a debugger, perhaps the keys aren't what you think they are...
Ok, So I have a method
public static int getTotalLegCountDog (ArrayList<Dog> dogList)
{
int temp = 0;
for (int i = 0; i < dogList.size(); i++)
{
temp = dogList.get(i).getNumLegs();
totalLegsDogs += temp;
}
return totalLegsDogs;
}
It adds up the total legs of dogs and returns them as totalLegsDogs and there is another that totals the legs for cats.
Now I'd like a method that would take both the returned totalLegsDogs and returned totalLegsCats and add them together. My try is below (It returns 0), any help would be great!
public int getTotalLegCount ()
{
totalLegs = totalLegsDogs + totalLegsCats;
return totalLegs;
}
Was not calling the Method correctly. The math in the Problem was solid. The problem was the Method output call.
As far as I can tell, there's nothing wrong with the methods themselves - likely you're calling getTotalLegCount before actually counting the legs.
Fix 1 (preferred): Have getTotalLegCount call the methods.
public int getTotalLegCount (ArrayList<Dog> dogList, ArrayList<Cat> catList) {
totalLegs = getTotalLegCountDog(dogList) + getTotalLegCountCat;
return totalLegs;
}
Fix 2: Make it very clear that the leg-counting methods are to be called first. This is the inferior solution, as it requires more effort on the future programmer's part (and that might be future-you!).
I don't think you've shown us enough of your code to do any troubleshooting. It looks like you must have a global static count for dog legs and cat legs? I can't figure out your use case, but any rate, you need to make sure both your counting methods are called before you do anything with the member variables or else they will not be initialized. Example:
DogCatCounter.getTotalLegDogCount(...);
DogCatCounter.getTotalLegCatCount(...);
new DogCatCounter().getTotalLegCount();
The result from that third line should be correct as long as no other instances of DogCatCounter have modified your static variables. In other words, if you have multiple instances of DogCatCounter, any calls to your counting methods are going to modify your global static members.
Recursion is a new practice for me and I am trying to get better at it and understand how the methods return. I have the following program but am unfailiar with how to use the this keyword. Can you please review the code and walk me through the program showing the values held by the variables as the methods execute?
I have tried numerous things to determine how the value answer in the compute method holds 14 after execution can anyone walk me through the first few recursive calls so I can try and figure out the rest?
public class Recurs1 {
public static void main (String [] arg) {
Recurs1 r = new Recurs1();
r.compute();
}
public void compute() {
int [] stuff = {1, 2, 3, 4};
int answer = this.go(stuff, 0);
System.out.println("The answer is " + answer);
}
private int go(int[] numbers, int spot) {
if (numbers.length == spot) return spot;
int value = this.go(numbers, spot + 1 );
return value + numbers[spot];
}
}
Ok so a few things I notice here:
The purpose of go() seems to be calculating the sum of the numbers in the array. If this is the case, your method should look like this:
private int go(int[] numbers, int spot) {
if (numbers.length - 1 == spot) return numbers[spot];
int value = this.go(numbers, spot + 1 );
return value + numbers[spot];
}
This is because numbers.length in this case will return 4, but the last element in this array is at index 3 (arrays are 0-indexed).
This way, when the function is called with the second parameter set to 3, it will return the value of the last element in the array and then the code will "bubble up" (as I like to call it) and calculate the sum of the elements by subsequently returning the current summed value + the value of the current call.
As for your problem with the this keyword, it's actually very simple. this always refers to the current class instance your code is in. In this case, you create a Recurs1 instance called r in your main function so whenever you call a method on that particular object, the this keyword used in those methods will refer to r. If you created multiple Recurs1 objects (each with potential different internal states) in your program, their respective this references would always point to themselves allowing you to access their member variables and methods.
Hope that helps and good luck, recursion is usually what most people have trouble getting their heads around at first but once you get used to it it's pretty cool!
OK so this is not an answer to your question per se, more like a lesson in recursion.
Keep in mind I have never tried to to do this with a java class.
Recursion means a function that calls itself repeatedly until a answer has been reached, or your function detects you are running out of stack space.
You first step into the function determines if you will call yourself.
When you call yourself you will push a new copy of the data onto the stack and begin executing. I think in the case of java you will allocate a new object into the heap ( don't quote me on this ) and each invocation will have a new set of variables that get populated with new values.
As you recurse deeper and deeper you simply allocate new copies of the object until you find the answer or run out of memory.
If you find the answer you then return the result to the previous level in the stack of objects eg:
int foo(int i ){
if(some condition){
return foo(i);
} else
return i
}
as You can see if the condition tests true the foo() keeps getting called. Now at each call, the variables of foo() are saved for as many levels deep as you go. If the condition tests false then each instance of foo() returns to the previous until you are at the original invocation of foo() which then returns to the caller of foo().
Clear as Mud?